Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_daldb / src / org / gvsig / fmap / dal / store / postgresql / PostgreSQLStoreProvider.java @ 28424

History | View | Annotate | Download (18.4 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
*
3
* Copyright (C) 2007-2008 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 2
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

    
23
/*
24
* AUTHORS (In addition to CIT):
25
* 2009 IVER T.I   {{Task}}
26
*/
27

    
28
package org.gvsig.fmap.dal.store.postgresql;
29

    
30
import java.security.InvalidParameterException;
31
import java.sql.Connection;
32
import java.sql.PreparedStatement;
33
import java.sql.ResultSet;
34
import java.sql.SQLException;
35
import java.util.ArrayList;
36
import java.util.Iterator;
37
import java.util.List;
38
import java.util.regex.Matcher;
39
import java.util.regex.Pattern;
40

    
41
import org.cresques.cts.IProjection;
42
import org.gvsig.fmap.dal.DALLocator;
43
import org.gvsig.fmap.dal.DataManager;
44
import org.gvsig.fmap.dal.DataServerExplorer;
45
import org.gvsig.fmap.dal.DataStoreNotification;
46
import org.gvsig.fmap.dal.DataTypes;
47
import org.gvsig.fmap.dal.exception.CloseException;
48
import org.gvsig.fmap.dal.exception.DataException;
49
import org.gvsig.fmap.dal.exception.InitializeException;
50
import org.gvsig.fmap.dal.exception.OpenException;
51
import org.gvsig.fmap.dal.exception.ReadException;
52
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
53
import org.gvsig.fmap.dal.feature.EditableFeatureType;
54
import org.gvsig.fmap.dal.feature.Feature;
55
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
56
import org.gvsig.fmap.dal.feature.FeatureQuery;
57
import org.gvsig.fmap.dal.feature.FeatureStore;
58
import org.gvsig.fmap.dal.feature.FeatureType;
59
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
60
import org.gvsig.fmap.dal.feature.spi.FeatureData;
61
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
62
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
63
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
64
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
65
import org.gvsig.fmap.dal.resource.exception.ResourceBeginException;
66
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
67
import org.gvsig.fmap.dal.store.jdbc.JDBCExecuteSQLException;
68
import org.gvsig.fmap.dal.store.jdbc.JDBCSQLException;
69
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreProvider;
70
import org.gvsig.fmap.geom.Geometry;
71
import org.gvsig.fmap.geom.operation.towkb.ToWKB;
72
import org.gvsig.fmap.geom.primitive.Envelope;
73
import org.gvsig.tools.ToolsLocator;
74
import org.gvsig.tools.dynobject.DelegatedDynObject;
75
import org.gvsig.tools.dynobject.DynClass;
76
import org.gvsig.tools.dynobject.DynObjectManager;
77
import org.gvsig.tools.exception.BaseException;
78
import org.gvsig.tools.persistence.PersistenceException;
79
import org.gvsig.tools.persistence.PersistentState;
80
import org.slf4j.Logger;
81
import org.slf4j.LoggerFactory;
82

    
83
public class PostgreSQLStoreProvider extends JDBCStoreProvider implements
84
                PostgreSQLHelperUser {
85

    
86
        final static private Logger logger = LoggerFactory
87
                        .getLogger(PostgreSQLStoreProvider.class);
88

    
89
        public static String NAME = "PostgreSQLStore";
90
        public static String DESCRIPTION = "PostgreSQL source";
91
        private static final String DYNCLASS_NAME = "PostgreSQLStore";
92
        private static DynClass DYNCLASS = null;
93

    
94

    
95
        protected PostgreSQLStoreParameters params;
96
        protected PostgreSQLHelper helper;
97
        protected boolean directSQLMode;
98

    
99
        private Long totalCount = null;
100

    
101
        protected static void registerDynClass() {
102
                DynObjectManager dynman = ToolsLocator.getDynObjectManager();
103
                DynClass dynClass;
104
                if (DYNCLASS == null) {
105
                        dynClass = dynman.add(DYNCLASS_NAME, DESCRIPTION);
106

    
107
                        dynClass.extend(dynman.get(FeatureStore.DYNCLASS_NAME));
108
                        DYNCLASS = dynClass;
109
                }
110
        }
111

    
112
        public PostgreSQLStoreProvider() {
113
                super();
114
        }
115

    
116
        public PostgreSQLStoreProvider(PostgreSQLStoreParameters params)
117
                        throws InitializeException {
118
                super();
119
                this.init(params);
120
        }
121

    
122
        protected void init(PostgreSQLStoreParameters params)
123
                        throws InitializeException {
124
                this.params = params;
125
                this.dynObject = (DelegatedDynObject) ToolsLocator
126
                                .getDynObjectManager().createDynObject(DYNCLASS);
127

    
128
                this.dynObject.setDynValue("DefaultSRS", null);
129
                this.dynObject.setDynValue("Envelope", null);
130

    
131
                helper = new PostgreSQLHelper(this, params);
132

    
133
                if (params.getSQL() != null && (params.getSQL()).trim().length() > 0) {
134
                        directSQLMode = true;
135
                }
136
        }
137

    
138
        protected String compoundCountSelect(String filter) {
139
                if (this.directSQLMode) {
140
                        return null;
141
                }
142
                // Select
143
                StringBuilder sql = new StringBuilder();
144
                sql.append("Select count(");
145
                String[] pkFields = params.getPkFields();
146
                if (pkFields != null && pkFields.length == 1) {
147
                        sql.append(helper.escapeFieldName(pkFields[0]));
148
                } else {
149
                        sql.append('*');
150

    
151
                }
152
                sql.append(") ");
153

    
154
                sql.append("from ");
155

    
156
                sql.append(params.tableID());
157
                sql.append(' ');
158

    
159
                appendWhere(sql, filter);
160

    
161
                return sql.toString();
162
        }
163

    
164
        private void appendWhere(StringBuilder sql, String filter) {
165
                filter = fixFilter(filter);
166
                String initialFilter = params.getInitialFilter();
167
                if ((initialFilter != null && initialFilter.length() != 0)
168
                                || (filter != null && filter.length() != 0)) {
169
                        sql.append("where (");
170

    
171
                        if (initialFilter != null && initialFilter.length() != 0
172
                                        && filter != null && filter.length() != 0) {
173
                                // initialFilter + filter
174
                                sql.append('(');
175
                                sql.append(initialFilter);
176
                                sql.append(") and (");
177
                                sql.append(filter);
178
                                sql.append(')');
179
                        } else if (initialFilter != null && initialFilter.length() != 0) {
180
                                // initialFilter only
181
                                sql.append(initialFilter);
182
                        } else {
183
                                // filter only
184
                                sql.append(filter);
185
                        }
186
                        sql.append(") ");
187
                }
188

    
189
        }
190

    
191
        private String fixFilter(String filter) {
192
                if (filter == null) {
193
                        return null;
194
                }
195

    
196
                // Transform SRS to code
197
                // GeomFromText\s*\(\s*'[^']*'\s*,\s*('[^']*')\s*\)
198
                Pattern pattern = Pattern
199
                                .compile("GeomFromText\\s*\\(\\s*'[^']*'\\s*,\\s*'([^']*)'\\s*\\)");
200
                Matcher matcher = pattern.matcher(filter);
201
                StringBuilder strb = new StringBuilder();
202
                int pos = 0;
203
                String srsCode;
204
                while (matcher.find(pos)) {
205
                        strb.append(filter.substring(pos, matcher.start(1)));
206
                        srsCode = matcher.group(1).trim();
207
                        if (srsCode.startsWith("'")) {
208
                                srsCode = srsCode.substring(1);
209
                        }
210
                        if (srsCode.endsWith("'")) {
211
                                srsCode = srsCode.substring(0, srsCode.length() - 1);
212
                        }
213
                        strb.append(helper.getPostgisSRID(srsCode));
214
                        strb.append(filter.substring(matcher.end(1), matcher.end()));
215
                        pos = matcher.end();
216

    
217
                }
218
                strb.append(filter.substring(pos));
219

    
220
                return strb.toString();
221
        }
222

    
223
        public String compoundSelect(FeatureType type,
224
                        String filter,
225
                        String order,
226
                        long limit, long offset) throws DataException {
227
                StringBuilder sql = new StringBuilder();
228
                if (directSQLMode) {
229
                        if (filter != null || order != null) {
230
                                // FIXME Exception
231
                                throw new UnsupportedOperationException();
232
                        }
233
                        sql.append(params.getSQL());
234
                        sql.append(' ');
235
                } else {
236
                        FeatureAttributeDescriptor[] fields = type
237
                                        .getAttributeDescriptors();
238

    
239
                        // Select
240
                        sql.append("Select ");
241
                        for (int i = 0; i < fields.length - 1; i++) {
242
                                sql.append(helper.getSqlFieldName(fields[i]));
243
                                sql.append(", ");
244
                        }
245
                        sql.append(helper.getSqlFieldName(fields[fields.length - 1]));
246
                        sql.append(' ');
247

    
248

    
249
                        FeatureAttributeDescriptor[] pkFields = store.getFeatureType(type.getId()).getPrimaryKey();
250
                        if (pkFields != null && pkFields.length > 0) {
251
                                // checks for pk fields are in select
252
                                boolean toAdd;
253
                                for (int i = 0; i < pkFields.length; i++) {
254
                                        toAdd = true;
255
                                        for (int j = 0; j < fields.length; j++) {
256
                                                if (pkFields[i].getName().equals(fields[j].getName())) {
257
                                                        toAdd = false;
258
                                                        break;
259
                                                }
260
                                                if (toAdd) {
261
                                                        sql.append(", ");
262
                                                        sql.append(helper.getSqlFieldName(pkFields[i]));
263
                                                }
264
                                        }
265
                                }
266
                                sql.append(' ');
267
                        }
268

    
269

    
270
                        // table
271
                        sql.append("from ");
272
                        sql.append(params.tableID());
273
                        sql.append(' ');
274

    
275
                        // Where
276
                        appendWhere(sql, filter);
277

    
278
                        // Order
279
                        if ((params.getInitialOrder() != null && params
280
                                        .getInitialOrder().length() != 0)
281
                                        || (order != null && order.length() != 0)) {
282
                                sql.append("order by ");
283

    
284
                                if (order != null && order.length() != 0) {
285
                                        // order
286
                                        sql.append(order);
287
                                } else {
288
                                        // initial order
289
                                        sql.append(params.getInitialOrder());
290
                                }
291
                                sql.append(' ');
292
                        }
293
                }
294
                // limit
295
                if (limit >= 1) {
296
                        sql.append("limit ");
297
                        sql.append(limit);
298
                        sql.append(' ');
299
                }
300

    
301
                // offset
302
                if (offset >= 1) {
303
                        sql.append("offset ");
304
                        sql.append(offset);
305
                        sql.append(' ');
306
                }
307

    
308

    
309
                return sql.toString();
310
        }
311

    
312
        public FeatureStoreProvider initialize(FeatureStoreProviderServices store)
313
                        throws InitializeException {
314
                super.initialize(store);
315
                this.initFeatureType();
316
                return this;
317
        }
318

    
319

    
320
        protected void initFeatureType() throws InitializeException {
321

    
322
                EditableFeatureType edFType = null;
323
                try {
324
                        edFType = this.store.createFeatureType();
325

    
326
                        helper.loadFeatureType(edFType, params);
327

    
328
                } catch (DataException e) {
329
                        throw new InitializeException(this.getName(), e);
330
                }
331

    
332
                FeatureType defaultType = edFType.getNotEditableCopy();
333
                List types = new ArrayList(1);
334
                types.add(defaultType);
335
                this.store.setFeatureTypes(types, defaultType);
336
                try {
337
                        loadMetadata();
338
                } catch (DataException e) {
339
                        throw new InitializeException(e);
340
                }
341
        }
342

    
343
        public Object createNewOID() {
344
                return null;
345
        }
346

    
347

    
348
        public FeatureData getFeatureDataByReference(
349
                        FeatureReferenceProviderServices reference) throws DataException {
350
                return getFeatureDataByReference(reference, store
351
                                .getDefaultFeatureType());
352
        }
353

    
354
        public FeatureData getFeatureDataByReference(
355
                        FeatureReferenceProviderServices reference, FeatureType featureType)
356
                        throws DataException {
357
                open();
358
                resourceBegin();
359
                try {
360
                        StringBuilder filter = new StringBuilder();
361
                        FeatureAttributeDescriptor[] pk = store.getFeatureType(
362
                                        featureType.getId()).getPrimaryKey();
363

    
364
                        List values = new ArrayList();
365

    
366
                        int i;
367
                        for (i = 0; i < pk.length - 1; i++) {
368
                                values.add(helper.dalValueToJDBC(pk[i], reference
369
                                                .getKeyValue(pk[i].getName())));
370
                                filter.append(helper.getSqlFieldName(pk[i]));
371
                                filter.append(" = ? AND ");
372
                        }
373
                        values.add(helper.dalValueToJDBC(pk[i], reference.getKeyValue(pk[i]
374
                                        .getName())));
375
                        filter.append(helper.getSqlFieldName(pk[i]));
376
                        filter.append(" = ? ");
377

    
378

    
379
                        String sql = compoundSelect(featureType, filter.toString(), null,
380
                                        1, 0);
381

    
382
                        FeatureData data;
383
                        int rsId = createResultSet(sql, values.toArray());
384
                        try{
385
                                if (!resulsetNext(rsId)) {
386
                                        // FIXME Exception
387
                                        throw new RuntimeException("Reference Not found");
388
                                }
389
                                data = createFeatureData(featureType);
390
                                loadFeatureData(data, rsId);
391
                        } finally {
392
                                closeResulset(rsId);
393
                        }
394

    
395
                        return data;
396

    
397
                } finally {
398
                        resourceEnd();
399
                }
400

    
401
        }
402

    
403
        public int getFeatureReferenceOIDType() {
404
                return DataTypes.UNKNOWN;
405
        }
406

    
407
        public String getName() {
408
                return NAME;
409
        }
410

    
411
        public Iterator getChilds() {
412
                return null;
413
        }
414

    
415
        public void open() throws OpenException {
416
                helper.open();
417
        }
418

    
419

    
420
        public boolean allowWrite() {
421
                return false;
422
        }
423

    
424
        public void close() throws CloseException {
425
                helper.close();
426
        }
427

    
428
        public Object getSourceId() {
429
                return this.params.getSourceId();
430
        }
431

    
432
        protected ResultSet createNewResultSet(String sql, Object[] values)
433
                        throws DataException {
434
                this.open();
435
                Connection conn =null;
436
                PreparedStatement st=null;
437
                ResultSet rs=null;
438
                this.resourceBegin();
439
                try{
440
                        conn = this.helper.getConnection();
441
                        st = conn.prepareStatement(sql);
442

    
443
                        if (values != null) {
444
                                Object value;
445
                                for (int i = 0; i < values.length; i++) {
446
                                        value = values[i];
447
                                        if (value instanceof Geometry) {
448
                                                byte[] bytes;
449
                                                try {
450
                                                        bytes = (byte[]) ((Geometry) value)
451
                                                                        .invokeOperation(ToWKB.CODE, null);
452
                                                } catch (BaseException e) {
453
                                                        // FIXME
454
                                                        throw new InvalidParameterException();
455
                                                }
456
                                                st.setBytes(i + 1, bytes);
457
                                        }
458
                                        st.setObject(i + 1, value);
459
                                }
460

    
461
                        }
462

    
463
                        try {
464
                                rs = st.executeQuery();
465
                        } catch (SQLException e1){
466
                                try {st.close();  } catch (Exception e2) {        };
467
                                try {conn.close();} catch (Exception e2) {        };
468
                                throw new JDBCExecuteSQLException(sql,e1);
469
                        }
470
                        rs.setFetchSize(5000); // TODO add to params?
471
                        return rs;
472
                } catch (SQLException e) {
473
                        // TODO throw exception ???
474
                        try {rs.close();  } catch (Exception e1) {        };
475
                        try {st.close();  } catch (Exception e1) {        };
476
                        try {conn.close();} catch (Exception e1) {        };
477
                        throw new JDBCSQLException(e);
478
                }finally{
479
                        this.resourceEnd();
480
                }
481
        }
482

    
483
        protected long getCount(String filter) throws DataException {
484
                this.open();
485
                if (filter == null && totalCount != null) {
486
                        return totalCount.longValue();
487
                }
488
                long count = 0;
489
                String sql = compoundCountSelect(filter);
490
                resourceBegin();
491
                try {
492
                        ResultSet rs = createNewResultSet(sql, null);
493
                        try {
494
                                if (rs.next()) {
495
                                        count = rs.getLong(1);
496
                                }
497
                        } catch (SQLException e) {
498
                                throw new JDBCSQLException(e);
499
                        } finally {
500
                                closeResulset(rs);
501
                        }
502
                } finally {
503
                        resourceEnd();
504
                }
505
                if (filter == null) {
506
                        totalCount = new Long(count);
507
                }
508
                return count;
509
        }
510

    
511
        protected void resourceBegin() throws ResourceBeginException {
512
                this.helper.begin();
513

    
514
        }
515

    
516
        protected void resourceEnd() {
517
                this.helper.end();
518
        }
519

    
520
        protected boolean closeResource(ResourceProvider resource) {
521
                try {
522
                        this.helper.close();
523
                } catch (CloseException e) {
524
                        logger.error("Exception in close Request", e);
525
                }
526
                return !this.helper.isOpen();
527
        }
528

    
529

    
530
        protected void loadFeatureDataValue(FeatureData data, ResultSet rs,
531
                        FeatureAttributeDescriptor attr) throws DataException {
532
                if (attr.getDataType() == DataTypes.GEOMETRY) {
533
                        byte[] buffer;
534
                        try {
535
                                buffer = rs.getBytes(attr.getIndex() + 1);
536
                                if (buffer == null) {
537
                                        data.set(attr.getIndex(), null);
538
                                } else {
539
                                        data.set(attr.getIndex(), this.helper
540
                                                        .getGeometry(buffer));
541
                                }
542
                        } catch (SQLException e) {
543
                                throw new JDBCSQLException(e);
544
                        } catch (BaseException e) {
545
                                throw new ReadException(getName(), e);
546
                        }
547

    
548
                } else {
549
                        super.loadFeatureDataValue(data, rs, attr);
550
                }
551
        }
552

    
553
        public FeatureSetProvider createSet(FeatureQuery query,
554
                        FeatureType featureType) throws DataException {
555

    
556
                return new PostgreSQLSetProvider(this, query, featureType);
557
        }
558

    
559
        public void dispose() throws CloseException {
560
                this.close();
561
                this.helper.dispose();
562
                super.dispose();
563
        }
564

    
565

    
566
        public DataServerExplorer getExplorer() throws ReadException {
567
                DataManager manager = DALLocator.getDataManager();
568
                PostgreSQLServerExplorerParameters exParams;
569
                try {
570
                        exParams = (PostgreSQLServerExplorerParameters) manager
571
                                        .createServerExplorerParameters(PostgreSQLServerExplorer.NAME);
572
                        exParams.setHost(params.getHost());
573
                        exParams.setPort(params.getPort());
574
                        exParams.setDBName(params.getDBName());
575
                        exParams.setUser(params.getUser());
576
                        exParams.setPassword(params.getPassword());
577
                        exParams.setCatalog(params.getCatalog());
578
                        exParams.setSchema(params.getSchema());
579
                        exParams.setJDBCDriverClassName(params.getJDBCDriverClassName());
580
                        exParams.setUseSSL(params.getUseSSL());
581

    
582
                        return manager.createServerExplorer(exParams);
583
                } catch (DataException e) {
584
                        throw new ReadException(this.getName(), e);
585
                } catch (ValidateDataParametersException e) {
586
                        // TODO Auto-generated catch block
587
                        throw new ReadException(this.getName(), e);
588
                }
589
        }
590

    
591
        private void loadMetadata() throws DataException {
592
                IProjection srs = params.getSRS();
593

    
594
                if (srs == null) {
595
                        srs = store.getDefaultFeatureType().getDefaultSRS();
596
                }
597

    
598

    
599
                this.dynObject.setDynValue("DefaultSRS", srs);
600

    
601
                String defGeomName = this.store.getDefaultFeatureType()
602
                                .getDefaultGeometryAttributeName();
603
                Envelope env = null;
604
                if (defGeomName != null && defGeomName.length() > 0) {
605
                        env = this.helper
606
                                        .getFullEnvelopeOfField(this.params,
607
                                        defGeomName,
608
                                        this.params.getWorkingArea());
609

    
610
                }
611
                this.dynObject.setDynValue("Envelope", env);
612

    
613
        }
614

    
615
        private void clearMetadata() {
616
                this.dynObject.setDynValue("DefaultSRS", null);
617
                this.dynObject.setDynValue("Envelope", null);
618
        }
619

    
620
        public void closeDone() throws DataException {
621
                clearMetadata();
622

    
623
        }
624

    
625
        public void opendDone() throws DataException {
626
                // Nothing to do
627
        }
628

    
629
        public Envelope getEnvelope() throws DataException {
630
                this.open();
631
                return (Envelope) this.dynObject.getDynValue("Envelope");
632
        }
633

    
634
        public void resourceChanged(ResourceProvider resource) {
635
                this.store.notifyChange(DataStoreNotification.RESOURCE_CHANGED,
636
                                resource);
637
        }
638

    
639
        public boolean canWriteGeometry(int geometryType) throws DataException {
640
                return false;
641
        }
642

    
643
        public boolean allowAutomaticValues() {
644
                return true;
645
        }
646

    
647
        public void performEditing(Iterator deleteds, Iterator inserteds,
648
                        Iterator updateds, Iterator originalFeatureTypesUpdated)
649
                        throws PerformEditingException {
650
                // FIXME exception
651
                throw new UnsupportedOperationException();
652

    
653
        }
654

    
655
        protected PostgreSQLHelper getHelper() {
656
                return helper;
657
        }
658

    
659
        // ************************************************************************************//
660

    
661

    
662
        // ************************************************************************************//
663

    
664

    
665
        public boolean supportsAppendMode() {
666
                // TODO Auto-generated method stub
667
                return false;
668
        }
669

    
670
        public PersistentState getState() throws PersistenceException {
671
                // TODO Auto-generated method stub
672
                return null;
673
        }
674

    
675
        public void loadState(PersistentState state) throws PersistenceException {
676
                // TODO Auto-generated method stub
677

    
678
        }
679

    
680
        public void setState(PersistentState state) throws PersistenceException {
681
                // TODO Auto-generated method stub
682

    
683
        }
684

    
685

    
686
        public void endAppend() throws DataException {
687
                // TODO Auto-generated method stub
688

    
689
        }
690

    
691

    
692
        public void append(Feature feature) throws DataException {
693
                // TODO Auto-generated method stub
694

    
695
        }
696

    
697
        public void beginAppend() throws DataException {
698
                // TODO Auto-generated method stub
699

    
700
        }
701

    
702
        public long getFeatureCount() throws DataException {
703
                return getCount(null);
704
        }
705

    
706
        /* (non-Javadoc)
707
         * @see org.gvsig.tools.persistence.Persistent#saveToState(org.gvsig.tools.persistence.PersistentState)
708
         */
709
        public void saveToState(PersistentState state) throws PersistenceException {
710
                // TODO Auto-generated method stub
711

    
712
        }
713

    
714
}