Statistics
| Revision:

gvsig-oracle / org.gvsig.oracle / trunk / org.gvsig.oracle / org.gvsig.oracle.provider / src / main / java / org / gvsig / oracle / dal / OracleHelper.java @ 67

History | View | Annotate | Download (13 KB)

1

    
2
package org.gvsig.oracle.dal;
3

    
4
import java.nio.ByteBuffer;
5
import java.nio.ByteOrder;
6
import java.sql.Connection;
7
import java.sql.PreparedStatement;
8
import java.sql.ResultSet;
9
import java.sql.SQLException;
10
import java.text.MessageFormat;
11
import java.util.ArrayList;
12
import java.util.List;
13

    
14
import org.apache.commons.dbcp.BasicDataSource;
15
import org.apache.commons.lang3.StringUtils;
16
import org.cresques.cts.IProjection;
17
import org.gvsig.fmap.crs.CRSFactory;
18
import org.gvsig.fmap.dal.DataTypes;
19
import org.gvsig.fmap.dal.ExpressionBuilder;
20
import org.gvsig.fmap.dal.SQLBuilder;
21
import org.gvsig.fmap.dal.exception.DataException;
22
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
23
import org.gvsig.fmap.dal.feature.FeatureType;
24
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
25
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
26
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
27
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
28
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
29
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
30
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCCantFetchValueException;
31
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
32
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
33
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
34
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
35
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
36
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverBase;
37
import org.gvsig.fmap.geom.Geometry;
38
import org.gvsig.fmap.geom.aggregate.MultiLine;
39
import org.gvsig.fmap.geom.aggregate.MultiPoint;
40
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
41
import org.gvsig.fmap.geom.exception.CreateGeometryException;
42
import org.gvsig.fmap.geom.primitive.Primitive;
43
import org.gvsig.fmap.geom.type.GeometryType;
44
import org.gvsig.oracle.dal.operations.OracleOperationsFactory;
45
import org.slf4j.Logger;
46
import org.slf4j.LoggerFactory;
47

    
48
public class OracleHelper extends JDBCHelperBase {
49

    
50
    static final Logger logger = LoggerFactory.getLogger(OracleHelper.class);
51

    
52
    public static final String ORACLE_JDBC_DRIVER = "oracle.jdbc.driver.OracleDriver";
53
    
54
    public static String getConnectionURL(OracleConnectionParameters params) {
55
        return getConnectionURL(
56
            params.getHost(),
57
            params.getPort(),
58
            params.getDBName()
59
        );
60
    }
61
    
62
    public static String getConnectionURL(String host, Integer port, String db) {
63
        if( StringUtils.isEmpty(host) ) {
64
            throw new IllegalArgumentException("Parameter 'host' can't be null.");
65
        }
66
        if( port==null ) {
67
            throw new IllegalArgumentException("Parameter 'port' can't be null.");
68
        }
69
        if( StringUtils.isEmpty(db) ) {
70
            throw new IllegalArgumentException("Parameter 'db' can't be null.");
71
        }
72
        //
73
        // http://docs.oracle.com/cd/E11882_01/appdev.112/e13995/oracle/jdbc/OracleDriver.html
74
        //
75
        String connectionURL = MessageFormat.format(
76
            "jdbc:oracle:thin:@{0}:{1,number,######}:{2}",
77
            host,
78
            port,
79
            db
80
        );
81
        logger.debug("connectionURL: {}", connectionURL);
82
        return connectionURL;
83
    }
84

    
85
    private static class ConnectionProvider {
86

    
87
        private static boolean needRegisterDriver = true;
88

    
89
        private BasicDataSource dataSource = null;
90

    
91
        private final OracleConnectionParameters connectionParameters;
92

    
93
        public ConnectionProvider(OracleConnectionParameters connectionParameters) {
94
            this.connectionParameters = connectionParameters;
95
        }
96

    
97
        public Connection getConnection() throws SQLException {
98
            if (this.dataSource == null) {
99
                this.dataSource = this.createDataSource();               
100
            }
101
            Connection conn = this.dataSource.getConnection();
102
            return conn;
103
        }
104

    
105
        private BasicDataSource createDataSource() throws SQLException {
106
            if (!this.isRegistered()) {
107
                this.registerDriver();
108
            }
109
            OracleConnectionParameters params = connectionParameters;
110

    
111
            BasicDataSource ds = new BasicDataSource();
112
            ds.setDriverClassName(params.getJDBCDriverClassName());
113
            if( !StringUtils.isEmpty(params.getUser()) ) {
114
                ds.setUsername(params.getUser());
115
            }
116
            if( !StringUtils.isEmpty(params.getPassword()) ) {
117
                ds.setPassword(params.getPassword());
118
            }
119
            ds.setUrl(params.getUrl());
120

    
121
            ds.setMaxWait(60L * 1000);
122
            return ds;
123
        }
124

    
125
        private boolean isRegistered() {
126
            return needRegisterDriver;
127
        }
128

    
129
        public void registerDriver() throws SQLException {
130
            String className = this.connectionParameters.getJDBCDriverClassName();
131
            if (className == null) {
132
                return;
133
            }
134
            try {
135
                Class theClass = Class.forName(className);
136
                if (theClass == null) {
137
                    throw new JDBCDriverClassNotFoundException(OracleLibrary.NAME, className);
138
                }
139
            } catch (Exception e) {
140
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
141
            }
142
            needRegisterDriver = false;
143
        }
144

    
145
    }
146

    
147
    private ConnectionProvider connectionProvider = null;
148
   
149
    public OracleHelper(JDBCConnectionParameters connectionParameters) {
150
        super(connectionParameters);
151
        this.srssolver = new SRSSolverBase(this);
152
    }
153

    
154
    @Override
155
    public Connection getConnection() throws AccessResourceException {
156
        try {
157
            if (this.connectionProvider == null) {
158
                this.connectionProvider = new ConnectionProvider(this.getConnectionParameters());
159
            }
160
            return this.connectionProvider.getConnection();
161
        } catch (SQLException ex) {
162
            throw new AccessResourceException(OracleLibrary.NAME, ex);
163
        }
164
    }
165
    
166
    @Override
167
    public OracleConnectionParameters getConnectionParameters() {
168
        return (OracleConnectionParameters) super.getConnectionParameters();
169
    }
170
    
171
    @Override
172
    public String getConnectionURL() {
173
        return getConnectionURL(this.getConnectionParameters());
174
    }
175

    
176
    @Override
177
    protected String getResourceType() {
178
        return OracleLibrary.NAME;
179
    }
180

    
181
    @Override
182
    public String getProviderName() {
183
        return OracleLibrary.NAME;
184
    }
185

    
186
    @Override
187
    public JDBCSQLBuilderBase createSQLBuilder() {
188
        return new OracleSQLBuilder(this);
189
    }
190
    
191
    @Override
192
    public OperationsFactory getOperations() {
193
        if (this.operationsFactory == null) {
194
            this.operationsFactory = new OracleOperationsFactory(this);
195
        }
196
        return operationsFactory;
197
    }
198

    
199
    @Override
200
    public SQLBuilder.GeometrySupportType getGeometrySupportType() {
201
        return SQLBuilder.GeometrySupportType.WKB;
202
    }
203

    
204
    @Override
205
    public boolean hasSpatialFunctions() {
206
        return true;
207
    }
208

    
209
    @Override
210
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
211
        return true;
212
    }
