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 @ 43377

History | View | Annotate | Download (14.2 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 defaultGeometryColumn,
44
            IProjection crs
45
        ) {
46
        this(helper, featureType, null, null, null, null, defaultGeometryColumn, crs);
47
    }
48

    
49
    public FetchFeatureTypeOperation(
50
            JDBCHelper helper,
51
            EditableFeatureType featureType,
52
            String dbname,
53
            String schema,
54
            String table,
55
            List<String> primaryKeys,
56
            String defaultGeometryColumn,
57
            IProjection crs
58
        ) {
59
        super(helper);
60
        this.featureType = featureType;
61
        this.dbname = dbname;
62
        this.schema = schema;
63
        this.table = table;
64
        this.primaryKeys = primaryKeys;
65
        this.defaultGeometryColumn = defaultGeometryColumn;
66
        this.crs = crs;
67
    }
68
    
69
    @Override
70
    public final Object perform(Connection conn) throws DataException {
71
        this.fetch(featureType, conn, dbname, schema, table, 
72
                primaryKeys, defaultGeometryColumn, crs
73
        );
74
        return true;
75
    }
76
    
77
    protected String getDatabase() {
78
        return this.dbname;
79
    }
80
    
81
    protected String getSchema() {
82
        return this.schema;
83
    }
84
    
85
    protected String getTablename() {
86
        return this.table;
87
    }
88
    
89
    public void fetch(
90
            EditableFeatureType featureType,
91
            Connection conn,
92
            String database,
93
            String schema,
94
            String table,
95
            List<String> pks,
96
            String defaultGeometryColumn,
97
            IProjection crs
98
    ) throws DataException {
99

    
100
        Statement st = null;
101
        ResultSet rs = null;
102
        try {
103
            if (CollectionUtils.isEmpty(pks)) {
104
                if (!StringUtils.isEmpty(table)) {
105
                    pks = this.getPrimaryKeysFromMetadata(conn, null, schema, table);
106
                    if (CollectionUtils.isEmpty(pks)) {
107
                        pks = getPrimaryKeysFromInformationSchema(conn, null, schema, table);
108
                    }
109
                }
110
            }
111

    
112
            JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
113
            sqlbuilder.select().column().all();
114
            sqlbuilder.select().from().table().database(database).schema(schema).name(table);
115
            sqlbuilder.select().limit(1);
116

    
117
            st = conn.createStatement();
118
            st.setFetchSize(1);
119
            rs = JDBCUtils.executeQuery(st, sqlbuilder.toString());
120
            ResultSetMetaData rsMetadata = rs.getMetaData();
121

    
122
            fetchFeatureTypeFromMetadata(conn, rsMetadata, pks);
123

    
124
        } catch (SQLException ex) {
125
            throw new RuntimeException("Can't fecth feature type.",ex);
126
        } finally {
127
            JDBCUtils.closeQuietly(rs);
128
            JDBCUtils.closeQuietly(st);
129
        }
130
    }
131
    
132
    public void fetchFeatureTypeFromMetadata(Connection conn, ResultSetMetaData rsMetadata) throws SQLException {
133
        this.fetchFeatureTypeFromMetadata(conn, rsMetadata, new ArrayList<String>());
134
    }
135

    
136
    protected void fetchFeatureTypeFromMetadata(Connection conn, ResultSetMetaData rsMetadata, List<String> pks) throws SQLException {
137
        int i;
138
        int geometriesColumns = 0;
139
        String lastGeometry = null;
140

    
141
        EditableFeatureAttributeDescriptor attr;
142
        boolean firstGeometryAttrFound = false;
143
        for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
144
            attr = getAttributeFromMetadata(featureType, conn, rsMetadata, i);
145
            if ( isInPrimaryKeys(pks,attr) ) {
146
                attr.setIsPrimaryKey(true);
147
            }
148
            if (attr.getType() == DataTypes.GEOMETRY) {
149
                geometriesColumns++;
150
                lastGeometry = attr.getName();
151
                // Set the default geometry attribute if it is the one
152
                // given as parameter or it is the first one, just in case.
153
                if (!firstGeometryAttrFound || lastGeometry.equals(defaultGeometryColumn)) {
154
                    firstGeometryAttrFound = true;
155
                    featureType.setDefaultGeometryAttributeName(lastGeometry);
156
                }
157
            }
158

    
159
        }
160
        if (defaultGeometryColumn == null && geometriesColumns == 1) {
161
            featureType.setDefaultGeometryAttributeName(lastGeometry);
162
        }
