Statistics
| Revision:

gvsig-mssqlserver / trunk / org.gvsig.mssqlserver / org.gvsig.mssqlserver.provider / src / main / java / org / gvsig / mssqlserver / dal / MSSQLServerHelper.java @ 213

History | View | Annotate | Download (14.2 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2016 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.mssqlserver.dal;
23

    
24
import org.gvsig.mssqlserver.dal.operations.MSSQLServerOperationsFactory;
25
import java.sql.Connection;
26
import java.sql.ResultSet;
27
import java.sql.SQLException;
28
import java.sql.Statement;
29
import java.text.MessageFormat;
30
import java.util.ArrayList;
31
import java.util.List;
32
import org.apache.commons.dbcp.BasicDataSource;
33
import org.apache.commons.lang3.StringUtils;
34
import org.gvsig.expressionevaluator.ExpressionBuilder;
35
import org.gvsig.fmap.dal.DataParameters;
36
import org.gvsig.fmap.dal.DataTypes;
37
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
38
import org.gvsig.fmap.dal.feature.FeatureType;
39
import org.gvsig.fmap.dal.SQLBuilder;
40
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
41
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
42
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
43
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
44
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
45
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
46
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
47
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
48
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
49
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
51
import org.gvsig.fmap.geom.Geometry;
52
import org.gvsig.fmap.geom.primitive.Envelope;
53
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
55

    
56
public class MSSQLServerHelper extends JDBCHelperBase {
57

    
58
    private static final Logger logger = LoggerFactory.getLogger(MSSQLServerHelper.class);
59

    
60
    public static final String NAME = "MSSQLServer";
61
    public static final String INSTANCE_NAME = "SQLEXPRESS";
62
    public static final int PORT = 1433;
63
    public static final String MSSQLServerJDBCDriver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
64
    
65
//    private static final boolean ALLOW_AUTOMATIC_VALUES = true;
66
//    private static final String QUOTE_FOR_USE_IN_IDENTIFIERS = "\"";
67
//    private static final String QUOTE_FOR_USE_IN_STRINGS = "'";
68

    
69
    public static String getConnectionURL(JDBCConnectionParameters params) {
70
        String connectionURL = MessageFormat.format(
71
                //"jdbc:sqlserver://{0}:{1,number,#};databaseName={2};instanceName={3};",
72
                "jdbc:sqlserver://{0};databaseName={2};instanceName={3};",
73
                params.getHost(),
74
                params.getPort(),
75
                params.getDBName(),
76
                ((DataParameters) params).getDynValue("instanceName")
77
        );
78
        logger.debug("connectionURL: {}", connectionURL);
79
        return connectionURL;
80
    }
81

    
82
    private static class ConnectionProvider {
83

    
84
        private static boolean needRegisterDriver = true;
85

    
86
        private BasicDataSource dataSource = null;
87

    
88
        private final JDBCConnectionParameters connectionParameters;
89

    
90
        public ConnectionProvider(JDBCConnectionParameters connectionParameters) {
91
            this.connectionParameters = connectionParameters;
92
        }
93

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

    
102
        private BasicDataSource createDataSource() throws SQLException {
103
            if (!this.isRegistered()) {
104
                this.registerDriver();
105
            }
106
            JDBCConnectionParameters params = connectionParameters;
107

    
108
            BasicDataSource dataSource = new BasicDataSource();
109
            dataSource.setDriverClassName(params.getJDBCDriverClassName());
110
            dataSource.setUsername(params.getUser());
111
            dataSource.setPassword(params.getPassword());
112
            dataSource.setUrl(params.getUrl());
113

    
114
            dataSource.setMaxWait(60L * 1000);
115
            return dataSource;
116
        }
117

    
118
        private boolean isRegistered() {
119
            return needRegisterDriver;
120
        }
121

    
122
        public void registerDriver() throws SQLException {
123
            String className = this.connectionParameters.getJDBCDriverClassName();
124
            if (className == null) {
125
                return;
126
            }
127
            try {
128
                Class theClass = Class.forName(className);
129
                if (theClass == null) {
130
                    throw new JDBCDriverClassNotFoundException(MSSQLServerLibrary.NAME, className);
131
                }
132
            } catch (Exception e) {
133
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
134
            }
135
            needRegisterDriver = false;
136
        }
137

    
138
    }
139

    
140
    private ConnectionProvider connectionProvider = null;
141

    
142
    private FeatureType lastUsedFeatureType = null;
143
    private String lastUsedSpatialType = null;
144
    
145
    public MSSQLServerHelper(JDBCConnectionParameters connectionParameters) {
146
        super(connectionParameters);
147
    }
148

    
149
    @Override
150
    public Connection getConnection() throws AccessResourceException {
151
        try {
152
            if (this.connectionProvider == null) {
153
                this.connectionProvider = new ConnectionProvider(this.getConnectionParameters());
154
            }
155
            return this.connectionProvider.getConnection();
156
        } catch (SQLException ex) {
157
            throw new AccessResourceException(MSSQLServerLibrary.NAME, ex);
158
        }
159
    }
160
    
161
    @Override
162
    public String getConnectionURL() {
163
        return getConnectionURL(this.getConnectionParameters());
164
    }
165

    
166
    @Override
167
    protected String getResourceType() {
168
        return MSSQLServerLibrary.NAME;
169
    }
170

    
171
    @Override
172
    public String getProviderName() {
173
        return MSSQLServerLibrary.NAME;
174
    }
175

    
176
    @Override
177
    public JDBCSQLBuilderBase createSQLBuilder() {
178
        return new MSSQLServerSQLBuilder(this);
179
    }
180

    
181
    /**
182
     * Devuelbe el nombre del tipo de datos espacial de SQLServer asociado 
183
     * al ultimo FeatureType cargado.
184
     * 
185
     * Esta funcion es usada para dar un soporte limitado al tipo de datos
186
     * spaciales "geography".
187
     * 
188
     * Si no disponemos de un FeatureType asumimos "geometry".
189
     * Si hay un solo campo espacial asume el tipo de ese campo, y si 
190
     * hay mas de uno asume "geometry".
191
     * En caso de que no haya ningun campo espacial asumimos "geometry".
192
     * 
193
     * @return "geometry" or "geography" for the last used table.
194
     */
195
    public String getSpatialType() {
196
        if( this.lastUsedSpatialType != null ) {
197
            return this.lastUsedSpatialType;
198
        }
199
        if( this.lastUsedFeatureType == null ) {
200
            this.lastUsedSpatialType = "geometry";
201
            return this.lastUsedSpatialType;
202
        }
203
        String spatialType = null;
204
        for (FeatureAttributeDescriptor attr : lastUsedFeatureType) {
205
            if( attr.getType() == DataTypes.GEOMETRY ) {
206
                if( spatialType != null ) {
207
                    this.lastUsedSpatialType = "geometry";
208
                    return this.lastUsedSpatialType;
209
                }
210
                spatialType = (String) attr.getAdditionalInfo("SQLServer_type_name");
211
            }
212
        }
213
        if( StringUtils.isEmpty(spatialType) ) {
214
            this.lastUsedSpatialType = "geometry";
215
            return this.lastUsedSpatialType;
216
        }
217
        this.lastUsedSpatialType = spatialType;
218
        return this.lastUsedSpatialType;
219
    }
220

    
221
    /**
222
     * Devuelbe el tipo de datos espacial de SQLServer asociado a la columna 
223
     * indicada.
224
     * 
225
     * Esta funcion es usada para dar un soporte limitado al tipo de datos
226
     * spaciales "geography".
227
     * 
228
     * Si no disponemos de un FeatureType asumimos "geometry".
229
     * Si no existe el campo solicitado o no es de tipo geoemtria, asumimos 
230
     * el tipo espacia asociado al FeatureType (getSpatialType()).
231
     * 
232
     * @param columnName
233
     * @return "geometry" or "geography" for column in the last used table.
234
     */
235
    public String getSpatialType(String columnName) {
236
        if( this.lastUsedFeatureType == null ) {
237
            return "geometry";
238
        }
239
        FeatureAttributeDescriptor attr = this.lastUsedFeatureType.getAttributeDescriptor(columnName);
240
        if( attr == null ) {
241
            return this.getSpatialType();
242
        }
243
        if( attr.getType() != DataTypes.GEOMETRY ) {
244
            return this.getSpatialType();
245
        }
246
        String spatialType = (String) attr.getAdditionalInfo("SQLServer_type_name");
247
        if( StringUtils.isEmpty(spatialType) ) {
248
            return "geometry";
249
        }
250
        return spatialType;
251
    }
252
    
253
    public void setLastUsedFeatureType(FeatureType featureType) {
254
        this.lastUsedSpatialType = null;
255
        this.lastUsedFeatureType = featureType;
256
    }
257

    
258
    public void createOrUpdateSpatialIndex(
259
            Connection conn,
260
            String database,
261
            String schema,
262
            String table,
263
            String columnName
264
        ) throws JDBCSQLException {
265
        List<String> sqls = this.createOrUpdateSpatialIndexSql(
266
                conn, database, schema, table, columnName
267
        );
268
        Statement st = null;
269
        try {
270
            st = conn.createStatement();
271
            for (String sql : sqls) {
272
                JDBCUtils.execute(st, sql);
273
            }
274
        } catch (SQLException ex) {
275
            throw new JDBCSQLException(ex);
276
        } finally {
277
            JDBCUtils.closeQuietly(st);
278
        }
279
        
280
    }
281
    
282
    public List<String> createOrUpdateSpatialIndexSql(
283
            Connection conn,
284
            String database,
285
            String schema,
286
            String table,
287
            String columnName
288
        ) throws JDBCSQLException {
289
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
290
        MSSQLServerSQLBuilder.MSSQLServerCreateIndexBuilder create_index = (MSSQLServerSQLBuilder.MSSQLServerCreateIndexBuilder) sqlbuilder.create_index();
291

    
292
        sqlbuilder.create_index().spatial();
293
        create_index.setBoundingBox(
294
                this.getBoundingBox(
295
                        conn,
296
                        database,
297
                        schema,
298
                        table,
299
                        columnName
300
                )
301
        );
302
        create_index.if_not_exist();
303
        create_index.name("idx_" + table + "_" + columnName);
304
        create_index.column(columnName);
305
        create_index.table().database(database).schema(schema).name(table);
306

    
307
        return create_index.toStrings();
308
    }    
309
    
310
    public Envelope getBoundingBox(
311
            Connection conn,
312
            String database,
313
            String schema,
314
            String table,
315
            String columnName
316
        ) throws JDBCSQLException {
317
        JDBCSQLBuilderBase sqlbuilder = createSQLBuilder();
318
        ExpressionBuilder expbuilder = sqlbuilder.expression();
319
        
320
        sqlbuilder.select().column().value(
321
            expbuilder.as_geometry(
322
                expbuilder.ST_ExtentAggregate(
323
                        expbuilder.column(columnName)
324
                )
325
            )
326
        );
327
        sqlbuilder.select().from().table().database(database).schema(schema).name(table);
328

    
329
        String sql = sqlbuilder.select().toString();
330
        Statement st = null;
331
        ResultSet rs = null;
332
        try {
333
            st = conn.createStatement();
334
            rs = JDBCUtils.executeQuery(st, sql);
335
            if (!rs.next()) {
336
                return null;
337
            }
338
            Geometry geom = this.getGeometryFromColumn(rs, 1);
339
            if (geom == null) {
340
                return null;
341
            }
342
            return geom.getEnvelope();
343

    
344
        } catch (Exception ex) {
345
            throw new JDBCSQLException(ex);
346
        } finally {
347
            JDBCUtils.closeQuietly(st);
348
            JDBCUtils.closeQuietly(rs);
349
        }        
350
    }
351
    
352
    @Override
353
    public OperationsFactory getOperations() {
354
        if (this.operationsFactory == null) {
355
            this.operationsFactory = new MSSQLServerOperationsFactory(this);
356
        }
357
        return operationsFactory;
358
    }
359

    
360
    @Override
361
    public ExpressionBuilder.GeometrySupportType getGeometrySupportType() {
362
        return ExpressionBuilder.GeometrySupportType.WKB;
363
    }
364

    
365
    @Override
366
    public boolean hasSpatialFunctions() {
367
        return true;
368
    }
369

    
370
    @Override
371
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
372
        return true;
373
    }
374

    
375
    @Override
376
    public String getQuoteForIdentifiers() {
377
        return "\"";
378
    }
379

    
380
    @Override
381
    public boolean allowAutomaticValues() {
382
        return true;
383
    }
384

    
385
    @Override
386
    public boolean supportOffsetInSelect() {
387
        return true;
388
    }
389

    
390
    @Override
391
    public String getQuoteForStrings() {
392
        return "'";
393
    }
394

    
395
    @Override
396
    public String getSourceId(JDBCStoreParameters parameters) {
397
        return parameters.getHost() + ":" +
398
               parameters.getDynValue("InstanceName")+ ":" + 
399
               parameters.getDBName() + "." + 
400
               parameters.getSchema()+ "." + 
401
               parameters.getTable();
402
    }
403

    
404
    @Override
405
    public JDBCNewStoreParameters createNewStoreParameters() {
406
        return new MSSQLServerNewStoreParameters();
407
    }
408

    
409
    @Override
410
    public JDBCStoreParameters createOpenStoreParameters() {
411
        return new MSSQLServerStoreParameters();
412
    }
413

    
414
    @Override
415
    public JDBCServerExplorerParameters createServerExplorerParameters() {
416
        return new MSSQLServerExplorerParameters();
417
    }
418

    
419
}