213

    
214
    @Override
215
    public String getQuoteForIdentifiers() {
216
        return "\"";
217
    }
218

    
219
    @Override
220
    public boolean allowAutomaticValues() {
221
        return true;
222
    }
223

    
224
    @Override
225
    public boolean supportOffsetInSelect() {
226
        return true;
227
    }
228

    
229
    @Override
230
    public String getQuoteForStrings() {
231
        return "'";
232
    }
233
    
234
    @Override
235
    public String getSourceId(JDBCStoreParameters parameters) {
236
        return parameters.getDBName() + "." + 
237
               parameters.getSchema()+ "." + 
238
               parameters.getTable();
239
    }
240

    
241
    @Override
242
    public JDBCNewStoreParameters createNewStoreParameters() {
243
        return new OracleNewStoreParameters();
244
    }
245

    
246
    @Override
247
    public JDBCStoreParameters createOpenStoreParameters() {
248
        return new OracleStoreParameters();
249
    }
250

    
251
    @Override
252
    public JDBCServerExplorerParameters createServerExplorerParameters() {
253
        return new OracleExplorerParameters();
254
    }
255

    
256
    public void setPreparedStatementParameters(PreparedStatement st, JDBCSQLBuilderBase sqlbuilder, FeatureType type, FeatureProvider feature) {
257
        try {
258
            List<Object> values = new ArrayList<>();
259
            for (ExpressionBuilder.Parameter parameter : sqlbuilder.getParameters()) {
260
                Object value;
261
                if (parameter.is_constant()) {
262
                    value = parameter.getValue();
263
                } else {
264
                    String name = parameter.getName();
265
                    value = feature.get(name);
266
                    FeatureAttributeDescriptor attr = type.getAttributeDescriptor(name);
267
                    if( attr.getType()==DataTypes.GEOMETRY ) {
268
                        value = forceGeometry(attr.getGeomType(), (Geometry) value);
269
                    }
270
                }
271
                values.add(value);
272
            }
273
            JDBCUtils.setObjects(st, values, sqlbuilder.geometry_support_type());
274
        } catch (Exception ex) {
275
            String f = "unknow";
276
            try {
277
                f = feature.toString();
278
            } catch (Exception ex2) {
279
                // Do nothing
280
            }
281
            throw new RuntimeException("Can't set parameters to prepared statement from the feature (" + f + ")", ex);
282
        }
283
    }
