View Javadoc

1   package liquibase.ext.spatial.preconditions;
2   
3   import java.util.Arrays;
4   import java.util.LinkedHashSet;
5   import java.util.Set;
6   
7   import liquibase.changelog.ChangeSet;
8   import liquibase.changelog.DatabaseChangeLog;
9   import liquibase.database.Database;
10  import liquibase.database.core.DerbyDatabase;
11  import liquibase.database.core.H2Database;
12  import liquibase.exception.PreconditionErrorException;
13  import liquibase.exception.PreconditionFailedException;
14  import liquibase.exception.UnexpectedLiquibaseException;
15  import liquibase.exception.ValidationErrors;
16  import liquibase.exception.Warnings;
17  import liquibase.ext.spatial.xml.XmlConstants;
18  import liquibase.parser.core.ParsedNode;
19  import liquibase.parser.core.ParsedNodeException;
20  import liquibase.precondition.AbstractPrecondition;
21  import liquibase.precondition.Precondition;
22  import liquibase.precondition.core.IndexExistsPrecondition;
23  import liquibase.precondition.core.TableExistsPrecondition;
24  import liquibase.resource.ResourceAccessor;
25  import liquibase.structure.DatabaseObject;
26  import liquibase.structure.core.Column;
27  import liquibase.structure.core.Index;
28  import liquibase.structure.core.Schema;
29  import liquibase.structure.core.Table;
30  import liquibase.util.StringUtils;
31  
32  /**
33   * <code>SpatialIndexExistsPrecondition</code> determines if a spatial index exists on a specified
34   * table.
35   */
36  public class SpatialIndexExistsPrecondition extends AbstractPrecondition {
37     private String catalogName;
38     private String schemaName;
39     private String tableName;
40     private String columnNames;
41     private String indexName;
42  
43     public String getCatalogName() {
44        return this.catalogName;
45     }
46  
47     public void setCatalogName(final String catalogName) {
48        this.catalogName = catalogName;
49     }
50  
51     public String getSchemaName() {
52        return this.schemaName;
53     }
54  
55     public void setSchemaName(final String schemaName) {
56        this.schemaName = schemaName;
57     }
58  
59     public String getTableName() {
60        return this.tableName;
61     }
62  
63     public void setTableName(final String tableName) {
64        this.tableName = tableName;
65     }
66  
67     public String getIndexName() {
68        return this.indexName;
69     }
70  
71     public void setIndexName(final String indexName) {
72        this.indexName = indexName;
73     }
74  
75     public String getColumnNames() {
76        return this.columnNames;
77     }
78  
79     public void setColumnNames(final String columnNames) {
80        this.columnNames = columnNames;
81     }
82  
83     @Override
84     public String getName() {
85        return "spatialIndexExists";
86     }
87  
88     @Override
89     public Warnings warn(final Database database) {
90        return new Warnings();
91     }
92  
93     @Override
94     public ValidationErrors validate(final Database database) {
95        final ValidationErrors validationErrors;
96  
97        if ((database instanceof DerbyDatabase || database instanceof H2Database)
98              && getTableName() == null) {
99           validationErrors = new ValidationErrors();
100          validationErrors
101                .addError("tableName is required for " + database.getDatabaseProductName());
102       } else {
103          final IndexExistsPrecondition precondition = new IndexExistsPrecondition();
104          precondition.setCatalogName(getCatalogName());
105          precondition.setSchemaName(getSchemaName());
106          precondition.setTableName(getTableName());
107          precondition.setIndexName(getIndexName());
108          precondition.setColumnNames(getColumnNames());
109          validationErrors = precondition.validate(database);
110       }
111       return validationErrors;
112    }
113 
114    @Override
115    public void check(final Database database, final DatabaseChangeLog changeLog,
116          final ChangeSet changeSet) throws PreconditionFailedException, PreconditionErrorException {
117       Precondition delegatedPrecondition;
118       if (database instanceof DerbyDatabase || database instanceof H2Database) {
119          final TableExistsPrecondition precondition = new TableExistsPrecondition();
120          precondition.setCatalogName(getCatalogName());
121          precondition.setSchemaName(getSchemaName());
122          final String tableName = getHatboxTableName();
123          precondition.setTableName(tableName);
124          delegatedPrecondition = precondition;
125       } else {
126          final IndexExistsPrecondition precondition = new IndexExistsPrecondition();
127          precondition.setCatalogName(getCatalogName());
128          precondition.setSchemaName(getSchemaName());
129          precondition.setTableName(getTableName());
130          precondition.setIndexName(getIndexName());
131          precondition.setColumnNames(getColumnNames());
132          delegatedPrecondition = precondition;
133       }
134       delegatedPrecondition.check(database, changeLog, changeSet);
135    }
136 
137    /**
138     * Generates the table name containing the Hatbox index.
139     *
140     * @return the Hatbox table name.
141     */
142    protected String getHatboxTableName() {
143       final String tableName;
144       if (!StringUtils.hasUpperCase(getTableName())) {
145          tableName = getTableName() + "_hatbox";
146       } else {
147          tableName = getTableName() + "_HATBOX";
148       }
149       return tableName;
150    }
151 
152    /**
153     * Creates an example of the database object for which to check.
154     *
155     * @param database
156     *           the database instance.
157     * @param tableName
158     *           the table name of the index.
159     * @return the database object example.
160     */
161    public DatabaseObject getExample(final Database database, final String tableName) {
162       final Schema schema = new Schema(getCatalogName(), getSchemaName());
163       final DatabaseObject example;
164 
165       // For GeoDB, the index is another table.
166       if (database instanceof DerbyDatabase || database instanceof H2Database) {
167          final String correctedTableName = database.correctObjectName(getHatboxTableName(),
168                Table.class);
169          example = new Table().setName(correctedTableName).setSchema(schema);
170       } else {
171          example = getIndexExample(database, schema, tableName);
172       }
173       return example;
174    }
175 
176    /**
177     * Generates the {@link Index} example (taken from {@link IndexExistsPrecondition}).
178     *
179     * @param database
180     *           the database instance.
181     * @param schema
182     *           the schema instance.
183     * @param tableName
184     *           the table name of the index.
185     * @return the index example.
186     */
187    protected Index getIndexExample(final Database database, final Schema schema,
188          final String tableName) {
189       final Index example = new Index();
190       if (tableName != null) {
191          example.setTable((Table) new Table().setName(
192                database.correctObjectName(getTableName(), Table.class)).setSchema(schema));
193       }
194       example.setName(database.correctObjectName(getIndexName(), Index.class));
195       if (StringUtils.trimToNull(getColumnNames()) != null) {
196          for (final String columnName : getColumnNames().split("\\s*,\\s*")) {
197             final Column column = new Column(database.correctObjectName(columnName, Column.class));
198             example.getColumns().add(column);
199          }
200       }
201       return example;
202    }
203 
204    /**
205     * @see liquibase.serializer.LiquibaseSerializable#getSerializedObjectName()
206     */
207    @Override
208    public String getSerializedObjectName() {
209       return "spatialIndexExists";
210    }
211 
212    /**
213     * @see liquibase.serializer.LiquibaseSerializable#getSerializableFields()
214     */
215    @Override
216    public Set<String> getSerializableFields() {
217       return new LinkedHashSet<String>(Arrays.asList("catalogName", "schemaName", "tableName",
218             "columnNames", "indexName"));
219    }
220 
221    /**
222     * @see liquibase.serializer.LiquibaseSerializable#getSerializableFieldValue(java.lang.String)
223     */
224    @Override
225    public Object getSerializableFieldValue(final String field) {
226       final Object value;
227       if ("catalogName".equals(field)) {
228          value = getCatalogName();
229       } else if ("schemaName".equals(field)) {
230          value = getSchemaName();
231       } else if ("tableName".equals(field)) {
232          value = getTableName();
233       } else if ("columnNames".equals(field)) {
234          value = getColumnNames();
235       } else if ("indexName".equals(field)) {
236          value = getIndexName();
237       } else {
238          throw new UnexpectedLiquibaseException("Unexpected field request on "
239                + getSerializedObjectName() + ": " + field);
240       }
241       return value;
242    }
243 
244    /**
245     * @see liquibase.serializer.LiquibaseSerializable#getSerializableFieldType(java.lang.String)
246     */
247    @Override
248    public SerializationType getSerializableFieldType(final String field) {
249       return SerializationType.NAMED_FIELD;
250    }
251 
252    /**
253     * @see liquibase.serializer.LiquibaseSerializable#getSerializedObjectNamespace()
254     */
255    @Override
256    public String getSerializedObjectNamespace() {
257       return XmlConstants.SPATIAL_CHANGELOG_NAMESPACE;
258    }
259 
260    /**
261     * @see liquibase.serializer.LiquibaseSerializable#serialize()
262     */
263    @Override
264    public ParsedNode serialize() throws ParsedNodeException {
265       final String namespace = getSerializedObjectNamespace();
266       final ParsedNode node = new ParsedNode(namespace, getSerializedObjectName());
267       for (final String field : getSerializableFields()) {
268          final Object value = getSerializableFieldValue(field);
269          node.addChild(namespace, field, value);
270       }
271       return node;
272    }
273 
274    /**
275     * @see liquibase.precondition.Precondition#load(liquibase.parser.core.ParsedNode,
276     *      liquibase.resource.ResourceAccessor)
277     */
278    @Override
279    public void load(final ParsedNode parsedNode, final ResourceAccessor resourceAccessor)
280          throws ParsedNodeException {
281       final String namespace = null;
282       this.catalogName = parsedNode.getChildValue(namespace, "catalogName", String.class);
283       this.schemaName = parsedNode.getChildValue(namespace, "schemaName", String.class);
284       this.tableName = parsedNode.getChildValue(namespace, "tableName", String.class);
285       this.columnNames = parsedNode.getChildValue(namespace, "columnNames", String.class);
286       this.indexName = parsedNode.getChildValue(namespace, "indexName", String.class);
287    }
288 }