Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.db / org.gvsig.fmap.dal.db.jdbc / src / main / java / org / gvsig / fmap / dal / store / jdbc2 / spi / operations / FetchFeatureTypeOperation.java @ 43355

History | View | Annotate | Download (13.5 KB)

1
package org.gvsig.fmap.dal.store.jdbc2.spi.operations;
2

    
3
import java.sql.Connection;
4
import java.sql.DatabaseMetaData;
5
import java.sql.ResultSet;
6
import java.sql.ResultSetMetaData;
7
import java.sql.SQLException;
8
import java.sql.Statement;
9
import java.util.ArrayList;
10
import java.util.List;
11
import org.apache.commons.collections.CollectionUtils;
12
import org.apache.commons.lang3.StringUtils;
13
import org.cresques.cts.IProjection;
14
import org.gvsig.fmap.dal.DataTypes;
15
import org.gvsig.fmap.dal.exception.DataException;
16
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
17
import org.gvsig.fmap.dal.feature.EditableFeatureType;
18
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
19
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
20
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
21
import org.gvsig.fmap.geom.Geometry;
22
import org.gvsig.fmap.geom.GeometryLocator;
23
import org.gvsig.fmap.geom.type.GeometryType;
24

    
25
public class FetchFeatureTypeOperation extends AbstractConnectionOperation {
26
    private final EditableFeatureType featureType;
27
    private final String dbname;
28
    private final String schema;
29
    private final String table;
30
    private final List<String> primaryKeys;
31
    private final String defaultGeometryColumn;
32
    private final IProjection crs;
33

    
34
    public FetchFeatureTypeOperation(
35
            JDBCHelper helper
36
        ) {
37
        this(helper, null, null, null, null, null, null, null);
38
    }
39
    
40
    public FetchFeatureTypeOperation(
41
            JDBCHelper helper,
42
            EditableFeatureType featureType,
43
            String dbname,
44
            String schema,
45
            String table,
46
            List<String> primaryKeys,
47
            String defaultGeometryColumn,
48
            IProjection crs
49
        ) {
50
        super(helper);
51
        this.featureType = featureType;
52
        this.dbname = dbname;
53
        this.schema = schema;
54
        this.table = table;
55
        this.primaryKeys = primaryKeys;
56
        this.defaultGeometryColumn = defaultGeometryColumn;
57
        this.crs = crs;
58
    }
59
    
60
    @Override
61
    public final Object perform(Connection conn) throws DataException {
62
        this.fetch(featureType, conn, dbname, schema, table, 
63
                primaryKeys, defaultGeometryColumn, crs
64
        );
65
        return true;
66
    }
67
    
68
    protected String getDatabase() {
69
        return this.dbname;
70
    }
71
    
72
    protected String getSchema() {
73
        return this.schema;
74
    }
75
    
76
    protected String getTablename() {
77
        return this.table;
78
    }
79
    
80
    public void fetch(
81
            EditableFeatureType featureType,
82
            Connection conn,
83
            String database,
84
            String schema,
85
            String table,
86
            List<String> pks,
87
            String defaultGeometryColumn,
88
            IProjection crs
89
    ) throws DataException {
90

    
91
        Statement st = null;
92
        ResultSet rs = null;
93
        try {
94
            if (CollectionUtils.isEmpty(pks)) {
95
                if (!StringUtils.isEmpty(table)) {
96
                    pks = this.getPrimaryKeysFromMetadata(conn, null, schema, table);
97
                    if (CollectionUtils.isEmpty(pks)) {
98
                        pks = getPrimaryKeysFromInformationSchema(conn, null, schema, table);
99
                    }
100
                }
101
            }
102

    
103
            JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
104
            sqlbuilder.select().column().all();
105
            sqlbuilder.select().from().table().database(database).schema(schema).name(table);
106
            sqlbuilder.select().limit(1);
107

    
108
            st = conn.createStatement();
109
            st.setFetchSize(1);
110
            rs = JDBCUtils.executeQuery(st, sqlbuilder.toString());
111
            ResultSetMetaData rsMetadata = rs.getMetaData();
112

    
113
            int i;
114
            int geometriesColumns = 0;
115
            String lastGeometry = null;
116

    
117
            EditableFeatureAttributeDescriptor attr;
118
            boolean firstGeometryAttrFound = false;
119
            for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
120
                attr = getAttributeFromMetadata(featureType, conn, rsMetadata, i);
121
                if ( isInPrimaryKeys(pks,attr) ) {
122
                    attr.setIsPrimaryKey(true);
123
                }
124
                if (attr.getType() == DataTypes.GEOMETRY) {
125
                    geometriesColumns++;
126
                    lastGeometry = attr.getName();
127
                    // Set the default geometry attribute if it is the one
128
                    // given as parameter or it is the first one, just in case.
129
                    if (!firstGeometryAttrFound || lastGeometry.equals(defaultGeometryColumn)) {
130
                        firstGeometryAttrFound = true;
131
                        featureType.setDefaultGeometryAttributeName(lastGeometry);
132
                    }
133
                }
134

    
135
            }
136

    
137
            if (defaultGeometryColumn == null && geometriesColumns == 1) {
138
                featureType.setDefaultGeometryAttributeName(lastGeometry);
139
            }
140

    
141
        } catch (SQLException ex) {
142
            throw new RuntimeException("Can't fecth feature type.",ex);
143
        } finally {
144
            JDBCUtils.closeQuietly(rs);
145
            JDBCUtils.closeQuietly(st);
146
        }
147

    
148
        if (crs != null && featureType.getDefaultGeometryAttribute() != null) {
149
            ((EditableFeatureAttributeDescriptor) featureType.getDefaultGeometryAttribute()).setSRS(crs);
150
        }
151
    }
