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 @ 41536

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.exception.PerformEditingException;
41
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
42
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
43
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
44
import org.gvsig.fmap.dal.store.db.FeatureTypeHelper;
45
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecutePreparedSQLException;
46
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
47
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCPreparingSQLException;
48
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCSQLException;
49
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCUpdateWithoutChangesException;
50
import org.gvsig.tools.dynobject.DynObject;
51
import org.slf4j.Logger;
52
import org.slf4j.LoggerFactory;
53

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

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

    
63
        protected Appender appender;
64

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

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

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

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

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

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

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

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

    
114
        }
115

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

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

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

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

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

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

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

    
193
                        }
194

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

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

    
229
                        }
230

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

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

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

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

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

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

    
262
        }
263

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

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

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

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

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

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

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

    
321
                return actions;
322
        }
323

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

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

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

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

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

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

    
361
                StringBuilder sqlb = new StringBuilder();
362

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

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

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

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

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

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

    
392
                String sql = sqlb.toString();
393

    
394
                Statement st = null;
395

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

    
419
        }
420

    
421

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

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

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

    
451

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

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

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

    
463
        }
464

    
465

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

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

    
477
                sqlb.append(" (");
478

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

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

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

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

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

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

    
504
                sqlb.append(") ");
505

    
506
        }
507

    
508

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

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

    
515
                prepareSQLAndAttributeListForInsert(sqlb, attrs);
516

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

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

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

    
547
                // ************ Prepare SQL ****************
548

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

    
553
                sqlb.append(" SET ");
554

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

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

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

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

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

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

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

    
583
                updateAttrs.addAll(pkAttributes);
584

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

    
588

    
589

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

    
596
                TransactionalAction action = new TransactionalAction() {
597

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

    
600
                                if (featureTypesChanged.hasNext()) {
601

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

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

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

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

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

    
625
                                return null;
626
                        }
627

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

    
632
                };
633

    
634
                return action;
635

    
636
        }
637

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

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

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

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

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

    
680

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

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

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