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

History | View | Annotate | Download (12.9 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
    public void fetch(
69
            EditableFeatureType featureType,
70
            Connection conn,
71
            String database,
72
            String schema,
73
            String table,
74
            List<String> pks,
75
            String defaultGeometryColumn,
76
            IProjection crs
77
    ) throws DataException {
78

    
79
        Statement st = null;
80
        ResultSet rs = null;
81
        try {
82
            if (CollectionUtils.isEmpty(pks)) {
83
                if (!StringUtils.isEmpty(table)) {
84
                    pks = this.getPrimaryKeysFromMetadata(conn, null, schema, table);
85
                    if (CollectionUtils.isEmpty(pks)) {
86
                        pks = getPrimaryKeysFromInformationSchema(conn, null, schema, table);
87
                    }
88
                }
89
            }
90

    
91
            JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
92
            sqlbuilder.select().column().all();
93
            sqlbuilder.select().from().table().database(database).schema(schema).name(table);
94
            sqlbuilder.select().limit(1);
95

    
96
            st = conn.createStatement();
97
            st.setFetchSize(1);
98
            rs = JDBCUtils.executeQuery(st, sqlbuilder.toString());
99
            ResultSetMetaData rsMetadata = rs.getMetaData();
100

    
101
            int i;
102
            int geometriesColumns = 0;
103
            String lastGeometry = null;
104

    
105
            EditableFeatureAttributeDescriptor attr;
106
            boolean firstGeometryAttrFound = false;
107
            for (i = 1; i <= rsMetadata.getColumnCount(); i++) {
108
                attr = getAttributeFromMetadata(featureType, conn, rsMetadata, i);
109
                if (pks != null && pks.contains(attr.getName())) {
110
                    attr.setIsPrimaryKey(true);
111
                }
112
                if (attr.getType() == DataTypes.GEOMETRY) {
113
                    geometriesColumns++;
114
                    lastGeometry = attr.getName();
115
                    // Set the default geometry attribute if it is the one
116
                    // given as parameter or it is the first one, just in case.
117
                    if (!firstGeometryAttrFound || lastGeometry.equals(defaultGeometryColumn)) {
118
                        firstGeometryAttrFound = true;
119
                        featureType.setDefaultGeometryAttributeName(lastGeometry);
120
                    }
121
                }
122

    
123
            }
124

    
125
            if (geometriesColumns > 0) {
126
                fetch_CRS_and_shapeType(conn, rsMetadata, featureType, schema, table);
127
            }
128

    
129
            if (defaultGeometryColumn == null && geometriesColumns == 1) {
130
                featureType.setDefaultGeometryAttributeName(lastGeometry);
131
            }
132

    
133
        } catch (SQLException ex) {
134
            throw new RuntimeException("Can't fecth feature type.",ex);
135
        } finally {
136
            JDBCUtils.closeQuietly(rs);
137
            JDBCUtils.closeQuietly(st);
138
        }
139

    
140
        if (crs != null && featureType.getDefaultGeometryAttribute() != null) {
141
            ((EditableFeatureAttributeDescriptor) featureType.getDefaultGeometryAttribute()).setSRS(crs);
142
        }
143
    }
144

    
145
    protected List<String> getPrimaryKeysFromMetadata(
146
            Connection conn,
147
            String catalog,
148
            String schema,
149
            String table) throws SQLException {
150

    
151
        ResultSet rsPrimaryKeys = null;
152
        ResultSet rs = null;
153
        try {
154
            DatabaseMetaData metadata = conn.getMetaData();
155
            rs = metadata.getTables(catalog, schema, table, null);
156

    
157
            if (!rs.next()) {
158
                // No tables found with default values, ignoring catalog
159
                rs.close();
160
                catalog = null;
161
                schema = null;
162
                rs = metadata.getTables(catalog, schema, table, null);
163
                if (!rs.next()) {
164
                    // table not found
165
                    return null;
166
                } else if (rs.next()) {
167
                    // More that one, cant identify
168
                    return null;
169
                }
170

    
171
            } else if (rs.next()) {
172
                // More that one, cant identify
173
                return null;
174
            }
175
            rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, table);
176
            List pks = new ArrayList();
177
            while (rsPrimaryKeys.next()) {
178
                pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
179
            }
180
            return pks;
181

    
182
        } catch (SQLException e) {
183
            return null;
184

    
185
        } finally {
186
            JDBCUtils.closeQuietly(rs);
187
            JDBCUtils.closeQuietly(rsPrimaryKeys);
188
        }
189

    
190
    }