163

    
164
        if (crs != null && featureType.getDefaultGeometryAttribute() != null) {
165
            ((EditableFeatureAttributeDescriptor) featureType.getDefaultGeometryAttribute()).setSRS(crs);
166
        }
167
    }
168

    
169
    protected boolean isInPrimaryKeys(List<String> pks, EditableFeatureAttributeDescriptor attr) {
170
        // En algunos gestores de BBDD, los nombres obtenidos de las pks de los 
171
        // metadados no coinciden con los nombres de los campos ya que unos estan
172
        // en mayusculas y otros en minusculas, asi que en lugar de usar un "contains"
173
        // nos los recorremos y comparamos con IgnoreCase.
174
        for (String pk : pks) {
175
            if( StringUtils.equalsIgnoreCase(pk, attr.getName()) ) {
176
                return true;
177
            }
178
        }
179
        return false;        
180
    }
181
    
182
    protected List<String> getPrimaryKeysFromMetadata(
183
            Connection conn,
184
            String catalog,
185
            String schema,
186
            String table) throws SQLException {
187

    
188
        ResultSet rsPrimaryKeys = null;
189
        ResultSet rs = null;
190
        try {
191
            DatabaseMetaData metadata = conn.getMetaData();
192
            rs = metadata.getTables(catalog, schema, table, null);
193

    
194
            if (!rs.next()) {
195
                // No tables found with default values, ignoring catalog
196
                rs.close();
197
                catalog = null;
198
                schema = null;
199
                rs = metadata.getTables(catalog, schema, table, null);
200
                if (!rs.next()) {
201
                    // table not found
202
                    return null;
203
                } else if (rs.next()) {
204
                    // More that one, cant identify
205
                    return null;
206
                }
207

    
208
            } else if (rs.next()) {
209
                // More that one, cant identify
210
                return null;
211
            }
212
            rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, table);
213
            List pks = new ArrayList();
214
            while (rsPrimaryKeys.next()) {
215
                pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
216
            }
217
            return pks;
218

    
219
        } catch (SQLException e) {
220
            return null;
221

    
222
        } finally {
223
            JDBCUtils.closeQuietly(rs);
224
            JDBCUtils.closeQuietly(rsPrimaryKeys);
225
        }
226

    
227
    }
228

    
229
    protected List<String> getPrimaryKeysFromInformationSchema(
230
            Connection conn,
231
            String catalog,
232
            String schema,
233
            String table) throws SQLException {
234

    
235
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
236

    
237
        sqlbuilder.select().column().name("COLUMN_NAME");
238
        sqlbuilder.select().column().name("CONSTRAINT_TYPE");
239
        sqlbuilder.select().from().custom(
240
                "INFORMATION_SCHEMA.table_constraints t_cons "
241
                + "inner join INFORMATION_SCHEMA.key_column_usage c on "
242
                + "c.constraint_catalog = t_cons.constraint_catalog and "
243
                + "c.table_schema = t_cons.table_schema and "
244
                + "c.table_name = t_cons.table_name and "
245
                + "c.constraint_name = t_cons.constraint_name "
246
        );
247
        sqlbuilder.select().where().set(
248
                sqlbuilder.like(
249
                        sqlbuilder.custom("c.TABLE_NAME"), 
250
                        sqlbuilder.constant(table)
251
                )
252
        );
253
        if (schema != null) {
254
            sqlbuilder.select().where().and(
255
                    sqlbuilder.like(
256
                            sqlbuilder.custom("c.TABLE_SCHEMA"),
257
                            sqlbuilder.constant(schema)
258
                    )
259
            );
260
        }
261
        if (catalog != null) {
262
            sqlbuilder.select().where().and(
263
                    sqlbuilder.like(
264
                            sqlbuilder.custom("c.CONSTRAINT_CATALOG"),
265
                            sqlbuilder.constant(catalog)
266
                    )
267
            );
268
        }
269
        sqlbuilder.select().where().and(
270
                sqlbuilder.eq(
271
                        sqlbuilder.column("CONSTRAINT_TYPE"),
272
                        sqlbuilder.constant("PRIMARY KEY")
273
                )
274
        );
275

    
276
        Statement st = null;
277
        ResultSet rs = null;
278
        List<String> pks = new ArrayList();
279
        try {
280
            st = conn.createStatement();
281
            rs = JDBCUtils.executeQuery(st, sqlbuilder.toString());
282
            while (rs.next()) {
283
                pks.add(rs.getString(1));
284
            }
285
            if (pks.isEmpty()) {
286
                return null;
287
            }
288
            return pks;
289

    
290
        } catch (Exception ex) {
291
            return pks;
292
            
293
        } finally {
294
            JDBCUtils.closeQuietly(rs);
295
            JDBCUtils.closeQuietly(st);
296
        }
297
    }