284
    
285
    private Geometry forceGeometry(GeometryType geomtype, Geometry geom) throws CreateGeometryException {
286
        switch( geomtype.getType() ) {
287
        case Geometry.TYPES.MULTIPOLYGON:
288
            if( geom.getType()==Geometry.TYPES.POLYGON ) {
289
                MultiPolygon x = getGeometryManager().createMultiPolygon(geomtype.getSubType());
290
                x.addPrimitive((Primitive) geom);
291
                geom = x;
292
            }
293
            break;
294
        case Geometry.TYPES.MULTILINE:
295
            if( geom.getType()==Geometry.TYPES.LINE ) {
296
                MultiLine x = getGeometryManager().createMultiLine(geomtype.getSubType());
297
                x.addPrimitive((Primitive) geom);
298
                geom = x;
299
            }
300
            break;
301
        case Geometry.TYPES.MULTIPOINT:
302
            if( geom.getType()==Geometry.TYPES.POINT ) {
303
                MultiLine x = getGeometryManager().createMultiLine(geomtype.getSubType());
304
                x.addPrimitive((Primitive) geom);
305
                geom = x;
306
            }
307
            break;
308
        case Geometry.TYPES.POLYGON:
309
            if( geom.getType()==Geometry.TYPES.MULTIPOLYGON ) {
310
                MultiPolygon x = (MultiPolygon) geom;
311
                if( x.getPrimitivesNumber()==1 ) {
312
                    geom = x.getPrimitiveAt(0);
313
                }
314
            }
315
            break;
316
        case Geometry.TYPES.LINE:
317
            if( geom.getType()==Geometry.TYPES.MULTILINE ) {
318
                MultiLine x = (MultiLine) geom;
319
                if( x.getPrimitivesNumber()==1 ) {
320
                    geom = x.getPrimitiveAt(0);
321
                }
322
            }
323
            break;
324
        case Geometry.TYPES.POINT:
325
            if( geom.getType()==Geometry.TYPES.MULTIPOINT ) {
326
                MultiPoint x = (MultiPoint) geom;
327
                if( x.getPrimitivesNumber()==1 ) {
328
                    geom = x.getPrimitiveAt(0);
329
                }
330
            }
331
        }
332
        return geom;
333
    }
334
    
335

    
336
    @Override
337
    public Geometry getGeometryFromColumn(ResultSet rs, int index) throws DataException {
338
        try {
339
                // Oracle uses non-standard WKB encoding for rectangles (used in bounding boxes)
340
                // Correct it when needed
341
                byte[] wkb = (byte[]) rs.getBytes(index);
342

    
343
                ByteBuffer data = ByteBuffer.wrap(wkb);
344
                byte endian = data.get();
345
                if (endian == 1) {
346
                    data.order(ByteOrder.LITTLE_ENDIAN);
347
                }
348
                int typeword = data.getInt();
349
                int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits
350
                if (realtype==3) { // polygon
351
                        int rings = data.getInt();
352
                        if (rings==1) {
353
                                int count = data.getInt();
354
                                if (count==2) { // Declares 2 points but it has in fact 5
355
                                        data.putInt(9, 5);
356
                                }
357
                        }
358
                }
359
                return this.getGeometryManager().createFrom(wkb);
360
        } catch (Exception ex) {
361
            throw new JDBCCantFetchValueException(ex);
362
        }
363
    }
364

    
365
    @Override
366
    public IProjection getProjectionFromDatabaseCode(String databaseCode) {
367
            /**
368
             * FIXME: We can query the following table to search the proper definition:
369
             * SELECT * FROM SDO_COORD_REF_SYS  ;
370
             */
371
        if( StringUtils.trimToEmpty(databaseCode).equals("0") ) {
372
            return null;
373
        }
374
        String abbrev = null;
375
                try {
376
                        abbrev = this.srssolver.getApplicationAbbrev(this.getConnection(), databaseCode);
377
                } catch (AccessResourceException e) {
378
                        // TODO Auto-generated catch block
379
                        e.printStackTrace();
380
                }
381
        if( StringUtils.isEmpty(abbrev) ) {
382
            return null;
383
        }
384
        IProjection proj = CRSFactory.getCRS(abbrev);
385
        return proj;
386
    }
387

    
388
}