Statistics
| Revision:

root / trunk / org.gvsig.postgresql / org.gvsig.postgresql.provider / src / main / java / org / gvsig / postgresql / dal / PostgreSQLHelper.java @ 433

History | View | Annotate | Download (14.7 KB)

1

    
2
package org.gvsig.postgresql.dal;
3

    
4
import java.sql.Connection;
5
import java.sql.PreparedStatement;
6
import java.sql.SQLException;
7
import java.util.ArrayList;
8
import java.util.List;
9
import org.apache.commons.dbcp.BasicDataSource;
10
import org.apache.commons.dbcp.BasicDataSourceFactory;
11
import org.apache.commons.lang3.BooleanUtils;
12
import org.apache.commons.lang3.StringUtils;
13
import org.gvsig.fmap.dal.DataTypes;
14
import org.gvsig.fmap.dal.ExpressionBuilder;
15
import org.gvsig.fmap.dal.SQLBuilder;
16
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
17
import org.gvsig.fmap.dal.feature.FeatureType;
18
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
19
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
20
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
21
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
22
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
23
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
24
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
25
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
26
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
27
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
28
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
29
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverBase;
30
import org.gvsig.fmap.geom.Geometry;
31
import org.gvsig.fmap.geom.aggregate.MultiLine;
32
import org.gvsig.fmap.geom.aggregate.MultiPoint;
33
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
34
import org.gvsig.fmap.geom.exception.CreateGeometryException;
35
import org.gvsig.fmap.geom.primitive.Primitive;
36
import org.gvsig.fmap.geom.type.GeometryType;
37
import org.gvsig.postgresql.dal.operations.PostgreSQLOperationsFactory;
38
import org.slf4j.Logger;
39
import org.slf4j.LoggerFactory;
40

    
41
public class PostgreSQLHelper extends JDBCHelperBase {
42

    
43
    static final Logger logger = LoggerFactory.getLogger(PostgreSQLHelper.class);
44

    
45
    public static final String POSTGRESQL_JDBC_DRIVER = "org.postgresql.Driver";
46
    
47
    public static String getConnectionURL(PostgreSQLConnectionParameters params) {
48
        return getConnectionURL(
49
            params.getHost(),
50
            params.getPort(),
51
            params.getDBName()
52
        );
53
    }
54
    
55
    public static String getConnectionURL(String host, Integer port, String db) {
56
        if( StringUtils.isEmpty(host) ) {
57
            throw new IllegalArgumentException("Parameter 'host' can't be null.");
58
        }
59
        String connectionURL = "jdbc:postgresql://" + host;
60
        if (port != null) {
61
            connectionURL = connectionURL + ":" + port;
62
        }
63
        connectionURL = connectionURL + "/" + db;
64
        logger.debug("connectionURL: {}", connectionURL);
65
        return connectionURL;
66
    }
67

    
68
    private static class ConnectionProvider {
69

    
70
        private static boolean needRegisterDriver = true;
71

    
72
        private BasicDataSource dataSource = null;
73

    
74
        private final PostgreSQLConnectionParameters connectionParameters;
75

    
76
        public ConnectionProvider(PostgreSQLConnectionParameters connectionParameters) {
77
            this.connectionParameters = connectionParameters;
78
        }
79

    
80
        public Connection getConnection() throws SQLException {
81
            if (this.dataSource == null) {
82
                this.dataSource = this.createDataSource();               
83
            }
84
            if( logger.isDebugEnabled() ) {
85
                logger.debug("getConnection:\n" + getStatusInformation());
86
            }
87
            Connection conn;
88
            try {
89
                conn = this.dataSource.getConnection();
90
            } catch(Throwable ex) {
91
                logger.debug("Error getting connection from pool.",ex);
92
                throw ex;
93
            }
94
            if( logger.isDebugEnabled() ) {
95
                logger.debug("Created connection: {}\n  NumActive: {}\n  NumIdle: {}",
96
                    new Object[] {
97
                        conn.hashCode(), 
98
                        this.dataSource.getNumActive(),
99
                        this.dataSource.getNumIdle()
100
                    }
101
                );
102
            }
103
            return conn;
104
        }
105
        
106
        public void closeConnection(Connection connection) {
107
            if( connection != null ) {
108
                int connectionId = connection.hashCode();
109
                try {
110
                    connection.close();
111
                } catch(Throwable ex) {
112
                    logger.warn("Can't close connection.", ex);
113
                }
114
                if( logger.isDebugEnabled() ) {
115
                    Boolean isClosed;
116
                    try {
117
                        isClosed = connection.isClosed();
118
                    } catch(Throwable th) {
119
                        isClosed = null;
120
                    }
121
                    logger.debug("Closed connection: {}\n  isClosed: {}\n  NumActive: {}\n  NumIdle: {}",
122
                        new Object[] {
123
                            connectionId, 
124
                            isClosed,
125
                            this.dataSource.getNumActive(),
126
                            this.dataSource.getNumIdle()
127
                        }
128
                    );
129
                }
130
           } else if( logger.isDebugEnabled() ) {
131
               logger.debug("Close connection: null");
132
           }
133
        }
134
        
135
        public String getStatusInformation() {
136
            StringBuilder builder = new StringBuilder();
137
            builder.append("BasicDataSource pool status:\n");
138
            builder.append("  Connection URL: '").append(this.dataSource.getUrl()).append("'\n");
139
            if( this.dataSource.getInitialSize()>0 ) {
140
                builder.append("  InitialSize: ").append(this.dataSource.getInitialSize()).append(" (The initial number of connections that are created when the pool is started)\n");
141
            }
142
            if( this.dataSource.isPoolPreparedStatements() ) {
143
                builder.append("  PoolPreparedStatements: ").append(this.dataSource.isPoolPreparedStatements()).append("\n");
144
                builder.append("  MaxOpenPreparedStatements: ").append(this.dataSource.getMaxOpenPreparedStatements()).append(" (The maximum number of open statements that can be allocated from the statement pool at the same time, or non-positive for no limit)\n");
145
            }
146
            builder.append("  MaxActive: ").append(this.dataSource.getMaxActive()).append(" (The maximum number of active connections that can be allocated from this pool at the same time)\n");
147
            builder.append("  MaxIdle: ").append(this.dataSource.getMaxIdle()).append(" (The maximum number of connections that can remain idle in the pool)\n");
148
            builder.append("  NumActive:").append(this.dataSource.getNumActive()).append(" (the current number of active connections)\n");
149
            builder.append("  NumIdle:").append(this.dataSource.getNumIdle()).append(" (the current number of idle connections)\n");
150
            return builder.toString();
151
        }
152

    
153
        private BasicDataSource createDataSource() throws SQLException {
154
            if (!this.isRegistered()) {
155
                this.registerDriver();
156
            }
157
            PostgreSQLConnectionParameters params = connectionParameters;
158

    
159
            BasicDataSource ds = new BasicDataSource();
160
            ds.setMaxIdle(params.getMaxIdle());
161
            ds.setDriverClassName(params.getJDBCDriverClassName());
162
            if( params.getUseSSL() ) {
163
                String s = BooleanUtils.toStringTrueFalse(params.getUseSSL());
164
                ds.addConnectionProperty("ssl", s );
165
            }
166
            if( !StringUtils.isEmpty(params.getUser()) ) {
167
                ds.setUsername(params.getUser());
168
            }
169
            if( !StringUtils.isEmpty(params.getPassword()) ) {
170
                ds.setPassword(params.getPassword());
171
            }
172
            ds.setUrl(params.getUrl());
173

    
174
            ds.setMaxWait(60L * 1000);
175
            return ds;
176
        }
177

    
178
        private boolean isRegistered() {
179
            return needRegisterDriver;
180
        }
181

    
182
        public void registerDriver() throws SQLException {
183
            String className = this.connectionParameters.getJDBCDriverClassName();
184
            if (className == null) {
185
                return;
186
            }
187
            try {
188
                Class theClass = Class.forName(className);
189
                if (theClass == null) {
190
                    throw new JDBCDriverClassNotFoundException(PostgreSQLLibrary.NAME, className);
191
                }
192
            } catch (Exception e) {
193
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
194
            }
195
            needRegisterDriver = false;
196
        }
197

    
198
    }
199

    
200
    private ConnectionProvider connectionProvider = null;
201
   
202
    public PostgreSQLHelper(JDBCConnectionParameters connectionParameters) {
203
        super(connectionParameters);
204
        this.srssolver = new SRSSolverBase(this);
205
    }
206

    
207
    @Override
208
    public Connection getConnection() throws AccessResourceException {
209
        try {
210
            if (this.connectionProvider == null) {
211
                this.connectionProvider = new ConnectionProvider(this.getConnectionParameters());
212
            }
213
            return this.connectionProvider.getConnection();
214
        } catch (SQLException ex) {
215
            throw new AccessResourceException(PostgreSQLLibrary.NAME, ex);
216
        }
217
    }
218

    
219
    @Override
220
    public void closeConnection(Connection connection) {
221
         this.connectionProvider.closeConnection(connection);
222
    }
223
    
224
    
225
    
226
    @Override
227
    public PostgreSQLConnectionParameters getConnectionParameters() {
228
        return (PostgreSQLConnectionParameters) super.getConnectionParameters();
229
    }
230
    
231
    @Override
232
    public String getConnectionURL() {
233
        return getConnectionURL(this.getConnectionParameters());
234
    }
235

    
236
    @Override
237
    protected String getResourceType() {
238
        return PostgreSQLLibrary.NAME;
239
    }
240

    
241
    @Override
242
    public String getProviderName() {
243
        return PostgreSQLLibrary.NAME;
244
    }
245

    
246
    @Override
247
    public JDBCSQLBuilderBase createSQLBuilder() {
248
        return new PostgreSQLBuilder(this);
249
    }
250
    
251
    @Override
252
    public OperationsFactory getOperations() {
253
        if (this.operationsFactory == null) {
254
            this.operationsFactory = new PostgreSQLOperationsFactory(this);
255
        }
256
        return operationsFactory;
257
    }
258

    
259
    @Override
260
    public SQLBuilder.GeometrySupportType getGeometrySupportType() {
261
        return SQLBuilder.GeometrySupportType.WKB;
262
    }
263

    
264
    @Override
265
    public boolean hasSpatialFunctions() {
266
        return true;
267
    }
268

    
269
    @Override
270
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
271
        return true;
272
    }