298

    
299
    protected EditableFeatureAttributeDescriptor getAttributeFromMetadata(
300
            EditableFeatureType type,
301
            Connection conn,
302
            ResultSetMetaData rsMetadata,
303
            int colIndex
304
        ) throws SQLException {
305

    
306
        EditableFeatureAttributeDescriptor attr = type.add(
307
                rsMetadata.getColumnName(colIndex),
308
                this.getDataTypeFromMetadata(rsMetadata, colIndex)
309
        );
310
        attr.setAllowNull(
311
            rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable
312
        );
313
        attr.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
314
        attr.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
315
        attr.setPrecision(rsMetadata.getPrecision(colIndex));
316
        attr.setSize(rsMetadata.getColumnDisplaySize(colIndex));
317
        switch(attr.getType()) {
318
            case DataTypes.OBJECT:
319
                attr.setAdditionalInfo(
320
                        "SQLType",
321
                        rsMetadata.getColumnType(colIndex)
322
                );
323
                attr.setAdditionalInfo(
324
                        "SQLTypeName",
325
                        rsMetadata.getColumnTypeName(colIndex)
326
                );
327
                break;
328
            case DataTypes.GEOMETRY:
329
                this.fetchGeometryTypeAndSRS(attr, rsMetadata, colIndex);
330
                break;
331
        }
332
        return attr;
333
    }
334

    
335
    protected int getDataTypeFromMetadata(
336
            ResultSetMetaData rsMetadata,
337
            int colIndex
338
        ) throws SQLException {
339

    
340
        switch (rsMetadata.getColumnType(colIndex)) {
341
            case java.sql.Types.INTEGER:
342
                return DataTypes.INT;
343

    
344
            case java.sql.Types.BIGINT:
345
                return DataTypes.LONG;
346

    
347
            case java.sql.Types.REAL:
348
                return DataTypes.DOUBLE;
349

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

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

    
356
            case java.sql.Types.VARCHAR:
357
            case java.sql.Types.LONGVARCHAR:
358
                return DataTypes.STRING;
359

    
360
            case java.sql.Types.FLOAT:
361
                return DataTypes.DOUBLE;
362

    
363
            case java.sql.Types.NUMERIC:
364
                return DataTypes.DOUBLE;
365

    
366
            case java.sql.Types.DECIMAL:
367
                return DataTypes.FLOAT;
368

    
369
            case java.sql.Types.DATE:
370
                return DataTypes.DATE;
371

    
372
            case java.sql.Types.TIME:
373
                return DataTypes.TIME;
374

    
375
            case java.sql.Types.TIMESTAMP:
376
                return DataTypes.TIMESTAMP;
377

    
378
            case java.sql.Types.BOOLEAN:
379
            case java.sql.Types.BIT:
380
                return DataTypes.BOOLEAN;
381

    
382
            case java.sql.Types.BLOB:
383
            case java.sql.Types.BINARY:
384
            case java.sql.Types.LONGVARBINARY:
385
                return DataTypes.BYTEARRAY;
386

    
387
            default:
388
                String typeName = rsMetadata.getColumnTypeName(colIndex);
389
                if( "geometry".equalsIgnoreCase(typeName) ) {
390
                    return DataTypes.GEOMETRY;
391
                }
392
                return DataTypes.OBJECT;
393
        }
394
    }
395

    
396
    /**
397
     * Inicializa el tipo, subtipo y SRS del attributo de tipo geometria.
398
     * 
399
     * @param attr
400
     * @param rsMetadata
401
     * @param colIndex 
402
     */
403
    protected void fetchGeometryTypeAndSRS(
404
            EditableFeatureAttributeDescriptor attr,
405
            ResultSetMetaData rsMetadata,
406
            int colIndex
407
        ) {
408
        if( attr.getType()!=DataTypes.GEOMETRY ) {
409
            return;
410
        }
411
        try {
412
            GeometryType geomType = GeometryLocator.getGeometryManager().getGeometryType(
413
                    Geometry.TYPES.GEOMETRY,
414
                    Geometry.SUBTYPES.GEOM2D
415
            );
416
            attr.setGeometryType(geomType);
417
            attr.setSRS(null);
418
        } catch (Exception ex) {
419
            logger.warn("Can't get default geometry type.",ex);
420
        }
421
    }
422
    
423
}