152

    
153
    protected boolean isInPrimaryKeys(List<String> pks, EditableFeatureAttributeDescriptor attr) {
154
        // En algunos gestores de BBDD, los nombres obtenidos de las pks de los 
155
        // metadados no coinciden con los nombres de los campos ya que unos estan
156
        // en mayusculas y otros en minusculas, asi que en lugar de usar un "contains"
157
        // nos los recorremos y comparamos con IgnoreCase.
158
        for (String pk : pks) {
159
            if( StringUtils.equalsIgnoreCase(pk, attr.getName()) ) {
160
                return true;
161
            }
162
        }
163
        return false;        
164
    }
165
    
166
    protected List<String> getPrimaryKeysFromMetadata(
167
            Connection conn,
168
            String catalog,
169
            String schema,
170
            String table) throws SQLException {
171

    
172
        ResultSet rsPrimaryKeys = null;
173
        ResultSet rs = null;
174
        try {
175
            DatabaseMetaData metadata = conn.getMetaData();
176
            rs = metadata.getTables(catalog, schema, table, null);
177

    
178
            if (!rs.next()) {
179
                // No tables found with default values, ignoring catalog
180
                rs.close();
181
                catalog = null;
182
                schema = null;
183
                rs = metadata.getTables(catalog, schema, table, null);
184
                if (!rs.next()) {
185
                    // table not found
186
                    return null;
187
                } else if (rs.next()) {
188
                    // More that one, cant identify
189
                    return null;
190
                }
191

    
192
            } else if (rs.next()) {
193
                // More that one, cant identify
194
                return null;
195
            }
196
            rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, table);
197
            List pks = new ArrayList();
198
            while (rsPrimaryKeys.next()) {
199
                pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
200
            }
201
            return pks;
202

    
203
        } catch (SQLException e) {
204
            return null;
205

    
206
        } finally {
207
            JDBCUtils.closeQuietly(rs);
208
            JDBCUtils.closeQuietly(rsPrimaryKeys);
209
        }
210

    
211
    }
212

    
213
    protected List<String> getPrimaryKeysFromInformationSchema(
214
            Connection conn,
215
            String catalog,
216
            String schema,
217
            String table) throws SQLException {
218

    
219
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
220

    
221
        sqlbuilder.select().column().name("COLUMN_NAME");
222
        sqlbuilder.select().column().name("CONSTRAINT_TYPE");
223
        sqlbuilder.select().from().custom(
224
                "INFORMATION_SCHEMA.table_constraints t_cons "
225
                + "inner join INFORMATION_SCHEMA.key_column_usage c on "
226
                + "c.constraint_catalog = t_cons.constraint_catalog and "
227
                + "c.table_schema = t_cons.table_schema and "
228
                + "c.table_name = t_cons.table_name and "
229
                + "c.constraint_name = t_cons.constraint_name "
230
        );
231
        sqlbuilder.select().where().set(
232
                sqlbuilder.like(
233
                        sqlbuilder.custom("c.TABLE_NAME"), 
234
                        sqlbuilder.constant(table)
235
                )
236
        );
237
        if (schema != null) {
238
            sqlbuilder.select().where().and(
239
                    sqlbuilder.like(
240
                            sqlbuilder.custom("c.TABLE_SCHEMA"),
241
                            sqlbuilder.constant(schema)
242
                    )
243
            );
244
        }
245
        if (catalog != null) {
246
            sqlbuilder.select().where().and(
247
                    sqlbuilder.like(
248
                            sqlbuilder.custom("c.CONSTRAINT_CATALOG"),
249
                            sqlbuilder.constant(catalog)
250
                    )
251
            );
252
        }
253
        sqlbuilder.select().where().and(
254
                sqlbuilder.eq(
255
                        sqlbuilder.column("CONSTRAINT_TYPE"),
256
                        sqlbuilder.constant("PRIMARY KEY")
257
                )
258
        );
259

    
260
        Statement st = null;
261
        ResultSet rs = null;
262
        List<String> pks = new ArrayList();
263
        try {
264
            st = conn.createStatement();
265
            rs = JDBCUtils.executeQuery(st, sqlbuilder.toString());
266
            while (rs.next()) {
267
                pks.add(rs.getString(1));
268
            }
269
            if (pks.isEmpty()) {
270
                return null;
271
            }
272
            return pks;
273

    
274
        } finally {
275
            JDBCUtils.closeQuietly(rs);
276
            JDBCUtils.closeQuietly(st);
277
        }
278
    }