191

    
192
    protected List<String> getPrimaryKeysFromInformationSchema(
193
            Connection conn,
194
            String catalog,
195
            String schema,
196
            String table) throws SQLException {
197

    
198
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
199

    
200
        sqlbuilder.select().column().name("COLUMN_NAME");
201
        sqlbuilder.select().column().name("CONSTRAINT_TYPE");
202
        sqlbuilder.select().from().custom(
203
                "INFORMATION_SCHEMA.table_constraints t_cons "
204
                + "inner join INFORMATION_SCHEMA.key_column_usage c on "
205
                + "c.constraint_catalog = t_cons.constraint_catalog and "
206
                + "c.table_schema = t_cons.table_schema and "
207
                + "c.table_name = t_cons.table_name and "
208
                + "c.constraint_name = t_cons.constraint_name "
209
        );
210
        sqlbuilder.select().where().set(
211
                sqlbuilder.like(
212
                        sqlbuilder.custom("c.TABLE_NAME"), // Con SQLServer si pones comillas no funciona.
213
                        sqlbuilder.constant(table)
214
                )
215
        );
216
        if (schema != null) {
217
            sqlbuilder.select().where().and(
218
                    sqlbuilder.like(
219
                            sqlbuilder.custom("c.TABLE_SCHEMA"),
220
                            sqlbuilder.constant(schema)
221
                    )
222
            );
223
        }
224
        if (catalog != null) {
225
            sqlbuilder.select().where().and(
226
                    sqlbuilder.like(
227
                            sqlbuilder.custom("c.CONSTRAINT_CATALOG"),
228
                            sqlbuilder.constant(catalog)
229
                    )
230
            );
231
        }
232
        sqlbuilder.select().where().and(
233
                sqlbuilder.eq(
234
                        sqlbuilder.column("CONSTRAINT_TYPE"),
235
                        sqlbuilder.constant("PRIMARY KEY")
236
                )
237
        );
238

    
239
        Statement st = null;
240
        ResultSet rs = null;
241
        List<String> pks = new ArrayList();
242
        try {
243
            st = conn.createStatement();
244
            rs = JDBCUtils.executeQuery(st, sqlbuilder.toString());
245
            while (rs.next()) {
246
                pks.add(rs.getString(1));
247
            }
248
            if (pks.isEmpty()) {
249
                return null;
250
            }
251
            return pks;
252

    
253
        } finally {
254
            JDBCUtils.closeQuietly(rs);
255
            JDBCUtils.closeQuietly(st);
256
        }
257
    }
258

    
259
    protected EditableFeatureAttributeDescriptor getAttributeFromMetadata(
260
            EditableFeatureType type,
261
            Connection conn,
262
            ResultSetMetaData rsMetadata,
263
            int colIndex
264
        ) throws SQLException {
265

    
266
        EditableFeatureAttributeDescriptor attr = type.add(
267
                rsMetadata.getColumnName(colIndex),
268
                this.getDataTypeFromMetadata(rsMetadata, colIndex)
269
        );
270
        attr.setAllowNull(
271
            rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable
272
        );
273
        attr.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
274
        attr.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
275
        attr.setPrecision(rsMetadata.getPrecision(colIndex));
276
        attr.setSize(rsMetadata.getColumnDisplaySize(colIndex));
277
        switch(attr.getType()) {
278
            case DataTypes.OBJECT:
279
                attr.setAdditionalInfo(
280
                        "SQLType",
281
                        rsMetadata.getColumnType(colIndex)
282
                );
283
                attr.setAdditionalInfo(
284
                        "SQLTypeName",
285
                        rsMetadata.getColumnTypeName(colIndex)
286
                );
287
                break;
288
            case DataTypes.GEOMETRY:
289
                this.fetchGeometryType(attr, rsMetadata, colIndex);
290
                break;
291
        }
292
        return attr;
293
    }
294

    
295
    protected void fetchGeometryType(
296
            EditableFeatureAttributeDescriptor attr,
297
            ResultSetMetaData rsMetadata,
298
            int colIndex
299
        ) {
300
        try {
301
            GeometryType geomType = GeometryLocator.getGeometryManager().getGeometryType(
302
                    Geometry.TYPES.GEOMETRY,
303
                    Geometry.SUBTYPES.GEOM2D
304
            );
305
            attr.setGeometryType(geomType);
306
        } catch (Exception ex) {
307
            logger.warn("Can't get default geometry type.",ex);
308
        }
309
    }
310
    
311
    protected int getDataTypeFromMetadata(
312
            ResultSetMetaData rsMetadata,
313
            int colIndex
314
        ) throws SQLException {
315

    
316
        switch (rsMetadata.getColumnType(colIndex)) {
317
            case java.sql.Types.INTEGER:
318
                return DataTypes.INT;
319

    
320
            case java.sql.Types.BIGINT:
321
                return DataTypes.LONG;
322

    
323
            case java.sql.Types.REAL:
324
                return DataTypes.DOUBLE;
325

    
326
            case java.sql.Types.DOUBLE:
327
                return DataTypes.DOUBLE;
328

    
329
            case java.sql.Types.CHAR:
330
                return DataTypes.STRING;
331

    
332
            case java.sql.Types.VARCHAR:
333
            case java.sql.Types.LONGVARCHAR:
334
                return DataTypes.STRING;
335

    
336
            case java.sql.Types.FLOAT:
337
                return DataTypes.DOUBLE;
338

    
339
            case java.sql.Types.NUMERIC:
340
                return DataTypes.DOUBLE;
341

    
342
            case java.sql.Types.DECIMAL:
343
                return DataTypes.FLOAT;
344

    
345
            case java.sql.Types.DATE:
346
                return DataTypes.DATE;
347

    
348
            case java.sql.Types.TIME:
349
                return DataTypes.TIME;
350

    
351
            case java.sql.Types.TIMESTAMP:
352
                return DataTypes.TIMESTAMP;
353

    
354
            case java.sql.Types.BOOLEAN:
355
            case java.sql.Types.BIT:
356
                return DataTypes.BOOLEAN;
357

    
358
            case java.sql.Types.BLOB:
359
            case java.sql.Types.BINARY:
360
            case java.sql.Types.LONGVARBINARY:
361
                return DataTypes.BYTEARRAY;
362

    
363
            default:
364
                String typeName = rsMetadata.getColumnTypeName(colIndex);
365
                if( "geometry".equalsIgnoreCase(typeName) ) {
366
                    return DataTypes.GEOMETRY;
367
                }
368
                return DataTypes.OBJECT;
369
        }
370
    }
371

    
372
    protected void fetch_CRS_and_shapeType(
373
            Connection conn,
374
            ResultSetMetaData rsMetadata,
375
            EditableFeatureType featureType,
376
            String schema,
377
            String table
378
        ) throws SQLException {
379

    
380
        // Nothing to do
381
    }
382

    
383
}