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 / jdbc / JDBCStoreProviderWriter.java @ 44871

History | View | Annotate | Download (22 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
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
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.store.jdbc;
25

    
26
import java.sql.Connection;
27
import java.sql.PreparedStatement;
28
import java.sql.SQLException;
29
import java.sql.Statement;
30
import java.util.ArrayList;
31
import java.util.Arrays;
32
import java.util.Iterator;
33
import java.util.List;
34

    
35
import org.gvsig.fmap.dal.exception.DataException;
36
import org.gvsig.fmap.dal.exception.InitializeException;
37
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
38
import org.gvsig.fmap.dal.feature.FeatureRules;
39
import org.gvsig.fmap.dal.feature.FeatureType;
40
import org.gvsig.fmap.dal.feature.FeatureType.FeatureTypeChanged;
41
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
42
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
43
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
44
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
45
import org.gvsig.fmap.dal.store.db.FeatureTypeHelper;
46
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecutePreparedSQLException;
47
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
48
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCPreparingSQLException;
49
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
50
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCUpdateWithoutChangesException;
51
import org.gvsig.tools.dynobject.DynObject;
52
import org.slf4j.Logger;
53
import org.slf4j.LoggerFactory;
54

    
55
/**
56
 * @author jmvivo
57
 *
58
 */
59
public class JDBCStoreProviderWriter extends JDBCStoreProvider {
60

    
61
        final static private Logger logger = LoggerFactory
62
                        .getLogger(JDBCStoreProviderWriter.class);
63

    
64
        protected Appender appender;
65

    
66
        public JDBCStoreProviderWriter(JDBCStoreParameters params,
67
                        DataStoreProviderServices storeServices)
68
                        throws InitializeException {
69
                super(params, storeServices);
70
                this.appender = this.createAppender();
71
        }
72

    
73
        protected JDBCStoreProviderWriter(JDBCStoreParameters params,
74
                        DataStoreProviderServices storeServices, DynObject metadata)
75
                        throws InitializeException {
76
                super(params, storeServices, metadata);
77
                this.appender = this.createAppender();
78
        }
79

    
80
        protected Appender createAppender() {
81
            return new JDBCAppender(this);
82
        }
83

    
84
        public boolean supportsAppendMode() {
85
            return true;
86
        }
87

    
88
        public void endAppend() throws DataException {
89
            this.appender.end();
90
        }
91

    
92
        public void beginAppend() throws DataException {
93
            this.appender.begin();
94
        }
95

    
96
        public void append(final FeatureProvider featureProvider) throws DataException {
97
            this.appender.append(featureProvider);
98
        }
99

    
100
        protected void addToListFeatureValues(FeatureProvider featureProvider,
101
                        FeatureAttributeDescriptor attrOfList,
102
                        FeatureAttributeDescriptor attr, List<Object> values) throws DataException {
103
                if (attr == null) {
104
                        if (attrOfList.isPrimaryKey()) {
105
                                throw new RuntimeException("pk attribute '"
106
                                                + attrOfList.getName() + "' not found in feature");
107
                        }
108
                        values.add(helper
109
                                        .dalValueToJDBC(attr, attrOfList.getDefaultValue()));
110
                } else {
111
                        values.add(helper.dalValueToJDBC(attr, featureProvider.get(attr
112
                                        .getIndex())));
113
                }
114

    
115
        }
116

    
117
        protected void addToListFeatureValues(FeatureProvider featureProvider,
118
                        List<FeatureAttributeDescriptor> attributes, List<Object> values) throws DataException {
119
                FeatureAttributeDescriptor attr, attrOfList;
120
                FeatureType fType = featureProvider.getType();
121
                for (int i = 0; i < attributes.size(); i++) {
122
                        attrOfList = (FeatureAttributeDescriptor) attributes.get(i);
123
                        attr = fType.getAttributeDescriptor(attrOfList.getName());
124
                        addToListFeatureValues(featureProvider, attrOfList, attr, values);
125
                }
126
        }
127

    
128
        protected void appendToSQLPreparedPkWhereClause(StringBuilder sql,
129
                        List<FeatureAttributeDescriptor> pkAttributes) {
130
                sql.append(" Where ");
131
                FeatureAttributeDescriptor attr;
132
                for (int i = 0; i < pkAttributes.size() - 1; i++) {
133
                        attr = (FeatureAttributeDescriptor) pkAttributes.get(i);
134
                        sql.append(helper.escapeFieldName(attr.getName()));
135
                        sql.append(" = ? AND ");
136
                }
137
                attr = (FeatureAttributeDescriptor) pkAttributes.get(pkAttributes
138
                                .size() - 1);
139
                sql.append(helper.escapeFieldName(attr.getName()));
140
                sql.append(" = ? ");
141
        }
142

    
143
        protected void executeRemovePreparedStatement(Connection conn, String sql,
144
                        List<FeatureAttributeDescriptor> attributes, Iterator<FeatureReferenceProviderServices> featureReferences) throws DataException {
145
                                PreparedStatement st;
146
                                try {
147
                                        st = conn.prepareStatement(sql);
148
                                } catch (SQLException e) {
149
                                        throw new JDBCPreparingSQLException(sql, e);
150
                                }
151
                                try {
152
                                        List<Object> values = new ArrayList<Object>();
153
                                        FeatureReferenceProviderServices featureRef;
154
//                                        FeatureType featureType;
155
                                        while (featureReferences.hasNext()) {
156
                                                st.clearParameters();
157
                                                featureRef = featureReferences.next();
158
                                                values.clear();
159
//                                                featureType = this.getFeatureStore()
160
//                                                        .getFeatureType(featureRef.getFeatureTypeId());
161

    
162
                                                Iterator<FeatureAttributeDescriptor> iter = attributes.iterator();
163
                                                FeatureAttributeDescriptor attr;
164
                                                while (iter.hasNext()) {
165
                                                        attr =  iter.next();
166
                                                        values.add( helper.dalValueToJDBC(attr, featureRef
167
                                                                        .getKeyValue(attr.getName())));
168
                                                }
169

    
170
                                                for (int i = 0; i < values.size(); i++) {
171
                                                        st.setObject(i + 1, values.get(i));
172
                                                }
173
                                                try {
174
                                                        int nAffected =JDBCHelper.executeUpdate(st);
175
                                                        if (nAffected == 0) {
176
                                                                throw new JDBCUpdateWithoutChangesException(sql, values);
177
                                                        }
178
                                                        if (nAffected > 1){
179
                                                                logger.warn("Remove statement affectst to {} rows: {}",
180
                                                                                nAffected, sql);
181
                                                        }
182

    
183
                                                } catch (SQLException e) {
184
                                                        throw new JDBCExecutePreparedSQLException(sql, values, e);
185
                                                }
186

    
187
                                        }
188
                                } catch (SQLException e) {
189
                                        throw new JDBCSQLException(e);
190
                                } finally {
191
                                        try {st.close();} catch (SQLException e) {        };
192
                                }
193

    
194
                        }
195

    
196
        protected void executeUpdatePreparedStatement(Connection conn, String sql,
197
                        List<FeatureAttributeDescriptor> attributes, Iterator<FeatureProvider> featureProviders) throws DataException {
198
                                PreparedStatement st;
199
                                try {
200
                                        st = conn.prepareStatement(sql);
201
                                } catch (SQLException e) {
202
                                        throw new JDBCPreparingSQLException(sql, e);
203
                                }
204
                                try {
205
                                        List<Object> values = new ArrayList<Object>();
206
                                        FeatureProvider featureProvider;
207
                                        while (featureProviders.hasNext()) {
208
                                                st.clearParameters();
209
                                                featureProvider = (FeatureProvider) featureProviders.next();
210
                                                values.clear();
211
                                                addToListFeatureValues(featureProvider, attributes, values);
212
                                                for (int i = 0; i < values.size(); i++) {
213
                                                        st.setObject(i + 1, values.get(i));
214
                                                }
215
                                                try {
216
                                                        if ( JDBCHelper.executeUpdate(st) == 0) {
217
                                                                throw new JDBCUpdateWithoutChangesException(sql, values);
218
                                                        }
219
                                                } catch (SQLException e) {
220
                                                        throw new JDBCExecutePreparedSQLException(sql, values, e);
221
                                                }
222

    
223
                                        }
224
                                } catch (SQLException e) {
225
                                        throw new JDBCSQLException(e);
226
                                } finally {
227
                                        try {st.close();} catch (SQLException e) {        };
228
                                }
229

    
230
                        }
231

    
232
        protected void performDeletes(Connection conn, Iterator<FeatureReferenceProviderServices> deleteds, List<FeatureAttributeDescriptor> pkAttributes)
233
                        throws DataException {
234

    
235
                                if (pkAttributes.size() < 0) {
236
                                        throw new RuntimeException("Operation requires missing pk");
237
                                }
238

    
239
                                // ************ Prepare SQL ****************
240
                                StringBuilder sqlb = new StringBuilder();
241
                                sqlb.append("Delete from ");
242
                                sqlb.append(getJDBCParameters().tableID());
243
                                appendToSQLPreparedPkWhereClause(sqlb, pkAttributes);
244
                                String sql = sqlb.toString();
245
                                // ************ Prepare SQL (end) ****************
246

    
247
                                executeRemovePreparedStatement(conn, sql, pkAttributes, deleteds);
248
                        }
249

    
250
        protected String getSqlStatementAddField(FeatureAttributeDescriptor attr,
251
                        List<String> additionalStatement) throws DataException {
252
                StringBuilder strb = new StringBuilder();
253
                strb.append("ADD ");
254
                strb.append(this.helper.getSqlFieldDescription(attr));
255
                return strb.toString();
256
        }
257

    
258
        protected String getSqlStatementDropField(FeatureAttributeDescriptor attr,List<String> additionalStatement) {
259
                // DROP [ COLUMN ] column
260
                return " DROP COLUMN "
261
                                + this.helper.escapeFieldName(attr.getName());
262

    
263
        }
264

    
265
        protected List<String> getSqlStatementAlterField(
266
                        FeatureAttributeDescriptor attrOrg,
267
                        FeatureAttributeDescriptor attrTrg, List<String> additionalStatement)
268
                        throws DataException {
269
                //
270
                List<String> actions = new ArrayList<String>();
271
                StringBuilder strb;
272
                if (attrOrg.getDataType() != attrTrg.getDataType()) {
273
                        // ALTER COLUMN {col} TYPE {type} character varying(35)
274
                        strb = new StringBuilder();
275
                        strb.append("ALTER COLUMN ");
276
                        strb.append(helper.escapeFieldName(attrTrg.getName()));
277
                        strb.append(" ");
278
                        strb.append(helper.getSqlColumnTypeDescription(attrTrg));
279

    
280
                        actions.add(strb.toString());
281
                }
282

    
283
                if (attrOrg.allowNull() != attrTrg.allowNull()) {
284
                        // ALTER [ COLUMN ] column { SET | DROP } NOT NULL
285

    
286
                        strb = new StringBuilder();
287
                        strb.append("ALTER COLUMN ");
288
                        strb.append(helper.escapeFieldName(attrTrg.getName()));
289
                        strb.append(' ');
290
                        if (attrTrg.allowNull()) {
291
                                strb.append("SET ");
292
                        } else {
293
                                strb.append("DROP ");
294
                        }
295
                        strb.append("NOT NULL");
296
                        actions.add(strb.toString());
297
                }
298

    
299
                if (attrOrg.getDefaultValue() != attrTrg.getDefaultValue()) {
300
                        if (attrTrg.getDefaultValue() == null) {
301
                                // ALTER [ COLUMN ] column DROP DEFAULT
302

    
303
                                strb = new StringBuilder();
304
                                strb.append("ALTER COLUMN ");
305
                                strb.append(helper.escapeFieldName(attrTrg.getName()));
306
                                strb.append(" DROP DEFAULT");
307
                                actions.add(strb.toString());
308
                        } else if (!attrTrg.getDefaultValue().equals(
309
                                        attrOrg.getDefaultValue())) {
310
                                // ALTER [ COLUMN ] column DROP DEFAULT
311

    
312
                                strb = new StringBuilder();
313
                                strb.append("ALTER COLUMN ");
314
                                strb.append(helper.escapeFieldName(attrTrg.getName()));
315
                                strb.append(" SET DEFAULT");
316
                                strb.append(helper.dalValueToJDBC(attrTrg, attrTrg
317
                                                .getDefaultValue()));
318
                                actions.add(strb.toString());
319
                        }
320
                }
321

    
322
                return actions;
323
        }
324

    
325
        protected void performUpdateTable(Connection conn, FeatureType original,
326
                        FeatureType target) throws DataException {
327

    
328
                /*
329
                 *
330
                 * ALTER TABLE [ ONLY ] name [ * ] action [, ... ]
331
                 */
332

    
333
                List<String> toDrop = new ArrayList<String>();
334
                List<String> toAdd = new ArrayList<String>();
335
                List<String> toAlter = new ArrayList<String>();
336

    
337
                List<String> additionalStatement = new ArrayList<String>();
338

    
339
                FeatureAttributeDescriptor attrOrg;
340
                FeatureAttributeDescriptor attrTrg;
341
                Iterator<FeatureAttributeDescriptor> attrs = FeatureTypeHelper.iterator(original);
342
                while (attrs.hasNext()) {
343
                        attrOrg = (FeatureAttributeDescriptor) attrs.next();
344
                        attrTrg = target.getAttributeDescriptor(attrOrg.getName());
345
                        if (attrTrg == null) {
346
                                toDrop.add(getSqlStatementDropField(attrOrg,
347
                                                additionalStatement));
348
                        } else {
349
                                toAlter.addAll(getSqlStatementAlterField(attrOrg, attrTrg,additionalStatement));
350
                        }
351

    
352
                }
353
                attrs = FeatureTypeHelper.iterator(target);
354
                while (attrs.hasNext()) {
355
                        attrTrg = (FeatureAttributeDescriptor) attrs.next();
356
                        if (original.getAttributeDescriptor(attrTrg.getName()) == null) {
357
                                toAdd.add(getSqlStatementAddField(attrTrg,
358
                                                                additionalStatement));
359
                        }
360
                }
361

    
362
                StringBuilder sqlb = new StringBuilder();
363

    
364
                sqlb.append("ALTER TABLE ");
365
                sqlb.append(getJDBCParameters().tableID());
366
                sqlb.append(' ');
367

    
368
                List<String> actions = new ArrayList<String>();
369
                actions.addAll(toDrop);
370
                actions.addAll(toAlter);
371
                actions.addAll(toAdd);
372

    
373
                Iterator<String> it = actions.iterator();
374
                while (it.hasNext()) {
375
                        if (it.next() == null) {
376
                                it.remove();
377
                        }
378
                }
379

    
380
                it = additionalStatement.iterator();
381
                while (it.hasNext()) {
382
                        if (it.next() == null) {
383
                                it.remove();
384
                        }
385
                }
386

    
387
                if (actions.size() < 1) {
388
                        return;
389
                }
390

    
391
                helper.stringJoin(actions, ", ", sqlb);
392

    
393
                String sql = sqlb.toString();
394

    
395
                Statement st = null;
396

    
397
                try {
398
                        st = conn.createStatement();
399
                } catch (SQLException e1) {
400
                        throw new JDBCSQLException(e1);
401
                }
402
                try {
403
                        JDBCHelper.execute(st, sql);
404
                        Iterator<String> iter = additionalStatement.iterator();
405
                        while (iter.hasNext()) {
406
                                sql = (String) iter.next();
407
                                JDBCHelper.execute(st, sql);
408
                        }
409
                } catch (SQLException e1) {
410
                        throw new JDBCExecuteSQLException(sql, e1);
411
                } finally {
412
                        try {
413
                                st.close();
414
                        } catch (Exception e) {
415
                                logger.error("Exception closing statement", e);
416
                        }
417
                        ;
418
                }
419

    
420
        }
421

    
422

    
423
        public void perfomInsert(Connection conn, PreparedStatement insertSt,
424
                        String sql, FeatureProvider feature, List<FeatureAttributeDescriptor> attributes)
425
                        throws DataException {
426

    
427
                try {
428
                        insertSt.clearParameters();
429
                        List<Object> values = new ArrayList<Object>();
430
                        addToListFeatureValues(feature, attributes, values);
431
//                        FeatureAttributeDescriptor attr;
432
                        int j = 1;
433
                        for (int i = 0; i < values.size(); i++) {
434
                                insertSt.setObject(j, values.get(i));
435
                                j++;
436
                        }
437
                        if (logger.isDebugEnabled()) {
438
                                logger.debug("Executing insert. sql={} value={}", new Object[] {
439
                                                sql, values });
440
                        }
441
                        try {
442
                                JDBCHelper.execute(insertSt, sql);
443
                        } catch (SQLException e) {
444
                                throw new JDBCExecutePreparedSQLException(sql, values, e);
445
                        }
446

    
447
                } catch (Exception e1) {
448
                        throw new JDBCExecuteSQLException(sql, e1);
449
                }
450
        }
451

    
452

    
453
        protected void prepareAttributeForUpdate(FeatureAttributeDescriptor attr,
454
                        List<String> values) {
455
                values.add(helper.escapeFieldName(attr.getName()) + " = ?");
456
        }
457

    
458
        protected void prepareAttributeForInsert(FeatureAttributeDescriptor attr,
459
                        List<String> fields, List<String> values) {
460

    
461
                fields.add(helper.escapeFieldName(attr.getName()));
462
                values.add("?");
463

    
464
        }
465

    
466

    
467
        protected void prepareSQLAndAttributeListForInsert(StringBuilder sqlb,
468
                        List<FeatureAttributeDescriptor> attributes) throws DataException {
469
                /*
470
                 * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
471
                 * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
472
                 * output_expression [ AS output_name ] [, ...] ]
473
                 */
474

    
475
                sqlb.append("INSERT INTO ");
476
                sqlb.append(getJDBCParameters().tableID());
477

    
478
                sqlb.append(" (");
479

    
480
                FeatureType type = this.getFeatureStore().getDefaultFeatureType();
481

    
482
                List<String> fields = new ArrayList<String>();
483
                List<String> values = new ArrayList<String>();
484

    
485
                Iterator<FeatureAttributeDescriptor> iter = FeatureTypeHelper.iterator(type);
486
                FeatureAttributeDescriptor attr;
487
                while (iter.hasNext()) {
488
                        attr = iter.next();
489
                        if (attr.isAutomatic() || attr.isReadOnly()) {
490
                                continue;
491
                        }
492
                        attributes.add(attr);
493
                        prepareAttributeForInsert(attr, fields, values);
494

    
495
                }
496
                if (attributes.size() < 1) {
497
                        throw new RuntimeException("no fields to set");
498
                }
499

    
500
                helper.stringJoin(fields, ", ", sqlb);
501

    
502
                sqlb.append(") VALUES (");
503
                helper.stringJoin(values, ", ", sqlb);
504

    
505
                sqlb.append(") ");
506

    
507
        }
508

    
509

    
510
        protected void performInserts(Connection conn, Iterator<FeatureProvider> inserteds)
511
                        throws DataException {
512

    
513
                StringBuilder sqlb = new StringBuilder();
514
                List<FeatureAttributeDescriptor> attrs = new ArrayList<FeatureAttributeDescriptor>();
515

    
516
                prepareSQLAndAttributeListForInsert(sqlb, attrs);
517

    
518
                String sql = sqlb.toString();
519
                PreparedStatement st;
520
                try {
521
                        st = conn.prepareStatement(sql);
522
                } catch (SQLException e) {
523
                        throw new JDBCPreparingSQLException(sql, e);
524
                }
525
                try {
526
                        while (inserteds.hasNext()) {
527
                                perfomInsert(conn, st, sql, inserteds.next(),
528
                                                attrs);
529
                        }
530
                } finally {
531
                        try {st.close();} catch (SQLException e) {logger.error("Error closing statement", e);};
532
                }
533
        }
534

    
535
        protected void performUpdates(Connection conn, Iterator<FeatureProvider> updateds,
536
                        List<FeatureAttributeDescriptor> pkAttributes) throws DataException {
537
                /*
538
                 * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
539
                 * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
540
                 * } [, ...] [ FROM fromlist ] [ WHERE condition ] [ RETURNING * |
541
                 * output_expression [ AS output_name ] [, ...] ]
542
                 */
543

    
544
                if (pkAttributes.size() < 0) {
545
                        throw new RuntimeException("Operation requires missing pk");
546
                }
547

    
548
                // ************ Prepare SQL ****************
549

    
550
                StringBuilder sqlb = new StringBuilder();
551
                sqlb.append("UPDATE ");
552
                sqlb.append(getJDBCParameters().tableID());
553

    
554
                sqlb.append(" SET ");
555

    
556
                List<String> values = new ArrayList<String>();
557

    
558
                FeatureType type = this.getFeatureStore().getDefaultFeatureType();
559

    
560
                Iterator<FeatureAttributeDescriptor> iter = FeatureTypeHelper.iterator(type);
561
                FeatureAttributeDescriptor attr;
562
                List<FeatureAttributeDescriptor> updateAttrs = new ArrayList<FeatureAttributeDescriptor>();
563
                while (iter.hasNext()) {
564
                        attr = iter.next();
565
                        if (attr.isPrimaryKey() || attr.isAutomatic() || attr.isReadOnly()) {
566
                                continue;
567
                        }
568
                        updateAttrs.add(attr);
569
                        prepareAttributeForUpdate(attr, values);
570

    
571
                }
572
                if (updateAttrs.size() < 1) {
573
                        throw new RuntimeException("no fields to set");
574
                }
575

    
576
                helper.stringJoin(values, ", ", sqlb);
577

    
578
                sqlb.append(' ');
579
                appendToSQLPreparedPkWhereClause(sqlb, pkAttributes);
580

    
581
                String sql = sqlb.toString();
582
                // ************ Prepare SQL (end) ****************
583

    
584
                updateAttrs.addAll(pkAttributes);
585

    
586
                executeUpdatePreparedStatement(conn, sql, updateAttrs, updateds);
587
        }
588

    
589

    
590

    
591
        protected TransactionalAction getPerformChangesAction(
592
                        final Iterator<FeatureReferenceProviderServices> deleteds, 
593
                        final Iterator<FeatureProvider> inserteds,
594
                        final Iterator<FeatureProvider> updateds, 
595
                        final Iterator<FeatureTypeChanged> featureTypesChanged) {
596

    
597
                TransactionalAction action = new TransactionalAction() {
598

    
599
                        public Object action(Connection conn) throws DataException {
600

    
601
                                if (featureTypesChanged.hasNext()) {
602

    
603
                                        FeatureTypeChanged item = featureTypesChanged.next();
604
                                        performUpdateTable(conn, item.getSource(), item.getTarget());
605
                                }
606

    
607
                                List<FeatureAttributeDescriptor> pkAttributes = null;
608
                                if (deleteds.hasNext() || updateds.hasNext()) {
609
                                        pkAttributes = Arrays.asList(getFeatureStore()
610
                                                        .getDefaultFeatureType()
611
                                                        .getPrimaryKey());
612
                                }
613

    
614
                                if (deleteds.hasNext()) {
615
                                        performDeletes(conn, deleteds, pkAttributes);
616
                                }
617

    
618
                                if (updateds.hasNext()) {
619
                                        performUpdates(conn, updateds, pkAttributes);
620
                                }
621

    
622
                                if (inserteds.hasNext()) {
623
                                        performInserts(conn, inserteds);
624
                                }
625

    
626
                                return null;
627
                        }
628

    
629
                        public boolean continueTransactionAllowed() {
630
                                return false;
631
                        }
632

    
633
                };
634

    
635
                return action;
636

    
637
        }
638

    
639
        @SuppressWarnings("unchecked")
640
        public void performChanges(Iterator deleteds, Iterator inserteds,
641
                        Iterator updateds, Iterator featureTypesChanged)
642
                        throws PerformEditingException {
643

    
644
                boolean countChanged = deleteds.hasNext() || inserteds.hasNext();
645

    
646
                try {
647
                        this.helper.doConnectionAction(getPerformChangesAction(deleteds,
648
                                        inserteds, updateds, featureTypesChanged));
649

    
650
                        /*
651
                         * Get rules before initializing feature type
652
                         */
653
                        FeatureRules old_rules = getFeatureStore().getDefaultFeatureType().getRules();
654
                        
655
                        /*
656
                         * This initialization loses the feature type rules
657
                         */
658
                        this.initFeatureType();
659
                        
660
                        /*
661
                         * Get new feature type, clear rules and add
662
                         * the ones saved previously
663
                         */
664
                        FeatureType ft = getFeatureStore().getDefaultFeatureType();
665
                        FeatureRules new_rules = ft.getRules();
666
                        new_rules.clear();
667
                        for (int i=0; i<old_rules.size(); i++) {
668
                            new_rules.add(old_rules.getRule(i));
669
                        }
670
                        // ===================================================
671
                        
672
                        if (countChanged) {
673
                                resetCount();
674
                        }
675

    
676
                } catch (Exception e) {
677
                        throw new PerformEditingException(this.getSourceId().toString(), e);
678
                }
679
        }
680

    
681

    
682
        public boolean allowWrite() {
683
                if (directSQLMode) {
684
                        return false;
685
                }
686
                
687
        FeatureType ft = null;
688
        try {
689
            ft = this.getFeatureStore().getDefaultFeatureType();
690
        } catch (DataException e) {
691
            logger.error("While getting default Feature Type", e);
692
        }
693
        
694
        String[] storePK = getPK(ft);
695
        JDBCHelper helper = this.getHelper();
696
        String[] dbPK = null;
697
        try {
698
            Connection conn = helper.getConnection();
699
            dbPK = helper.getPksFrom(conn, getJDBCParameters());
700
            conn.close();
701
        } catch (Exception exc) {
702
            logger.error("While getting PK from DB", exc);
703
            return false;
704
        }
705
        return sameStrings(storePK, dbPK);
706
        }
707

    
708
    private boolean sameStrings(String[] a, String[] b) {
709
        
710
        if (a==null || b==null || a.length!=b.length || a.length==0) {
711
            /*
712
             * Must not be empty
713
             */
714
            return false;
715
        }
716
        int len = a.length;
717
        boolean found = false;
718
        /*
719
         * Check same 
720
         */
721
        for (int ai=0; ai<len; ai++) {
722
            found = false;
723
            for (int bi=0; bi<len; bi++) {
724
                if (b[bi].compareTo(a[ai]) == 0) {
725
                    found = true;
726
                    break;
727
                }
728
            }
729
            if (! found) {
730
                return false;
731
            }
732
        }
733
        return true;
734
    }
735

    
736
    private String[] getPK(FeatureType ft) {
737
        
738
        List resp = new ArrayList();
739
        FeatureAttributeDescriptor attr;
740
        Iterator<FeatureAttributeDescriptor> iter = FeatureTypeHelper.iterator(ft);
741
        while (iter.hasNext()) {
742
            attr = (FeatureAttributeDescriptor) iter.next();
743
            if (attr.isPrimaryKey()) {
744
                resp.add(attr.getName());
745
            }
746
        }
747
        return (String[]) resp.toArray(new String[0]);
748
    }
749
}