273

    
274
    @Override
275
    public String getQuoteForIdentifiers() {
276
        return "\"";
277
    }
278

    
279
    @Override
280
    public boolean allowAutomaticValues() {
281
        return true;
282
    }
283

    
284
    @Override
285
    public boolean supportOffsetInSelect() {
286
        return true;
287
    }
288

    
289
    @Override
290
    public String getQuoteForStrings() {
291
        return "'";
292
    }
293
    
294
    @Override
295
    public String getSourceId(JDBCStoreParameters parameters) {
296
        return parameters.getDBName() + "." + 
297
               parameters.getSchema()+ "." + 
298
               parameters.getTable();
299
    }
300

    
301
    @Override
302
    public JDBCNewStoreParameters createNewStoreParameters() {
303
        return new PostgreSQLNewStoreParameters();
304
    }
305

    
306
    @Override
307
    public JDBCStoreParameters createOpenStoreParameters() {
308
        return new PostgreSQLStoreParameters();
309
    }
310

    
311
    @Override
312
    public JDBCServerExplorerParameters createServerExplorerParameters() {
313
        return new PostgreSQLServerExplorerParameters();
314
    }
315

    
316
    public void setPreparedStatementParameters(PreparedStatement st, JDBCSQLBuilderBase sqlbuilder, FeatureType type, FeatureProvider feature) {
317
        try {
318
            List<Object> values = new ArrayList<>();
319
            for (ExpressionBuilder.Parameter parameter : sqlbuilder.getParameters()) {
320
                Object value;
321
                if (parameter.is_constant()) {
322
                    value = parameter.getValue();
323
                } else {
324
                    String name = parameter.getName();
325
                    value = feature.get(name);
326
                    FeatureAttributeDescriptor attr = type.getAttributeDescriptor(name);
327
                    if( attr.getType()==DataTypes.GEOMETRY ) {
328
                        value = forceGeometry(attr.getGeomType(), (Geometry) value);
329
                    }
330
                }
331
                values.add(value);
332
            }
333
            JDBCUtils.setObjects(st, values, sqlbuilder.geometry_support_type());
334
        } catch (Exception ex) {
335
            String f = "unknow";
336
            try {
337
                f = feature.toString();
338
            } catch (Exception ex2) {
339
                // Do nothing
340
            }
341
            throw new RuntimeException("Can't set parameters to prepared statement from the feature (" + f + ")", ex);
342
        }
343
    }
