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

History | View | Annotate | Download (13.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 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
        return pks != null && pks.contains(attr.getName());
155
    }
156
    
157
    protected List<String> getPrimaryKeysFromMetadata(
158
            Connection conn,
159
            String catalog,
160
            String schema,
161
            String table) throws SQLException {
162

    
163
        ResultSet rsPrimaryKeys = null;
164
        ResultSet rs = null;
165
        try {
166
            DatabaseMetaData metadata = conn.getMetaData();
167
            rs = metadata.getTables(catalog, schema, table, null);
168

    
169
            if (!rs.next()) {
170
                // No tables found with default values, ignoring catalog
171
                rs.close();
172
                catalog = null;
173
                schema = null;
174
                rs = metadata.getTables(catalog, schema, table, null);
175
                if (!rs.next()) {
176
                    // table not found
177
                    return null;
178
                } else if (rs.next()) {
179
                    // More that one, cant identify
180
                    return null;
181
                }
182

    
183
            } else if (rs.next()) {
184
                // More that one, cant identify
185
                return null;
186
            }
187
            rsPrimaryKeys = metadata.getPrimaryKeys(catalog, schema, table);
188
            List pks = new ArrayList();
189
            while (rsPrimaryKeys.next()) {
190
                pks.add(rsPrimaryKeys.getString("COLUMN_NAME"));
191
            }
192
            return pks;
193

    
194
        } catch (SQLException e) {
195
            return null;
196

    
197
        } finally {
198
            JDBCUtils.closeQuietly(rs);
199
            JDBCUtils.closeQuietly(rsPrimaryKeys);
200
        }
201

    
202
    }
203

    
204
    protected List<String> getPrimaryKeysFromInformationSchema(
205
            Connection conn,
206
            String catalog,
207
            String schema,
208
            String table) throws SQLException {
209

    
210
        JDBCSQLBuilderBase sqlbuilder = this.createSQLBuilder();
211

    
212
        sqlbuilder.select().column().name("COLUMN_NAME");
213
        sqlbuilder.select().column().name("CONSTRAINT_TYPE");
214
        sqlbuilder.select().from().custom(
215
                "INFORMATION_SCHEMA.table_constraints t_cons "
216
                + "inner join INFORMATION_SCHEMA.key_column_usage c on "
217
                + "c.constraint_catalog = t_cons.constraint_catalog and "
218
                + "c.table_schema = t_cons.table_schema and "
219
                + "c.table_name = t_cons.table_name and "
220
                + "c.constraint_name = t_cons.constraint_name "
221
        );
222
        sqlbuilder.select().where().set(
223
                sqlbuilder.like(
224
                        sqlbuilder.custom("c.TABLE_NAME"), // Con SQLServer si pones comillas no funciona.
225
                        sqlbuilder.constant(table)
226
                )
227
        );
228
        if (schema != null) {
229
            sqlbuilder.select().where().and(
230
                    sqlbuilder.like(
231
                            sqlbuilder.custom("c.TABLE_SCHEMA"),
232
                            sqlbuilder.constant(schema)
233
                    )
234
            );
235
        }
236
        if (catalog != null) {
237
            sqlbuilder.select().where().and(
238
                    sqlbuilder.like(
239
                            sqlbuilder.custom("c.CONSTRAINT_CATALOG"),
240
                            sqlbuilder.constant(catalog)
241
                    )
242
            );
243
        }
244
        sqlbuilder.select().where().and(
245
                sqlbuilder.eq(
246
                        sqlbuilder.column("CONSTRAINT_TYPE"),
247
                        sqlbuilder.constant("PRIMARY KEY")
248
                )
249
        );
250

    
251
        Statement st = null;
252
        ResultSet rs = null;
253
        List<String> pks = new ArrayList();
254
        try {
255
            st = conn.createStatement();
256
            rs = JDBCUtils.executeQuery(st, sqlbuilder.toString());
257
            while (rs.next()) {
258
                pks.add(rs.getString(1));
259
            }
260
            if (pks.isEmpty()) {
261
                return null;
262
            }
263
            return pks;
264

    
265
        } finally {
266
            JDBCUtils.closeQuietly(rs);
267
            JDBCUtils.closeQuietly(st);
268
        }
269
    }
270

    
271
    protected EditableFeatureAttributeDescriptor getAttributeFromMetadata(
272
            EditableFeatureType type,
273
            Connection conn,
274
            ResultSetMetaData rsMetadata,
275
            int colIndex
276
        ) throws SQLException {
277

    
278
        EditableFeatureAttributeDescriptor attr = type.add(
279
                rsMetadata.getColumnName(colIndex),
280
                this.getDataTypeFromMetadata(rsMetadata, colIndex)
281
        );
282
        attr.setAllowNull(
283
            rsMetadata.isNullable(colIndex) == ResultSetMetaData.columnNullable
284
        );
285
        attr.setIsAutomatic(rsMetadata.isAutoIncrement(colIndex));
286
        attr.setIsReadOnly(rsMetadata.isReadOnly(colIndex));
287
        attr.setPrecision(rsMetadata.getPrecision(colIndex));
288
        attr.setSize(rsMetadata.getColumnDisplaySize(colIndex));
289
        switch(attr.getType()) {
290
            case DataTypes.OBJECT:
291
                attr.setAdditionalInfo(
292
                        "SQLType",
293
                        rsMetadata.getColumnType(colIndex)
294
                );
295
                attr.setAdditionalInfo(
296
                        "SQLTypeName",
297
                        rsMetadata.getColumnTypeName(colIndex)
298
                );
299
                break;
300
            case DataTypes.GEOMETRY:
301
                this.fetchGeometryTypeAndSRS(attr, rsMetadata, colIndex);
302
                break;
303
        }
304
        return attr;
305
    }
306

    
307
    protected int getDataTypeFromMetadata(
308
            ResultSetMetaData rsMetadata,
309
            int colIndex
310
        ) throws SQLException {
311

    
312
        switch (rsMetadata.getColumnType(colIndex)) {
313
            case java.sql.Types.INTEGER:
314
                return DataTypes.INT;
315

    
316
            case java.sql.Types.BIGINT:
317
                return DataTypes.LONG;
318

    
319
            case java.sql.Types.REAL:
320
                return DataTypes.DOUBLE;
321

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

    
325
            case java.sql.Types.CHAR:
326
                return DataTypes.STRING;
327

    
328
            case java.sql.Types.VARCHAR:
329
            case java.sql.Types.LONGVARCHAR:
330
                return DataTypes.STRING;
331

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

    
335
            case java.sql.Types.NUMERIC:
336
                return DataTypes.DOUBLE;
337

    
338
            case java.sql.Types.DECIMAL:
339
                return DataTypes.FLOAT;
340

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

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

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

    
350
            case java.sql.Types.BOOLEAN:
351
            case java.sql.Types.BIT:
352
                return DataTypes.BOOLEAN;
353

    
354
            case java.sql.Types.BLOB:
355
            case java.sql.Types.BINARY:
356
            case java.sql.Types.LONGVARBINARY:
357
                return DataTypes.BYTEARRAY;
358

    
359
            default:
360
                String typeName = rsMetadata.getColumnTypeName(colIndex);
361
                if( "geometry".equalsIgnoreCase(typeName) ) {
362
                    return DataTypes.GEOMETRY;
363
                }
364
                return DataTypes.OBJECT;
365
        }
366
    }
367

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