279

    
280
    protected EditableFeatureAttributeDescriptor getAttributeFromMetadata(
281
            EditableFeatureType type,
282
            Connection conn,
283
            ResultSetMetaData rsMetadata,
284
            int colIndex
285
        ) throws SQLException {
286

    
287
        EditableFeatureAttributeDescriptor attr = type.add(
288
                rsMetadata.getColumnName(colIndex),
289
                this.getDataTypeFromMetadata(rsMetadata, colIndex)
290
        );
291
        attr.setAllowNull(
292
            rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable
293
        );
294
        attr.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
295
        attr.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
296
        attr.setPrecision(rsMetadata.getPrecision(colIndex));
297
        attr.setSize(rsMetadata.getColumnDisplaySize(colIndex));
298
        switch(attr.getType()) {
299
            case DataTypes.OBJECT:
300
                attr.setAdditionalInfo(
301
                        "SQLType",
302
                        rsMetadata.getColumnType(colIndex)
303
                );
304
                attr.setAdditionalInfo(
305
                        "SQLTypeName",
306
                        rsMetadata.getColumnTypeName(colIndex)
307
                );
308
                break;
309
            case DataTypes.GEOMETRY:
310
                this.fetchGeometryTypeAndSRS(attr, rsMetadata, colIndex);
311
                break;
312
        }
313
        return attr;
314
    }
315

    
316
    protected int getDataTypeFromMetadata(
317
            ResultSetMetaData rsMetadata,
318
            int colIndex
319
        ) throws SQLException {
320

    
321
        switch (rsMetadata.getColumnType(colIndex)) {
322
            case java.sql.Types.INTEGER:
323
                return DataTypes.INT;
324

    
325
            case java.sql.Types.BIGINT:
326
                return DataTypes.LONG;
327

    
328
            case java.sql.Types.REAL:
329
                return DataTypes.DOUBLE;
330

    
331
            case java.sql.Types.DOUBLE:
332
                return DataTypes.DOUBLE;
333

    
334
            case java.sql.Types.CHAR:
335
                return DataTypes.STRING;
336

    
337
            case java.sql.Types.VARCHAR:
338
            case java.sql.Types.LONGVARCHAR:
339
                return DataTypes.STRING;
340

    
341
            case java.sql.Types.FLOAT:
342
                return DataTypes.DOUBLE;
343

    
344
            case java.sql.Types.NUMERIC:
345
                return DataTypes.DOUBLE;
346

    
347
            case java.sql.Types.DECIMAL:
348
                return DataTypes.FLOAT;
349

    
350
            case java.sql.Types.DATE:
351
                return DataTypes.DATE;
352

    
353
            case java.sql.Types.TIME:
354
                return DataTypes.TIME;
355

    
356
            case java.sql.Types.TIMESTAMP:
357
                return DataTypes.TIMESTAMP;
358

    
359
            case java.sql.Types.BOOLEAN:
360
            case java.sql.Types.BIT:
361
                return DataTypes.BOOLEAN;
362

    
363
            case java.sql.Types.BLOB:
364
            case java.sql.Types.BINARY:
365
            case java.sql.Types.LONGVARBINARY:
366
                return DataTypes.BYTEARRAY;
367

    
368
            default:
369
                String typeName = rsMetadata.getColumnTypeName(colIndex);
370
                if( "geometry".equalsIgnoreCase(typeName) ) {
371
                    return DataTypes.GEOMETRY;
372
                }
373
                return DataTypes.OBJECT;
374
        }
375
    }
376

    
377
    /**
378
     * Inicializa el tipo, subtipo y SRS del attributo de tipo geometria.
379
     * 
380
     * @param attr
381
     * @param rsMetadata
382
     * @param colIndex 
383
     */
384
    protected void fetchGeometryTypeAndSRS(
385
            EditableFeatureAttributeDescriptor attr,
386
            ResultSetMetaData rsMetadata,
387
            int colIndex
388
        ) {
389
        if( attr.getType()!=DataTypes.GEOMETRY ) {
390
            return;
391
        }
392
        try {
393
            GeometryType geomType = GeometryLocator.getGeometryManager().getGeometryType(
394
                    Geometry.TYPES.GEOMETRY,
395
                    Geometry.SUBTYPES.GEOM2D
396
            );
397
            attr.setGeometryType(geomType);
398
            attr.setSRS(null);
399
        } catch (Exception ex) {
400
            logger.warn("Can't get default geometry type.",ex);
401
        }
402
    }
403
    
404
}