344
    
345
    private Geometry forceGeometry(GeometryType geomtype, Geometry geom) throws CreateGeometryException {
346
        if( geom == null ) {
347
            return null;
348
        }
349
        switch( geomtype.getType() ) {
350
        case Geometry.TYPES.MULTIPOLYGON:
351
            if( geom.getType()==Geometry.TYPES.POLYGON ) {
352
                MultiPolygon x = getGeometryManager().createMultiPolygon(geomtype.getSubType());
353
                x.addPrimitive((Primitive) geom);
354
                geom = x;
355
            }
356
            break;
357
        case Geometry.TYPES.MULTILINE:
358
            if( geom.getType()==Geometry.TYPES.LINE ) {
359
                MultiLine x = getGeometryManager().createMultiLine(geomtype.getSubType());
360
                x.addPrimitive((Primitive) geom);
361
                geom = x;
362
            }
363
            break;
364
        case Geometry.TYPES.MULTIPOINT:
365
            if( geom.getType()==Geometry.TYPES.POINT ) {
366
                MultiLine x = getGeometryManager().createMultiLine(geomtype.getSubType());
367
                x.addPrimitive((Primitive) geom);
368
                geom = x;
369
            }
370
            break;
371
        case Geometry.TYPES.POLYGON:
372
            if( geom.getType()==Geometry.TYPES.MULTIPOLYGON ) {
373
                MultiPolygon x = (MultiPolygon) geom;
374
                if( x.getPrimitivesNumber()==1 ) {
375
                    geom = x.getPrimitiveAt(0);
376
                }
377
            }
378
            break;
379
        case Geometry.TYPES.LINE:
380
            if( geom.getType()==Geometry.TYPES.MULTILINE ) {
381
                MultiLine x = (MultiLine) geom;
382
                if( x.getPrimitivesNumber()==1 ) {
383
                    geom = x.getPrimitiveAt(0);
384
                }
385
            }
386
            break;
387
        case Geometry.TYPES.POINT:
388
            if( geom.getType()==Geometry.TYPES.MULTIPOINT ) {
389
                MultiPoint x = (MultiPoint) geom;
390
                if( x.getPrimitivesNumber()==1 ) {
391
                    geom = x.getPrimitiveAt(0);
392
                }
393
            }
394
        }
395
        return geom;
396
    }
397
    
398

    
399
}