Statistics
| Revision:

root / trunk / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialDriver.java @ 18592

History | View | Annotate | Download (140 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 Prodevelop and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *   Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *   +34 963862235
28
 *   gvsig@gva.es
29
 *   www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   Prodevelop Integraci?n de Tecnolog?as SL
34
 *   Conde Salvatierra de ?lava , 34-10
35
 *   46004 Valencia
36
 *   Spain
37
 *
38
 *   +34 963 510 612
39
 *   +34 963 510 968
40
 *   gis@prodevelop.es
41
 *   http://www.prodevelop.es
42
 */
43
package es.prodevelop.cit.gvsig.fmap.drivers.jdbc.oracle;
44

    
45
import java.awt.Shape;
46
import java.awt.geom.Point2D;
47
import java.awt.geom.Rectangle2D;
48
import java.math.BigDecimal;
49
import java.sql.Connection;
50
import java.sql.DatabaseMetaData;
51
import java.sql.PreparedStatement;
52
import java.sql.ResultSet;
53
import java.sql.ResultSetMetaData;
54
import java.sql.SQLException;
55
import java.sql.Statement;
56
import java.sql.Timestamp;
57
import java.sql.Types;
58
import java.util.ArrayList;
59
import java.util.HashMap;
60
import java.util.Hashtable;
61
import java.util.Iterator;
62
import java.util.Random;
63
import java.util.TreeMap;
64

    
65
import oracle.sql.ARRAY;
66
import oracle.sql.Datum;
67
import oracle.sql.NUMBER;
68
import oracle.sql.ROWID;
69
import oracle.sql.STRUCT;
70
import oracle.sql.StructDescriptor;
71
import oracle.sql.TIMESTAMP;
72

    
73
import org.apache.log4j.Logger;
74
import org.cresques.cts.ICoordTrans;
75
import org.cresques.cts.IProjection;
76

    
77
import com.hardcode.driverManager.IDelayedDriver;
78
import com.hardcode.gdbms.driver.exceptions.InitializeWriterException;
79
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
80
import com.hardcode.gdbms.driver.exceptions.WriteDriverException;
81
import com.hardcode.gdbms.engine.data.DataSource;
82
import com.hardcode.gdbms.engine.data.DataSourceFactory;
83
import com.hardcode.gdbms.engine.data.edition.DataWare;
84
import com.hardcode.gdbms.engine.spatial.fmap.FShapeGeneralPathX;
85
import com.hardcode.gdbms.engine.values.DoubleValue;
86
import com.hardcode.gdbms.engine.values.Value;
87
import com.hardcode.gdbms.engine.values.ValueFactory;
88
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
89
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
90
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
91
import com.iver.cit.gvsig.fmap.core.FNullGeometry;
92
import com.iver.cit.gvsig.fmap.core.FPoint2D;
93
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
94
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
95
import com.iver.cit.gvsig.fmap.core.FShape;
96
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
97
import com.iver.cit.gvsig.fmap.core.ICanReproject;
98
import com.iver.cit.gvsig.fmap.core.IFeature;
99
import com.iver.cit.gvsig.fmap.core.IGeometry;
100
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
101
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
102
import com.iver.cit.gvsig.fmap.crs.CRSFactory;
103
import com.iver.cit.gvsig.fmap.drivers.ConnectionJDBC;
104
import com.iver.cit.gvsig.fmap.drivers.DBException;
105
import com.iver.cit.gvsig.fmap.drivers.DBLayerDefinition;
106
import com.iver.cit.gvsig.fmap.drivers.DefaultJDBCDriver;
107
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
108
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
109
import com.iver.cit.gvsig.fmap.drivers.IConnection;
110
import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator;
111
import com.iver.cit.gvsig.fmap.drivers.db.utils.ConnectionWithParams;
112
import com.iver.cit.gvsig.fmap.drivers.db.utils.SingleVectorialDBConnectionManager;
113
import com.iver.cit.gvsig.fmap.edition.IWriteable;
114
import com.iver.cit.gvsig.fmap.edition.IWriter;
115
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
116
import com.iver.cit.gvsig.fmap.layers.XMLException;
117
import com.iver.utiles.NumberUtilities;
118
import com.iver.utiles.XMLEntity;
119
import com.vividsolutions.jts.algorithm.CGAlgorithms;
120
import com.vividsolutions.jts.geom.Coordinate;
121
import com.vividsolutions.jts.geom.Geometry;
122
import com.vividsolutions.jts.geom.GeometryFactory;
123
import com.vividsolutions.jts.geom.LineString;
124
import com.vividsolutions.jts.geom.LinearRing;
125
import com.vividsolutions.jts.geom.MultiPolygon;
126
import com.vividsolutions.jts.geom.Polygon;
127
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
128

    
129
import es.prodevelop.cit.gvsig.fmap.drivers.jdbc.oracle.OracleSpatialUtils;
130

    
131

    
132
/**
133
 * Vectorial driver to access Oracle databases geometries
134
 * Should work on Oracle Locator.
135
 *
136
 * It contains switches to test different modules to perform the
137
 * translation oracle structs --> gvsig geometries:
138
 *
139
 * - Parsing the structs directly.
140
 * - Using Oracle's JGeometry static methods
141
 * - Using Geotools utilities
142
 *
143
 *  (currently, the driver parses the structs directly)
144
 *
145
 * @author jldominguez
146
 *
147
 */
148
public class OracleSpatialDriver extends DefaultJDBCDriver
149
    implements IDelayedDriver, ICanReproject, IWriteable {
150
    private static Logger logger = Logger.getLogger(OracleSpatialDriver.class.getName());
151
    private static int FETCH_SIZE = 15000;
152

    
153
    // constants
154
    public static final int GEODETIC_FULLEXTENT_SAMPLE_SIZE = 50;
155
    public static final String GEODETIC_SRID = "8307";
156
    // public static final String ASSUMED_ORACLE_SRID = "8307";
157
    
158
    // ------------------------------------------------
159
    public static final String NAME = "Oracle Spatial Database Driver";
160
    public static final int ID_COLUMN_INDEX = 1;
161
    
162
    public static final String ALL_ORACLE_GEOMETADATA_VIEW = "ALL_SDO_GEOM_METADATA";
163
    public static final String USER_ORACLE_GEOMETADATA_VIEW = "USER_SDO_GEOM_METADATA";
164
    
165
    public static final String ORACLE_EPSG_TABLE_NAME = "ORA_EPSG";
166
    public static final String ORACLE_EPSG_FILE_NAME = "ORA_EPSG.DBF";
167
    public static final String DEFAULT_GEO_FIELD = "GEOMETRY";
168
    // public static final String DEFAULT_GEO_FIELD = "MERGEDGEOMETRY";
169

    
170
    public static final String ORACLE_ID_FIELD = "ROWID";
171
    public static final String DEFAULT_ID_FIELD_CASE_SENSITIVE = "GID";
172
    public static final String ORACLE_GEO_SCHEMA = "MDSYS";
173
    public static final String CONN_STR_BEGIN = "jdbc:oracle:thin:";
174
    
175
    public static final int VARCHAR2_STANDARD_SIZE = 80;
176
    public static final int VARCHAR2_LONG_SIZE = 256;
177
    public static final int MAX_ID_LENGTH = 30;
178
    private final static GeometryFactory geomFactory = new GeometryFactory();
179
    public static final double IRRELEVANT_DISTANCE = 0.00000001;
180
        private static final long ID_MIN_DELAY = 1000;
181

    
182
        public static final String ORACLE_JAR_FILE_NAME = "oracle.jdbc.driver.OracleDriver";
183

    
184
    static {
185
        try {
186
            Class.forName(ORACLE_JAR_FILE_NAME);
187
        }
188
        catch (ClassNotFoundException e) {
189
            throw new RuntimeException(e);
190
        }
191
    }
192

    
193
    private OracleSpatialWriter writer = null;
194

    
195
    // utility object to convert geometries.
196
//    private GeometryConverter geotools_conv;
197

    
198
    // switch variable
199
    private boolean use_geotools = false;
200
    private boolean tableHasSrid = true;
201

    
202
    // ------------------------------------------------
203
    private boolean isNotAvailableYet = true;
204
    private IGeometry nullGeom = new FNullGeometry();
205
    private Value nullVal = ValueFactory.createNullValue();
206
    private IdLoaderThread idLoader;
207
    private DriverAttributes drvAtts;
208
    private int[] pkOneBasedIndexes;
209
    private String[] fieldNames;
210
    private String not_restricted_sql = "";
211

    
212
    private Rectangle2D workingAreaInViewsCS = null;
213
    private Rectangle2D workingAreaInTablesCS = null;
214
    private STRUCT workingAreaInTablesCSStruct = null;
215

    
216
    private String idFieldNames;
217
    private int oneBasedGeoColInd = 0;
218
    private int shapeType = -1;
219
    private boolean needsCollectionLayer = true;
220

    
221
    // ----------------------------------------------
222
    // one feature is cached to avoid querying for each attribute request:
223
    private IFeature singleCachedFeature = null;
224
    private long singleCachedFeatureRowNum = -1;
225

    
226
    // ----------------------------------------------
227
    private boolean cancelIDLoad = false;
228

    
229
    // ----------------------------------------------
230
    private String fullTableName = "";
231
    private String geoColName = "";
232
    private String oracleSRID;
233
    private String epsgSRID;
234
    private String destProj = "";
235
    private Rectangle2D full_Extent = null;
236
    private boolean emptyWhereClause = true;
237
    private boolean isGeogCS = false;
238
    private boolean hasRealiableExtent = true;
239

    
240
    // new hash map to perform queries by row number:
241
    private HashMap rowToId = new HashMap();
242
        private String destProjOracle;
243
        private boolean isDestGeogCS = false;
244

    
245
    public OracleSpatialDriver() {
246
        drvAtts = new DriverAttributes();
247
        drvAtts.setLoadedInMemory(false);
248
    }
249

    
250
        public String getWhereClause() {
251
            return lyrDef.getWhereClause();
252
        }
253

    
254

    
255
    /**
256
     * This method is called when the user creates a new oracle
257
     * table from a vectorial layer
258
     *
259
     * @param params this array simply contains the parameters <tt>Connection</tt> and
260
     * <tt>DBLayerDefinition</tt>
261
     */
262
    public void setData(Object[] params) {
263
        setData((IConnection) params[0], (DBLayerDefinition) params[1]);
264
    }
265

    
266
    private void adjustLyrDef() throws SQLException {
267
        DBLayerDefinition ldef = getLyrDef();
268
        int cnt = metaData.getColumnCount();
269

    
270
        FieldDescription[] _new = new FieldDescription[cnt];
271

    
272
        for (int i = 0; i < cnt; i++) {
273
            _new[i] = new FieldDescription();
274
            _new[i].setFieldName(metaData.getColumnName(i + 1));
275
            _new[i].setDefaultValue(ValueFactory.createNullValue());
276
            _new[i].setFieldAlias(_new[i].getFieldName());
277
            _new[i].setFieldLength(getFieldWidth(i));
278

    
279
            int _type = metaData.getColumnType(i + 1);
280
            _new[i].setFieldType(_type);
281

    
282
            if ((_type == Types.FLOAT) || (_type == Types.DOUBLE) ||
283
                    (_type == Types.DECIMAL) || (_type == Types.REAL)) {
284
                _new[i].setFieldDecimalCount(6);
285
            }
286
            else {
287
                _new[i].setFieldDecimalCount(0);
288
            }
289
        }
290

    
291
        ldef.setFieldsDesc(_new);
292
        setLyrDef(ldef);
293
    }
294

    
295
    /**
296
     * Standard initializing method.
297
     */
298
    public void setData(IConnection _conn, DBLayerDefinition lyrDef) {
299
        conn = _conn;
300
        
301
        // This metadata is required to store layer in GVP
302
        // without problems:
303
        ConnectionWithParams _cwp =
304
                SingleVectorialDBConnectionManager.instance().findConnection(conn);
305
                host = _cwp.getHost();
306
                port = _cwp.getPort();
307
                dbName = _cwp.getDb();
308
                connName = _cwp.getName();
309

    
310
                try {
311
                        if (conn.isClosed()) {
312
                                SingleVectorialDBConnectionManager.instance().closeAndRemove(_cwp);
313
                                _cwp = SingleVectorialDBConnectionManager.instance().getConnection(
314
                                                _cwp.getDrvName(),
315
                                                _cwp.getUser(),
316
                                                _cwp.getPw(),
317
                                                _cwp.getName(),
318
                                                _cwp.getHost(),
319
                                                _cwp.getPort(),
320
                                                _cwp.getDb(), true);
321
                        }
322
                } catch (DBException e1) {
323
                        logger.error("While trying to reconnect: " + e1.getMessage());
324
                        logger.error("Layer will not be reloaded!");
325
                }
326
                
327
        // ------------------
328

    
329
                setUpperCase(lyrDef);
330
        lyrDef.setConnection(conn);
331

    
332
        String geo_can[];
333
                try {
334
                        geo_can = getGeometryFieldsCandidates(conn, lyrDef.getTableName());
335
                        removeStructFields(lyrDef, geo_can);
336
                } catch (DBException e) {
337
                        logger.error("While removing STRUCT fields: " + e.getMessage());
338
                }
339
        
340
        setLyrDef(lyrDef);
341

    
342
        geoColName = lyrDef.getFieldGeometry();
343
        
344
        String tn = lyrDef.getTableName();
345
        
346
        if (tn.indexOf(".") == -1) {
347
                
348
                if (lyrDef.getSchema() == null) {
349
                        fullTableName = _cwp.getUser().toUpperCase() + "." + tn;
350
                } else {
351
                        fullTableName = lyrDef.getSchema() + "." + tn;
352
                }
353
                
354
                
355
        } else {
356
                fullTableName = tn;
357
        }
358
        
359
        not_restricted_sql = "select " + getStandardSelectExpression() +
360
            " from " + getTableName() + " c ";
361

    
362
        // various metadata settings
363
        // getMetaDataInThisThread();
364
        cleanWhereClause();
365
        loadSdoMetadata();
366
        oneRowMetadata();
367

    
368
        setDestProjection(lyrDef.getSRID_EPSG());
369
        workingAreaInViewsCS = lyrDef.getWorkingArea();
370
        
371
        if ((workingAreaInViewsCS != null) && (epsgSRID != null)) {
372
            IProjection viewProj = CRSFactory.getCRS("EPSG:" + destProj);
373
            IProjection tableProj = CRSFactory.getCRS("EPSG:" + epsgSRID);
374
            ICoordTrans reprojecter = viewProj.getCT(tableProj);
375
                workingAreaInTablesCS = reprojecter.convert(workingAreaInViewsCS);
376
            workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
377
                    FShape.NULL, tableHasSrid, false, true);
378
        }
379

    
380
        cancelIDLoad = false;
381
        idLoader = new IdLoaderThread(this);
382
        idLoader.start();
383
    }
384

    
385
        private void removeStructFields(DBLayerDefinition def, String[] arr) {
386
                
387
                FieldDescription[] flds = def.getFieldsDesc();
388
                ArrayList aux = new ArrayList();
389
                
390
                for (int i=0; i<flds.length; i++) {
391
                        if (!isOneOfThese(flds[i].getFieldName(), arr)) {
392
                                aux.add(flds[i]);
393
                        }
394
                }
395
                
396
                FieldDescription[] flds_new =
397
                        (FieldDescription[]) aux.toArray(new FieldDescription[0]);
398
                def.setFieldsDesc(flds_new);
399
        }
400

    
401
        private boolean isOneOfThese(String name, String[] arr) {
402

    
403
                for (int i=0; i<arr.length; i++) {
404
                                if (arr[i].compareToIgnoreCase(name) == 0) return true; 
405
                        }
406
                return false;
407
        }
408

    
409
        private void setUpperCase(DBLayerDefinition def) {
410
                
411
                String aux = def.getCatalogName();
412
                if (aux != null) def.setCatalogName(aux.toUpperCase());
413

    
414
                aux = def.getSchema();
415
                if (aux != null) def.setSchema(aux.toUpperCase());
416
                
417
                /*
418
                aux = def.getFieldID();
419
                if (aux != null) def.setFieldID(aux.toUpperCase());
420
                
421
                aux = def.getFieldGeometry();
422
                if (aux != null) def.setFieldGeometry(aux.toUpperCase());
423
                
424
                String flds[] = def.getFieldNames();
425
                if (flds != null) {
426
                        for (int i=0; i<flds.length; i++) flds[i] = flds[i].toUpperCase();
427
                        def.setFieldNames(flds);
428
                }
429
                */
430
        }
431

    
432
        /**
433
     * Utility method to load IDs in a different thred, so that gvsig's gui
434
     * does not get blocked.
435
     *
436
     */
437
    public void getMetaDataInThisThread() {
438
        getMetadata();
439
    }
440

    
441
    private void getMetadata() {
442

    
443
            long id_load_start = System.currentTimeMillis();
444
        setIdRowTable();
445
        long id_load_end = System.currentTimeMillis();
446

    
447
        long delay = id_load_end - id_load_start;
448
        if (delay < ID_MIN_DELAY) {
449
                logger.info("Ids thread delayed by: " + (ID_MIN_DELAY - delay) + " ms.");
450
                try {
451
                                Thread.sleep(ID_MIN_DELAY - delay);
452
                        } catch (InterruptedException e) {
453
                                logger.error("While delaying ids thread: " + e.getMessage());
454
                        }
455
        }
456

    
457
        if (!hasRealiableExtent) {
458
                full_Extent = getEstimatedExtent(
459
                                getTableName(), geoColName, conn, 20, 1.5, isGeogCS);
460
        }
461

    
462
        if (cancelIDLoad) {
463
            return;
464
        }
465
    }
466

    
467
    private boolean needsCollectionLayer() {
468
        try {
469
            // SELECT DISTINCT(C.GEOM.SDO_GTYPE) FROM COMUICV C
470
            // String qry = "select distinct(c."  + geoColName + ".SDO_GTYPE) from " + getTableName() + " c";
471
            String qry = "select c." + geoColName + ".SDO_ELEM_INFO from " +
472
                getTableName() + " c";
473

    
474
            // SDO_ELEM_INFO
475
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
476
            ResultSet _rs = _st.executeQuery(qry);
477

    
478
            ArrayList types = new ArrayList();
479
            int aux = 0;
480

    
481
            ARRAY info_aux;
482
            int[] info_aux_int;
483
            int size;
484

    
485
            while (_rs.next()) {
486
                // aux = _rs.getInt(1);
487
                info_aux = (ARRAY) _rs.getObject(1);
488
                info_aux_int = info_aux.getIntArray();
489
                size = info_aux_int.length / 3;
490

    
491
                for (int i = 0; i < size; i++) {
492
                    aux = info_aux_int[(3 * i) + 1];
493
                }
494

    
495
                types.add(new Integer(aux % 1000));
496
            }
497

    
498
            _rs.close();
499
            _st.close();
500

    
501
            boolean resp = hasSeveralGeometryTypes(types, false);
502

    
503
            return resp;
504
        }
505
        catch (Exception se) {
506
                logger.error("While getting SDO metadata: " + se.getMessage());
507
        }
508

    
509
        return false;
510
    }
511

    
512
    private boolean hasSeveralGeometryTypes(ArrayList tt, boolean are_dims) {
513
        if (tt.size() == 0) {
514
            return false;
515
        }
516

    
517
        HashMap m = new HashMap();
518

    
519
        for (int i = 0; i < tt.size(); i++) {
520
            Integer integ = (Integer) tt.get(i);
521
            int val = integ.intValue();
522

    
523
            if ((val == 4) && (!are_dims)) {
524
                return true;
525
            }
526

    
527
            m.put("" + (val % 4), "a type");
528
        }
529

    
530
        Iterator iter = m.keySet().iterator();
531
        iter.next();
532

    
533
        return iter.hasNext();
534
    }
535

    
536
    private String getOracleSridFromCurrentRecord(ResultSet _rs)
537
        throws SQLException {
538
        Object obj = _rs.getObject("SRID");
539

    
540
        if (obj == null) {
541
            logger.warn("No SRID found for this table.");
542
            tableHasSrid = false;
543

    
544
            return null;
545
        }
546

    
547
        return obj.toString();
548
    }
549

    
550
    private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
551
        throws SQLException {
552
        ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
553

    
554
        if (dim_info_array == null) {
555
            // no full extent found:
556
            return null;
557
        }
558
        else {
559
            Datum[] da = dim_info_array.getOracleArray();
560

    
561
            STRUCT sx = (STRUCT) da[0];
562
            STRUCT sy = (STRUCT) da[1];
563

    
564
            try {
565
                double minx = Double.parseDouble(sx.getAttributes()[1].toString());
566
                double maxx = Double.parseDouble(sx.getAttributes()[2].toString());
567
                double miny = Double.parseDouble(sy.getAttributes()[1].toString());
568
                double maxy = Double.parseDouble(sy.getAttributes()[2].toString());
569

    
570
                if (minx > maxx) {
571
                    double aux = minx;
572
                    minx = maxx;
573
                    maxx = aux;
574
                }
575

    
576
                if (miny > maxy) {
577
                    double aux = miny;
578
                    miny = maxy;
579
                    maxy = aux;
580
                }
581

    
582
                return getRectangle(minx, maxx, miny, maxy);
583

    
584
                // fullExtentJTS = shapeToGeometry(fullExtent);
585
            }
586
            catch (Exception ex) {
587
                    logger.error("While getting full extent from metadata table.");
588
                return null;
589
            }
590
        }
591
    }
592

    
593
    private void loadSdoMetadata() {
594
        try {
595
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
596
            String[] tokens = getTableName().split("\\u002E", 2);
597
            String qry;
598
            if (tokens.length > 1)
599
            {
600
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
601
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
602
                tokens[1] + "' AND COLUMN_NAME = '" + geoColName + "'";
603
            }
604
            else
605
            {
606
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
607
                " where TABLE_NAME = " + "'" + getTableName()
608
                + "' AND COLUMN_NAME = '"
609
                + geoColName + "'";
610

    
611
            }
612

    
613
            ResultSet _rs = _st.executeQuery(qry);
614

    
615
            if (_rs.next()) {
616
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
617

    
618
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
619

    
620
                try {
621
                                        epsgSRID = oracleSridToEpsgSrid(oracleSRID);
622
                                } catch (Exception e) {
623
                                        logger.error("Unknown oracle SRID: " + oracleSRID);
624
                                        tableHasSrid = false;
625
                                }
626
                full_Extent = getFullExtentFromCurrentRecord(_rs);
627

    
628
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS);
629

    
630
                if (!hasRealiableExtent) {
631
                        full_Extent = getFastEstimatedExtent(
632
                                            getTableName(), geoColName, conn, 20, 10, isGeogCS);
633
                }
634

    
635
                _rs.close();
636
                _st.close();
637
            }
638
            else {
639
                throw new SQLException("Empty resultset from this query: " +
640
                    qry);
641
            }
642
        }
643
        catch (SQLException se) {
644
                logger.error("While getting SDO metadata: " + se.getMessage());
645
        }
646
    }
647

    
648
    /**
649
     * Utility method to find out if a coordinate system is geodetic or not.
650
     *
651
     * @param oracleSRID2 the coordinate system's oracle code
652
     * @param thas whether the table has a coordinate system set.
653
     * if not, the method returns false.
654
     * @return whether the coordinate system is geodetic or not.
655
     */
656
    public static boolean getIsGCS(String oracleSRID2, boolean thas) {
657

    
658
        if (!thas) return false;
659
        if (oracleSRID2 == null) return false;
660
        
661
        int ora_cs = 0;
662

    
663
        try {
664
            ora_cs = Integer.parseInt(oracleSRID2);
665
        }
666
        catch (Exception ex) {
667
            return false;
668
        }
669

    
670
        if (((ora_cs >= 8000) && (ora_cs <= 8999)) || (ora_cs == 524288)) {
671
            return true;
672
        } else {
673
                return false;
674
        }
675
    }
676

    
677
    private Rectangle2D getRectangle(double minx, double maxx, double miny,
678
        double maxy) {
679
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
680
                maxy - miny);
681

    
682
        return resp;
683
    }
684

    
685
    private void oneRowMetadata() {
686
        try {
687
            String _sql = "select " + getStandardSelectExpression() + ", c." +
688
                geoColName + " from " + getTableName() + " c ";
689

    
690
            st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
691
                    ResultSet.CONCUR_READ_ONLY);
692

    
693
            ResultSet _rs = st.executeQuery(_sql + " where c." + geoColName + " is not NULL AND rownum = 1");
694

    
695
            if (_rs.next()) {
696
                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
697
                shapeType = getShapeTypeOfStruct(sample_geo);
698
            }
699
            else {
700
                shapeType = FShape.MULTI;
701
            }
702

    
703
            // -----------------------
704
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
705
            metaData = _rs.getMetaData();
706

    
707
            userName = ((ConnectionJDBC)conn).getConnection().getMetaData().getUserName();
708

    
709
            // geoColInd = _rs.findColumn(geoColName);
710
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
711

    
712
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
713
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
714

    
715
            int cnt = metaData.getColumnCount();
716
            fieldNames = new String[cnt];
717

    
718
            for (int i = 0; i < cnt; i++) {
719
                fieldNames[i] = metaData.getColumnName(i + 1);
720
            }
721

    
722
            getIdFieldNames();
723

    
724
            adjustLyrDef();
725

    
726
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan
727
        }
728
        catch (SQLException se) {
729
            logger.error("While getting metadata. " + se.getMessage());
730
        }
731
    }
732

    
733
    private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
734

    
735
        int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue();
736
        
737
        int type_part = code % 10;
738
        int dim_part = code / 1000;
739

    
740
        int z_added = 0;
741
        if ((dim_part == 3) || (dim_part == 4)) {
742
                z_added = 512;
743
        }
744

    
745
        switch (type_part) {
746
        case 1:
747
            return z_added + FShape.POINT;
748

    
749
        case 2:
750
            return z_added + FShape.LINE;
751

    
752
        case 3:
753
            return z_added + FShape.POLYGON;
754

    
755
        case 4:
756
            return z_added + FShape.MULTI;
757

    
758
        case 5:
759
            return z_added + FShape.MULTIPOINT;
760

    
761
        case 6:
762
            return z_added + FShape.LINE;
763

    
764
        case 7:
765
            return z_added + FShape.POLYGON;
766
        }
767

    
768
        logger.error("Unknown geometry type: " + code);
769

    
770
        return FShape.NULL;
771
    }
772

    
773
    private String getIdFieldNames() {
774
        try {
775
            idFieldNames = "";
776

    
777
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
778
                idFieldNames = idFieldNames +
779
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
780
            }
781
        }
782
        catch (SQLException se) {
783
        }
784

    
785
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
786

    
787
        return idFieldNames;
788
    }
789

    
790
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
791
        int[] _res = new int[1];
792
        _res[0] = 1;
793

    
794
        return _res;
795
    }
796

    
797
    public String getSqlTotal() {
798
        // TODO Auto-generated method stub
799
        return "";
800
    }
801

    
802
    public String getCompleteWhere() {
803
        // TODO Auto-generated method stub
804
        return "";
805
    }
806

    
807
    /**
808
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
809
     * and uses directly that sentence to query the table).
810
     */
811
    public IFeatureIterator getFeatureIterator(String sql)
812
        throws ReadDriverException {
813
        if (isNotAvailableYet) {
814
                return new AnEmptyFeatureIterator();
815
            // return null;
816
        }
817

    
818
        singleCachedFeatureRowNum = -1;
819

    
820
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
821

    
822
        ResultSet localrs = (ResultSet) rs_st[0];
823
        Statement _st = (Statement) rs_st[1];
824

    
825
        return new OracleSpatialFeatureIterator(this, localrs, _st,
826
            oneBasedGeoColInd, use_geotools);
827
    }
828

    
829
    /**
830
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
831
     */
832
    public String getConnectionStringBeginning() {
833
        // oracle
834
        return CONN_STR_BEGIN;
835
    }
836

    
837
    public void open() { // throws DriverException {
838
    }
839

    
840
    /**
841
     * Gets Oracle's default port: 1521
842
     */
843
    public int getDefaultPort() {
844
        // oracle port
845
        return 1521;
846
    }
847

    
848
    /**
849
     * Gets the feature iterator for a given rectangle (the view's bounding box)
850
     * and a SRS.
851
     */
852
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
853
        throws ReadDriverException {
854
        if (isNotAvailableYet) {
855
                return new AnEmptyFeatureIterator();
856
            // return null;
857
        }
858

    
859
        singleCachedFeatureRowNum = -1;
860

    
861
        STRUCT local_st = shapeToStruct(r, FShape.NULL, tableHasSrid, false, true);
862

    
863
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
864

    
865
        ResultSet localrs = (ResultSet) rs_st[0];
866
        Statement _st = (Statement) rs_st[1];
867

    
868
        return new OracleSpatialFeatureIterator(this, localrs, _st,
869
            oneBasedGeoColInd, use_geotools);
870
    }
871

    
872
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
873
        if (workingAreaInTablesCS == null) return r;
874
        return doIntersect(r, workingAreaInTablesCS);
875
    }
876

    
877
    /**
878
     * This method reverts to the one without the fields specification.
879
     * The fields have been selected from the start.
880
     */
881
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
882
        String[] alphaNumericFieldsNeeded) throws ReadDriverException {
883
            
884
        if (isNotAvailableYet) {
885
                return new AnEmptyFeatureIterator();
886
            // return null;
887
        }
888

    
889
        singleCachedFeatureRowNum = -1;
890

    
891
        return getFeatureIterator(r, strEPSG);
892
    }
893

    
894
    public String getGeometryField(String fieldName) {
895
        return fieldName;
896

    
897
        // return "ASBINARY(" + fieldName + ")";
898
    }
899

    
900
    public DriverAttributes getDriverAttributes() {
901
        return drvAtts;
902
    }
903

    
904
    /**
905
     * Gets the requested geometry. Always performs a new query in this case.
906
     * This should be a rare way to get the geometries. The standard way is by using
907
     * the iterators.
908
     */
909
    public IGeometry getShape(int _ind) throws ReadDriverException {
910
        if (isNotAvailableYet) {
911
            return nullGeom;
912
        }
913

    
914
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
915

    
916
        String _sql = "select " + geoColName + " from " + getTableName() +
917
            " where rowid = ?";
918

    
919
        try {
920
            java.sql.PreparedStatement ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(_sql);
921
            ps.setObject(1, r_id);
922

    
923
            // Statement stmnt = conn.createStatement();
924
            ps.execute();
925

    
926
            ResultSet _res = ps.getResultSet();
927

    
928
            if (_res.next()) {
929
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
930
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
931
                _res.close();
932
                ps.close();
933

    
934
                return theGeom;
935
            }
936
            else {
937
                logger.error("Unable to get shape: " + _ind +
938
                    " (probably due to edition)");
939
                
940

    
941
                return nullGeom;
942
            }
943
        }
944
        catch (SQLException se) {
945
            throw new ReadDriverException(getName(), se);
946
        }
947
    }
948

    
949
    public boolean isWritable() {
950
        return true;
951
    }
952

    
953
    public String getName() {
954
        return NAME;
955
    }
956

    
957
    public int[] getPrimaryKeys() throws ReadDriverException {
958
        return pkOneBasedIndexes;
959
    }
960

    
961
    /*
962
    public void write(DataWare dataWare) throws ReadDriverException {
963
    }
964
    */
965

    
966
    private void setIdRowTable() {
967
        hashRelate = new Hashtable();
968

    
969
        java.sql.PreparedStatement ps = null;
970

    
971
        try {
972
            String _sql = getIdAndElemInfoFullResulltSetQuery();
973

    
974
            logger.debug("SQL para leer ids: " + _sql);
975
            Statement st = null;
976

    
977

    
978
            st = ((ConnectionJDBC)conn).getConnection().createStatement(
979
                            ResultSet.TYPE_FORWARD_ONLY,
980
                            ResultSet.CONCUR_READ_ONLY);
981
            
982
            
983

    
984
            // st = ((ConnectionJDBC)conn).getConnection().createStatement();
985

    
986
             st.setFetchSize(FETCH_SIZE);
987
             logger.info("FETCH_SIZE = " + FETCH_SIZE);
988

    
989
            ResultSet _r = null;
990
            _r = st.executeQuery(_sql);
991

    
992
            ROWID ri = null;
993

    
994
            int row = 0;
995
            String gid;
996
            Value aux = null;
997

    
998
            // ----------------------------------- types init
999
            ArrayList types = new ArrayList();
1000
            int types_aux = 0;
1001

    
1002
            ARRAY info_aux;
1003
            int[] info_aux_int;
1004
            int size;
1005

    
1006
            // ----------------------------------- types init
1007
            logger.debug("Beginning of result set:");
1008

    
1009
            while (_r.next()) {
1010
                // ---------------------------------------
1011
                ri = (ROWID) _r.getObject(1);
1012
                gid = ri.stringValue();
1013
                aux = ValueFactory.createValue(gid);
1014

    
1015
                Integer intobj = new Integer(row);
1016
                hashRelate.put(aux, intobj);
1017
                rowToId.put(intobj, ri);
1018

    
1019
                if ((row % 5000) == 0) {
1020
                    // ------------------------------------------- cancel load
1021
                    if (cancelIDLoad) {
1022
                        hashRelate.clear();
1023
                        rowToId.clear();
1024

    
1025
                        return;
1026
                    }
1027

    
1028
                    // -------------------------------------------
1029
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
1030
                    logger.info("IDs read: " + fmt);
1031
                }
1032

    
1033
                row++;
1034

    
1035
                // --------------------------------------- types
1036
                info_aux = (ARRAY) _r.getObject(2);
1037

    
1038
                if (info_aux == null) {
1039
                    // logger.debug("NULL info array found in record: " + row);
1040
                }
1041
                else {
1042
                    info_aux_int = info_aux.getIntArray();
1043
                    size = info_aux_int.length / 3;
1044

    
1045
                    for (int i = 0; i < size; i++) {
1046
                        types_aux = info_aux_int[(3 * i) + 1];
1047
                        types.add(new Integer(types_aux % 1000));
1048
                    }
1049
                }
1050

    
1051
                // --------------------------------------- types end
1052
            }
1053

    
1054
            _r.close();
1055
//            ps.close();
1056
            st.close();
1057
            numReg = row;
1058

    
1059
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
1060

    
1061
            if (needsCollectionLayer) {
1062
                shapeType = FShape.MULTI;
1063
            }
1064
        }
1065
        catch (SQLException e) {
1066
                logger.error("While setting id-row hashmap: " +
1067
                e.getMessage());
1068
        }
1069
    }
1070

    
1071
    public int getFieldCount() throws ReadDriverException {
1072
        try {
1073
            return metaData.getColumnCount();
1074
        }
1075
        catch (SQLException e) {
1076
                logger.error("While getting field count: " + e.getMessage());
1077
            throw new ReadDriverException(getName(), e);
1078
        }
1079
    }
1080

    
1081
    public String[] getFieldNames() {
1082
        return fieldNames;
1083
    }
1084

    
1085
    public String getTotalFields() {
1086
        String strAux = "";
1087

    
1088
        for (int i = 0; i < fieldNames.length; i++) {
1089
            if (i == 0) {
1090
                strAux = fieldNames[i];
1091
            }
1092
            else {
1093
                strAux = strAux + ", " + fieldNames[i];
1094
            }
1095
        }
1096

    
1097
        return strAux;
1098
    }
1099

    
1100
    public int getFieldType(int idField) throws ReadDriverException {
1101
        int i = 0;
1102

    
1103
        try {
1104
            i = idField + 1; // idField viene basado en 0
1105

    
1106
            int __type = metaData.getColumnType(i);
1107

    
1108
            // we must add this entry because we did not remove the 'geometry' column
1109
            if (__type == Types.STRUCT) {
1110
                return Types.VARCHAR; // .STRUCT;
1111
                                      // ----------------------------------------------------------------------
1112
            }
1113

    
1114
            if (__type == Types.VARCHAR) {
1115
                return Types.VARCHAR;
1116
            }
1117

    
1118
            if (__type == Types.FLOAT) {
1119
                return Types.FLOAT;
1120
            }
1121

    
1122
            if (__type == Types.DOUBLE) {
1123
                return Types.DOUBLE;
1124
            }
1125

    
1126
            if (__type == Types.INTEGER) {
1127
                return Types.INTEGER;
1128
            }
1129

    
1130
            if (__type == Types.SMALLINT) {
1131
                return Types.SMALLINT;
1132
            }
1133

    
1134
            if (__type == Types.TINYINT) {
1135
                return Types.TINYINT;
1136
            }
1137

    
1138
            if (__type == Types.BIGINT) {
1139
                return Types.BIGINT;
1140
            }
1141

    
1142
            if (__type == Types.BIT) {
1143
                return Types.BIT;
1144
            }
1145

    
1146
            if (__type == Types.DATE) {
1147
                return Types.DATE;
1148
            }
1149

    
1150
            if (__type == Types.DECIMAL) {
1151
                return Types.DOUBLE;
1152
            }
1153

    
1154
            if (__type == Types.NUMERIC) {
1155
                    int dec_pos = metaData.getScale(i);
1156
                    if (dec_pos == 0) {
1157
                            return Types.INTEGER;
1158
                    } else {
1159
                            return Types.DOUBLE;
1160
                    }
1161
            }
1162

    
1163
            if (__type == Types.DATE) {
1164
                return Types.DATE;
1165
            }
1166

    
1167
            if (__type == Types.TIME) {
1168
                return Types.TIME;
1169
            }
1170

    
1171
            if (__type == Types.TIMESTAMP) {
1172
                return Types.TIMESTAMP;
1173
            }
1174
        }
1175
        catch (SQLException e) {
1176
            logger.error("Unknown field type of : " + i);
1177
            throw new ReadDriverException(getName(), e);
1178
        }
1179

    
1180
        return -1;
1181
    }
1182

    
1183

    
1184
    public String getFieldName(int fieldId) throws ReadDriverException {
1185
        return fieldNames[fieldId];
1186
    }
1187

    
1188
    public int getFieldWidth(int fieldId) {
1189
        int i = -1;
1190

    
1191
        try {
1192
            int aux = fieldId + 1; // fieldId viene basado en 0
1193
            i = metaData.getColumnDisplaySize(aux);
1194
        }
1195
        catch (SQLException e) {
1196
            logger.error("While getting field width: " + e.getMessage());
1197
        }
1198

    
1199
        if (i < 0) {
1200
            i = 255;
1201
        }
1202

    
1203
        return i;
1204
    }
1205

    
1206
    public Value getFieldValue(long rowIndex, int field_Id) throws ReadDriverException {
1207
        if (isNotAvailableYet) {
1208
            return nullVal;
1209
        }
1210

    
1211
        if ((singleCachedFeature != null) &&
1212
                (rowIndex == singleCachedFeatureRowNum)) {
1213
            return singleCachedFeature.getAttributes()[field_Id];
1214
        }
1215

    
1216
        // return ValueFactory.createNullValue();
1217
        ResultSet _r = null;
1218
        java.sql.PreparedStatement ps = null;
1219

    
1220
        try {
1221
            String rnq = getSearchId();
1222
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1223

    
1224
            ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(rnq);
1225
            ps.setObject(1, _id);
1226

    
1227
            ps.execute();
1228
            _r = ps.getResultSet();
1229
            
1230
            if (!_r.next()) {
1231
                _r.close();
1232
                ps.close();
1233
                    throw new SQLException("No row for ROWID: " + _id.toString() + ". Possibly deleted from another app.");
1234
            }
1235
            
1236
        } catch (SQLException se) {
1237
                logger.error("While getting row " + rowIndex + " : " + se.getMessage());
1238
                return ValueFactory.createNullValue();
1239
        }
1240

    
1241
        IFeature ife = null;
1242
        Value[] atts = null;
1243

    
1244
        try {
1245
            ROWID ri = (ROWID) _r.getObject(1);
1246
            atts = getAttributes(_r, true);
1247

    
1248
            String gid = ri.stringValue();
1249
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1250
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1251
            ife = new DefaultFeature(theGeom, atts, gid);
1252
            _r.close();
1253
            ps.close();
1254
        } catch (SQLException se) {
1255
            logger.error("Error while doing next(): " + se.getMessage(), se);
1256
            return ValueFactory.createNullValue();
1257
        }
1258

    
1259
        // -------------------------------
1260
        singleCachedFeature = ife;
1261
        singleCachedFeatureRowNum = rowIndex;
1262

    
1263
        // -------------------------------
1264
        if (atts == null) {
1265
            return ValueFactory.createNullValue();
1266
        } else {
1267
            return atts[field_Id];
1268
        }
1269
    }
1270

    
1271
    public static void showMemory() {
1272
        Runtime r = Runtime.getRuntime();
1273
        long mem = r.totalMemory() - r.freeMemory();
1274
        logger.info("Total memory : " + mem);
1275
    }
1276

    
1277
    public Rectangle2D getFullExtent() {
1278
            return full_Extent;
1279
    }
1280

    
1281
    /**
1282
     * Utility method to get a geometry from a struct.
1283
     *
1284
     * @param theStruct the struct to be converted
1285
     * @param use_gtools switch to use geotools classes or not
1286
     * @return the geometry
1287
     * @throws SQLException
1288
     */
1289
    public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
1290
        throws SQLException {
1291
        IGeometry _igeom = null;
1292

    
1293
        if (theStruct == null) {
1294
            return nullGeom;
1295
        }
1296

    
1297
        if (use_gtools) { // geotools
1298
//            _igeom = getGeotoolsIGeometry(theStruct);
1299
        }
1300
        else { // jgeometry
1301
            _igeom = getFMapGeometry(theStruct, false);
1302
        }
1303

    
1304
        return _igeom;
1305
    }
1306

    
1307
    /*
1308
    private IGeometry getFMapGeometry(JGeometry jg, boolean force_not_collection) {
1309
        int jgtype = jg.getType();
1310
        int dim = jg.getDimensions();
1311
        IGeometry ig = null;
1312

1313
        if ((jgtype != JGeometry.GTYPE_COLLECTION) &&
1314
                (isActuallyACollection(jg))) {
1315
            jgtype = JGeometry.GTYPE_COLLECTION;
1316
        }
1317

1318
        switch (jgtype) {
1319
        case JGeometry.GTYPE_COLLECTION:
1320

1321
            int srid = jg.getSRID();
1322
            ig = getFMapGeometryCollection(jg, dim, srid);
1323

1324
            break;
1325

1326
        case JGeometry.GTYPE_POINT:
1327
        case JGeometry.GTYPE_MULTIPOINT:
1328
            ig = getFMapGeometryPoint(jg, dim);
1329

1330
            break;
1331

1332
        case JGeometry.GTYPE_CURVE:
1333
        case JGeometry.GTYPE_MULTICURVE:
1334
            ig = getFMapGeometryMultiLineString(jg, dim);
1335

1336
            break;
1337

1338
        case JGeometry.GTYPE_POLYGON:
1339
        case JGeometry.GTYPE_MULTIPOLYGON:
1340
            ig = getFMapGeometryMultipolygon(jg, dim);
1341

1342
            break;
1343
        }
1344

1345
        return ig;
1346
    }
1347
    */
1348

    
1349
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim) {
1350
        // int __srid) {
1351

    
1352
            NUMBER _srid = new NUMBER(0);
1353
        NUMBER main_type = new NUMBER((dim * 1000) +
1354
                OracleSpatialUtils.getStructType(the_data));
1355

    
1356

    
1357
        Datum[] all_info_array = null;
1358
        Object[] elems_info_aray = null;
1359
        Datum[] all_ords = null;
1360

    
1361
        Object[] ords_of_groups = null;
1362
        Object[] _elems_info_aray = null;
1363
        try {
1364
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1365
            elems_info_aray = groupByElement(all_info_array);
1366
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1367

    
1368
            ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1369
            _elems_info_aray = new Object[elems_info_aray.length];
1370
        }
1371
        catch (SQLException e) {
1372
            logger.error("Unexpected error: " + e.getMessage());
1373
        }
1374

    
1375

    
1376
        for (int i = 0; i < elems_info_aray.length; i++) {
1377
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1378
        }
1379

    
1380
        // _elems_info_aray, ords_of_groups
1381
        int no_of_elems = ords_of_groups.length;
1382
        IGeometry[] geoms = new IGeometry[no_of_elems];
1383

    
1384
        for (int i = 0; i < no_of_elems; i++) {
1385
            Datum[] item_info_array = null;
1386
            Datum[] item_ords = null;
1387
            NUMBER gtype = null;
1388

    
1389
            try {
1390
                item_info_array = (Datum[]) _elems_info_aray[i];
1391
                item_ords = (Datum[]) ords_of_groups[i];
1392

    
1393
                gtype = new NUMBER((dim * 1000) +
1394
                        (item_info_array[1].intValue() % 1000));
1395

    
1396
                if (tableHasSrid) {
1397
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1398
                }
1399
            }
1400
            catch (SQLException se) {
1401
                logger.error("Unexpected error: " + se.getMessage());
1402
            }
1403

    
1404
            // if it's the first geometry, the type is the collection's main type (no?) - no
1405
            // if (i == 0) gtype = main_type;
1406

    
1407
            STRUCT itemst = null;
1408

    
1409
            if (tableHasSrid) {
1410

    
1411
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1412
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1413
            }
1414
            else {
1415
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1416
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1417
            }
1418

    
1419
            geoms[i] = getFMapGeometry(itemst, true);
1420
        }
1421

    
1422
        return new FGeometryCollection(geoms);
1423
    }
1424

    
1425
    /**
1426
     * Utility method to transform a struct into a IGeometry.
1427
     *
1428
     * @param st the struct to be converted
1429
     * @param force_not_collection t5his parameter is currently ignored
1430
     * @return the IGeometry
1431
     */
1432
    public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1433

    
1434
            if (st == null) {
1435
                    return new FNullGeometry();
1436
            }
1437

    
1438
        Datum[] the_data = null;
1439

    
1440
        try {
1441
            the_data = st.getOracleAttributes();
1442

    
1443
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1444
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1445

    
1446
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1447

    
1448
            if (dim < 2) {
1449
                dim = 2;
1450
            }
1451

    
1452
            IGeometry ig = null;
1453

    
1454
            if (isActuallyACollection(the_data)) {
1455
                    // logger.debug("isActuallyACollection(the_data) = TRUE");
1456
                jgtype = FShape.MULTI;
1457
            }
1458

    
1459
            switch (jgtype) {
1460
            case FShape.MULTI:
1461

    
1462
                // int srid = ((NUMBER) the_data[1]).intValue();
1463
                ig = getFMapGeometryCollection(the_data, dim);
1464

    
1465
                break;
1466

    
1467
            case FShape.POINT:
1468
                ig = getFMapGeometryPoint(the_data, dim);
1469

    
1470
                break;
1471

    
1472
            case FShape.LINE:
1473
                ig = getFMapGeometryMultiLineString(the_data, dim);
1474

    
1475
                break;
1476

    
1477
            case FShape.POLYGON:
1478
                ig = getFMapGeometryMultipolygon(the_data, dim);
1479

    
1480
                break;
1481
            }
1482

    
1483
            return ig;
1484
        }
1485
        catch (SQLException e) {
1486
            logger.error(e);
1487
        }
1488

    
1489
        return null;
1490
    }
1491

    
1492
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1493
        int size = input.length / n;
1494
        double[] resp = new double[size];
1495

    
1496
        for (int i = 0; i < size; i++) {
1497
            resp[i] = input[(i * n) + ind];
1498
        }
1499

    
1500
        return resp;
1501
    }
1502

    
1503
    private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1504
        int size = input.length / n;
1505
        double[] resp = new double[size];
1506

    
1507
        for (int i = 0; i < size; i++) {
1508
            resp[i] = input[(i * n) + ind];
1509
        }
1510

    
1511
        return resp;
1512
    }
1513

    
1514
    /*
1515
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1516
        IGeometry ig = null;
1517

1518
        if (jg.isCircle()) {
1519
            ig = getCircleFromJGeometry(jg);
1520
        }
1521
        else {
1522
            Shape shape = jg.createShape();
1523
            GeneralPathX gpx = new GeneralPathX(shape);
1524

1525
            if (dim == 2) {
1526
                ig = ShapeFactory.createPolygon2D(gpx);
1527
            }
1528
            else {
1529
                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1530
                ig = ShapeFactory.createPolygon3D(gpx, z);
1531
            }
1532
        }
1533

1534
        return ig;
1535
    }
1536
    */
1537

    
1538
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1539
        IGeometry ig = null;
1540

    
1541
        if (OracleSpatialUtils.isCircle(the_data)) {
1542
            ig = getCircleFromStruct(the_data);
1543
        }
1544
        else {
1545
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1546

    
1547
            if (dim == 2) {
1548
                ig = ShapeFactory.createPolygon2D(gpx);
1549
            }
1550
            else {
1551
                double[] ords = null;
1552

    
1553
                try {
1554
                    ords = ((ARRAY) the_data[4]).getDoubleArray();
1555
                }
1556
                catch (SQLException se) {
1557
                    logger.error("While getting ordinates: " + se.getMessage(),
1558
                        se);
1559
                }
1560

    
1561
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1562
                ig = ShapeFactory.createPolygon3D(gpx, z);
1563
            }
1564
        }
1565

    
1566
        return ig;
1567
    }
1568

    
1569
    /*
1570
    private IGeometry getCircleFromJGeometry(JGeometry jg) {
1571
        double[] threep = jg.getOrdinatesArray();
1572
        Point2D[] three = new Point2D.Double[3];
1573
        three[0] = new Point2D.Double(threep[0], threep[1]);
1574
        three[1] = new Point2D.Double(threep[2], threep[3]);
1575
        three[2] = new Point2D.Double(threep[4], threep[5]);
1576

1577
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1578

1579
        Point2D cent = (Point2D) cent_rad[0];
1580
        double radius = ((Double) cent_rad[1]).doubleValue();
1581

1582
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1583

1584
        return circ;
1585
    }
1586
    */
1587

    
1588
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1589
        double[] threep = null;
1590

    
1591
        try {
1592
            threep = ((ARRAY) the_data[4]).getDoubleArray();
1593
        }
1594
        catch (SQLException se) {
1595
            logger.error("While getting ords from struct: " + se.getMessage(),
1596
                se);
1597

    
1598
            return new FNullGeometry();
1599
        }
1600

    
1601
        Point2D[] three = new Point2D.Double[3];
1602
        three[0] = new Point2D.Double(threep[0], threep[1]);
1603
        three[1] = new Point2D.Double(threep[2], threep[3]);
1604
        three[2] = new Point2D.Double(threep[4], threep[5]);
1605

    
1606
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1607

    
1608
        Point2D cent = (Point2D) cent_rad[0];
1609
        double radius = ((Double) cent_rad[1]).doubleValue();
1610

    
1611
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1612

    
1613
        return circ;
1614
    }
1615

    
1616
    /*
1617
    private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1618
        Shape shape = jg.createShape();
1619
        GeneralPathX gpx = new GeneralPathX(shape);
1620
        IGeometry ig = null;
1621

1622
        if (dim == 2) {
1623
            ig = ShapeFactory.createPolyline2D(gpx);
1624
        }
1625
        else {
1626
            double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1627
            ig = ShapeFactory.createPolyline3D(gpx, z);
1628
        }
1629

1630
        return ig;
1631
    }
1632
    */
1633

    
1634
    private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1635
        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1636
        IGeometry ig = null;
1637
        double[] ords = null;
1638

    
1639
        if (dim == 2) {
1640
            ig = ShapeFactory.createPolyline2D(gpx);
1641
        }
1642
        else {
1643
            ords = OracleSpatialUtils.getOrds(the_data);
1644

    
1645
            double[] z = getIndBigDecimalModule(ords, 2, dim);
1646
            ig = ShapeFactory.createPolyline3D(gpx, z);
1647
        }
1648

    
1649
        return ig;
1650
    }
1651

    
1652
    /*
1653
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1654
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1655

1656
            return getFMapGeometrySdoPoint(jg_point, dim);
1657
        }
1658

1659
        IGeometry ig = null;
1660
        int total_size = jg_point.getOrdinatesArray().length;
1661
        int no_po = total_size / dim;
1662
        double[] x = new double[no_po];
1663
        double[] y = new double[no_po];
1664
        double[] z = new double[no_po];
1665

1666
        for (int i = 0; i < no_po; i++) {
1667
            x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1668
            y[i] = jg_point.getOrdinatesArray()[(i * dim) + 1];
1669

1670
            if (dim >= 3) {
1671
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1672
            }
1673
        }
1674

1675
        if (dim == 2) {
1676
            if (no_po == 1) {
1677
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1678
            }
1679
            else {
1680
                ig = ShapeFactory.createMultipoint2D(x, y);
1681
            }
1682
        }
1683
        else {
1684
            if (no_po == 1) {
1685
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1686
            }
1687
            else {
1688
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1689
            }
1690
        }
1691

1692
        return ig;
1693
    }
1694
    */
1695

    
1696
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1697
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1698

    
1699
        if (ords == null) { // sdo_point
1700

    
1701
            return getFMapGeometrySdoPoint(the_data, dim);
1702
        }
1703

    
1704
        IGeometry ig = null;
1705
        int total_size = ords.length;
1706
        int no_po = total_size / dim;
1707
        double[] x = new double[no_po];
1708
        double[] y = new double[no_po];
1709
        double[] z = new double[no_po];
1710

    
1711
        for (int i = 0; i < no_po; i++) {
1712
            x[i] = ords[i * dim]; // pp[i].getX();
1713
            y[i] = ords[(i * dim) + 1];
1714

    
1715
            if (dim >= 3) {
1716
                z[i] = ords[(i * dim) + 2];
1717
            }
1718
        }
1719

    
1720
        if (dim == 2) {
1721
            if (no_po == 1) {
1722
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1723
            }
1724
            else {
1725
                ig = ShapeFactory.createMultipoint2D(x, y);
1726
            }
1727
        }
1728
        else {
1729
            if (no_po == 1) {
1730
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1731
            }
1732
            else {
1733
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1734
            }
1735
        }
1736

    
1737
        return ig;
1738
    }
1739

    
1740
    /*
1741
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1742
        double[] p = jgp.getPoint();
1743
        IGeometry ig = null;
1744

1745
        if (d == 2) {
1746
            ig = ShapeFactory.createPoint2D(p[0], p[1]);
1747
        }
1748
        else {
1749
            ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1750
        }
1751

1752
        return ig;
1753
    }
1754
    */
1755

    
1756
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1757
        double x = 0;
1758
        double y = 0;
1759
        double z = 0;
1760

    
1761
        try {
1762
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1763
            x = ((NUMBER) aux[0]).doubleValue();
1764
            y = ((NUMBER) aux[1]).doubleValue();
1765

    
1766
            if (d > 2) {
1767
                z = ((NUMBER) aux[2]).doubleValue();
1768
            }
1769
        }
1770
        catch (SQLException se) {
1771
            logger.error("While getting sdo point ordinates: " +
1772
                se.getMessage(), se);
1773
        }
1774

    
1775
        IGeometry ig = null;
1776

    
1777
        if (d == 2) {
1778
            ig = ShapeFactory.createPoint2D(x, y);
1779
        }
1780
        else {
1781
            ig = ShapeFactory.createPoint3D(x, y, z);
1782
        }
1783

    
1784
        return ig;
1785
    }
1786

    
1787
    /*
1788
    private boolean isActuallyACollection(JGeometry jg) {
1789
        int[] info = jg.getElemInfo();
1790

1791
        if (info == null) {
1792
            return false; // sdo_point
1793
        }
1794

1795
        int size = info.length / 3;
1796

1797
        if (size == 1) {
1798
            return false;
1799
        }
1800

1801
        if (size == 2) {
1802
            return ((info[1] % 1000) != (info[4] % 1000));
1803
        }
1804

1805
        int second = info[4] % 1000;
1806

1807
        for (int i = 2; i < size; i++) {
1808
            if ((info[(i * 3) + 1] % 1000) != second) {
1809
                return true;
1810
            }
1811
        }
1812

1813
        return false;
1814
    }
1815
    */
1816

    
1817
    private boolean isActuallyACollection(Datum[] the_data) {
1818
        int[] info = null;
1819

    
1820
        try {
1821
            ARRAY aux = (ARRAY) the_data[3];
1822

    
1823
            if (aux == null) {
1824
                return false;
1825
            }
1826

    
1827
            info = aux.getIntArray();
1828
        }
1829
        catch (SQLException se) {
1830
            logger.error("While checking collection: " + se.getMessage());
1831
            return false;
1832
        }
1833

    
1834
        if (info == null) {
1835
            return false; // sdo_point
1836
        }
1837

    
1838
        int size = info.length / 3;
1839

    
1840
        if (size == 1) {
1841
            return false;
1842
        }
1843

    
1844
        if (size == 2) {
1845
            return ((info[1] % 1000) != (info[4] % 1000)) &&
1846
            ( ! ((info[1] == 1005) && (info[4] == 2)) );
1847
        }
1848

    
1849
        int second = info[4] % 1000;
1850
        int item = 0;
1851

    
1852
        for (int i = 2; i < size; i++) {
1853
                item = info[(i * 3) + 1] % 1000;
1854
            if ((item != second) &&
1855
                            ( ! ((item == 5) && (second == 2)) )
1856
                            ) {
1857
                return true;
1858
            }
1859
        }
1860

    
1861
        return false;
1862
    }
1863

    
1864
    /*
1865
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1866
        int main_type = jg.getType();
1867

1868
        int[] all_info_array = jg.getElemInfo();
1869
        Object[] elems_info_aray = groupByElement(all_info_array);
1870
        double[] all_ords = jg.getOrdinatesArray();
1871
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1872
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1873

1874
        for (int i = 0; i < elems_info_aray.length; i++) {
1875
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1876
        }
1877

1878
        // _elems_info_aray, ords_of_groups
1879
        int no_of_elems = ords_of_groups.length;
1880
        IGeometry[] geoms = new IGeometry[no_of_elems];
1881

1882
        for (int i = 0; i < no_of_elems; i++) {
1883
            int[] item_info_array = (int[]) _elems_info_aray[i];
1884
            double[] item_ords = (double[]) ords_of_groups[i];
1885
            int gtype = (dim * 1000) + (item_info_array[1] % 1000);
1886

1887
            // if it's the first geometry, the type is the collection's main type (no?)
1888
            if (i == 0) {
1889
                gtype = main_type;
1890
            }
1891

1892
            JGeometry itemjg = null;
1893

1894
            if (tableHasSrid) {
1895
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1896
            }
1897
            else {
1898
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1899
            }
1900

1901
            geoms[i] = getFMapGeometry(itemjg, true);
1902
        }
1903

1904
        return new FGeometryCollection(geoms);
1905
    }
1906
    */
1907

    
1908
    private Datum[] updateIndexes(Datum[] info) {
1909
        int size = info.length / 3;
1910
        NUMBER[] resp = new NUMBER[3 * size];
1911

    
1912
        try {
1913
            int rest = info[0].intValue() - 1;
1914

    
1915
            for (int i = 0; i < size; i++) {
1916
                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1917
                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
1918
                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
1919
            }
1920
        }
1921
        catch (SQLException se) {
1922
            logger.error("Unexpected error: " + se.getMessage());
1923
        }
1924

    
1925
        return resp;
1926
    }
1927

    
1928
    private int[] updateIndexes(int[] info) {
1929
        int size = info.length / 3;
1930
        int[] resp = new int[3 * size];
1931
        int rest = info[0] - 1;
1932

    
1933
        for (int i = 0; i < size; i++) {
1934
            resp[3 * i] = info[3 * i] - rest;
1935
            resp[(3 * i) + 1] = info[(3 * i) + 1];
1936
            resp[(3 * i) + 2] = info[(3 * i) + 2];
1937
        }
1938

    
1939
        return resp;
1940
    }
1941

    
1942
    private int[] appendIntArrays(int[] head, int[] tail) {
1943
        int[] resp = new int[head.length + tail.length];
1944
        int hsize = head.length;
1945

    
1946
        for (int i = 0; i < hsize; i++) {
1947
            resp[i] = head[i];
1948
        }
1949

    
1950
        for (int i = 0; i < tail.length; i++) {
1951
            resp[hsize + i] = tail[i];
1952
        }
1953

    
1954
        return resp;
1955
    }
1956

    
1957
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
1958
        Datum[] resp = new Datum[head.length + tail.length];
1959
        int hsize = head.length;
1960

    
1961
        for (int i = 0; i < hsize; i++) {
1962
            resp[i] = head[i];
1963
        }
1964

    
1965
        for (int i = 0; i < tail.length; i++) {
1966
            resp[hsize + i] = tail[i];
1967
        }
1968

    
1969
        return resp;
1970
    }
1971

    
1972
    private int[] getNthGroupOfThree(int[] list, int n) {
1973
        int[] resp = new int[3];
1974
        resp[0] = list[3 * n];
1975
        resp[1] = list[(3 * n) + 1];
1976
        resp[2] = list[(3 * n) + 2];
1977

    
1978
        return resp;
1979
    }
1980

    
1981
    private Datum[] getNthGroupOfThree(Datum[] list, int n) {
1982
        Datum[] resp = new Datum[3];
1983
        resp[0] = list[3 * n];
1984
        resp[1] = list[(3 * n) + 1];
1985
        resp[2] = list[(3 * n) + 2];
1986

    
1987
        return resp;
1988
    }
1989

    
1990
    private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
1991
        Datum[] resp = new Datum[last_inc - first_inc + 1];
1992

    
1993
        for (int i = first_inc; i <= last_inc; i++) {
1994
            resp[i - first_inc] = all[i];
1995
        }
1996

    
1997
        return resp;
1998
    }
1999

    
2000
    private double[] getSubSet(double[] all, int first_inc, int last_inc) {
2001
        double[] resp = new double[last_inc - first_inc + 1];
2002

    
2003
        for (int i = first_inc; i <= last_inc; i++) {
2004
            resp[i - first_inc] = all[i];
2005
        }
2006

    
2007
        return resp;
2008
    }
2009

    
2010
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) throws SQLException {
2011
        Object[] resp = new Object[groups.length];
2012

    
2013
        if (resp.length == 1) {
2014
            resp[0] = all;
2015

    
2016
            return resp;
2017
        }
2018

    
2019
        int ind = 0;
2020
        Datum[] aux = (Datum[]) groups[1];
2021
        int _end = aux[0].intValue() - 2;
2022
        Datum[] ord_aux = getSubSet(all, 0, _end);
2023

    
2024
        int _start = _end + 1;
2025
        resp[ind] = ord_aux;
2026
        ind++;
2027

    
2028
        for (int i = 2; i < groups.length; i++) {
2029
            aux = (Datum[]) groups[i];
2030
            _end = aux[0].intValue() - 2;
2031
            ord_aux = getSubSet(all, _start, _end);
2032
            resp[ind] = ord_aux;
2033
            ind++;
2034
            _start = _end + 1;
2035
        }
2036

    
2037
        // last
2038
        _end = all.length - 1;
2039
        ord_aux = getSubSet(all, _start, _end);
2040
        resp[groups.length - 1] = ord_aux;
2041

    
2042
        return resp;
2043
    }
2044

    
2045
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2046
        Object[] resp = new Object[groups.length];
2047

    
2048
        if (resp.length == 1) {
2049
            resp[0] = all;
2050

    
2051
            return resp;
2052
        }
2053

    
2054
        int ind = 0;
2055
        int[] aux = (int[]) groups[1];
2056
        int _end = aux[0] - 2;
2057
        double[] ord_aux = getSubSet(all, 0, _end);
2058

    
2059
        int _start = _end + 1;
2060
        resp[ind] = ord_aux;
2061
        ind++;
2062

    
2063
        for (int i = 2; i < groups.length; i++) {
2064
            aux = (int[]) groups[i];
2065
            _end = aux[0] - 2;
2066
            ord_aux = getSubSet(all, _start, _end);
2067
            resp[ind] = ord_aux;
2068
            ind++;
2069
            _start = _end + 1;
2070
        }
2071

    
2072
        // last
2073
        _end = all.length - 1;
2074
        ord_aux = getSubSet(all, _start, _end);
2075
        resp[groups.length - 1] = ord_aux;
2076

    
2077
        return resp;
2078
    }
2079

    
2080
    private Object[] groupByElement(int[] all_elem) {
2081
        ArrayList resp = new ArrayList();
2082

    
2083
        int size = all_elem.length / 3;
2084

    
2085
        int[] aux = getNthGroupOfThree(all_elem, 0);
2086

    
2087
        int[] newaux;
2088
        int i = 1;
2089

    
2090
        while (i < size) {
2091
            newaux = getNthGroupOfThree(all_elem, i);
2092

    
2093
            if (newaux[0] == aux[0]) {
2094
                // aux[2] says how many components
2095
                for (int j = 0; j < aux[2]; j++) {
2096
                    aux = appendIntArrays(aux,
2097
                            getNthGroupOfThree(all_elem, j + i));
2098
                }
2099

    
2100
                resp.add(aux);
2101
                i = i + aux[2];
2102
                aux = getNthGroupOfThree(all_elem, i);
2103
            }
2104
            else {
2105
                if (newaux[1] == 2003) {
2106
                    aux = appendIntArrays(aux, newaux);
2107
                }
2108
                else {
2109
                    resp.add(aux);
2110
                    aux = getNthGroupOfThree(all_elem, i);
2111
                }
2112
            }
2113

    
2114
            i++;
2115
        }
2116

    
2117
        resp.add(aux);
2118

    
2119
        return resp.toArray();
2120
    }
2121

    
2122
    private Object[] groupByElement(Datum[] all_elem) {
2123
            
2124
            if (isSimpleCollectionOfLines(all_elem)) {
2125
                    Object[] r = new Object[1];
2126
                    r[0] = removeThreeFirst(all_elem);
2127
                    return r;
2128
            }
2129
            
2130
        ArrayList resp = new ArrayList();
2131

    
2132
        int size = all_elem.length / 3;
2133

    
2134
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2135

    
2136
        Datum[] newaux;
2137
        int i = 1;
2138
        boolean add_last_time = true;
2139

    
2140
        try {
2141
            while (i < size) {
2142
                newaux = getNthGroupOfThree(all_elem, i);
2143

    
2144
                if (newaux[0].intValue() == aux[0].intValue()) {
2145
                    // aux[2] says how many components
2146
                    for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
2147
                        aux = appendDatArrays(aux,
2148
                                getNthGroupOfThree(all_elem, j + i));
2149
                    }
2150

    
2151
                    resp.add(aux);
2152
                    i = i + ((NUMBER) aux[2]).intValue();
2153
                    if (i < size) { // in some cases (line collection, 4)
2154
                            aux = getNthGroupOfThree(all_elem, i);
2155
                    } else {
2156
                            add_last_time = false;
2157
                    }
2158
                }
2159
                else {
2160
                    if (((NUMBER) newaux[1]).intValue() == 2003) {
2161
                        aux = appendDatArrays(aux, newaux);
2162
                    } else {
2163
                        resp.add(aux);
2164
                        aux = getNthGroupOfThree(all_elem, i);
2165
                    }
2166
                }
2167

    
2168
                i++;
2169
            }
2170
        }
2171
        catch (SQLException se) {
2172
            logger.error("Unexpected error: " + se.getMessage());
2173
        }
2174

    
2175
        if (add_last_time) {
2176
                resp.add(aux);
2177
        }
2178

    
2179
        return resp.toArray();
2180
    }
2181

    
2182
    /*
2183
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2184
        Point2D p = _jgeom.getJavaPoint();
2185
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2186

2187
        return ig;
2188
    }
2189

2190
    private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2191
        Point2D[] pp = _jgeom.getJavaPoints();
2192
        int l = pp.length;
2193
        double[] x = new double[l];
2194
        double[] y = new double[l];
2195

2196
        for (int i = 0; i < l; i++) {
2197
            x[i] = pp[i].getX();
2198
            y[i] = pp[i].getY();
2199
        }
2200

2201
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2202

2203
        return ig;
2204
    }
2205

2206
    private IGeometry getJGeometryOther(JGeometry _jgeom) {
2207
        int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2208
        Shape shape = _jgeom.createShape();
2209
        GeneralPathX gpx = new GeneralPathX(shape);
2210
        IGeometry ig = null;
2211

2212
        switch (type) {
2213
        case FShape.LINE:
2214

2215
            FPolyline2D fpl = new FPolyline2D(gpx);
2216
            ig = ShapeFactory.createPolyline2D(gpx);
2217

2218
            break;
2219

2220
        case FShape.POLYGON:
2221

2222
            FPolygon2D fpg = new FPolygon2D(gpx);
2223
            ig = ShapeFactory.createPolygon2D(gpx);
2224

2225
            break;
2226
        }
2227

2228
        return ig;
2229
    }
2230
    */
2231

    
2232
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
2233
        /*
2234
         * Tipos en Oracle Spatial usando JGeometry
2235
         *
2236
         * GTYPE_COLLECTION collection geometry type
2237
         * GTYPE_CURVE curve geoemtry type
2238
         * GTYPE_MULTICURVE multi-curve geometry type
2239
         * GTYPE_MULTIPOINT multi-point geometry type
2240
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
2241
         * GTYPE_POINT point geometry type
2242
         * GTYPE_POLYGON  polygon geometry type
2243
         *
2244
         * Tipos gvSIG FShape
2245
         *
2246
         * NULL = 0;
2247
         * POINT = 1;
2248
         * LINE = 2;
2249
         * POLYGON = 4;
2250
         * TEXT = 8;
2251
         * MULTI = 16;
2252
         * MULTIPOINT = 32;
2253
         * CIRCLE = 64;
2254
         * ARC = 128;
2255
         * ELLIPSE=256;
2256
         * Z=512
2257
         */
2258
        switch (type) {
2259
        case JGeometry_GTYPE_POLYGON:
2260
        case JGeometry_GTYPE_MULTIPOLYGON:
2261
            return FShape.POLYGON;
2262

    
2263
        case JGeometry_GTYPE_CURVE:
2264
        case JGeometry_GTYPE_MULTICURVE:
2265
            return FShape.LINE;
2266
        }
2267

    
2268
        logger.error("Unhandled Oracle Spatial geometry type: " + type +
2269
            " (conversion returned FShape.NULL)");
2270

    
2271
        return FShape.NULL;
2272
    }
2273

    
2274
    private void cleanWhereClause() {
2275
        emptyWhereClause = false;
2276

    
2277
        String aux = getWhereClauseWithoutWhere();
2278

    
2279
        for (int i = 0; i < aux.length(); i++)
2280
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
2281
                return;
2282
            }
2283

    
2284
        getLyrDef().setWhereClause("");
2285
        emptyWhereClause = true;
2286
    }
2287

    
2288
    private String getValidViewConstructor(
2289
                    STRUCT _st,
2290
                    String ora_srid,
2291
                    boolean _hassrid,
2292
                    boolean _isgeocs) {
2293

    
2294
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
2295
            String resp = "";
2296
            if ((_hassrid) && (_isgeocs)) {
2297
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
2298
            } else {
2299
                    resp = sdo;
2300
            }
2301

    
2302
            return resp;
2303
    }
2304

    
2305
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2306
        String resp = "";
2307

    
2308
        if (isGeogCS) {
2309
            String vport = "sdo_filter(" + geoColName +
2310
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
2311
                "), 'querytype=window') = 'TRUE'";
2312

    
2313
                resp = "select " + getStandardSelectExpression() + ", c." +
2314
                    geoColName + " from " + getTableName() + " c where ";
2315
                if (idsLoadWhere.length() > 0) {
2316
                        resp = resp + " (" + idsLoadWhere + ") AND ";
2317
                }
2318
                resp = resp + "(" + vport + ")";
2319
        }
2320
        else {
2321
                resp = "select " + getStandardSelectExpression() + ", c." +
2322
                    geoColName + " from " + getTableName() + " c where ";
2323
                if (idsLoadWhere.length() > 0) {
2324
                        resp = resp + " (" + idsLoadWhere + ") AND ";
2325
                }
2326
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
2327
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
2328
        }
2329

    
2330
//        return "select " + getStandardSelectExpression() + ", c." +
2331
//        geoColName + " from " + getTableName() + " c";
2332
        return resp;
2333
    }
2334

    
2335
    public void setWorkingArea(Rectangle2D rect) {
2336
    }
2337

    
2338
    private void setWAStructt() {
2339
    }
2340

    
2341
    private Geometry shapeToGeometry(Shape shp) {
2342
        if (shp == null) {
2343
            return null;
2344
        }
2345

    
2346
        int type = FShape.POLYGON;
2347

    
2348
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2349
            type = FShape.LINE;
2350
        }
2351

    
2352
        if (shp instanceof FPoint2D) {
2353
            type = FShape.POINT;
2354
        }
2355

    
2356
        if (shp instanceof FMultiPoint2D) {
2357
            type = FShape.MULTIPOINT;
2358
        }
2359

    
2360
        GeneralPathX wagp = new GeneralPathX(shp);
2361
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2362

    
2363
        return FConverter.java2d_to_jts(fwagp);
2364
    }
2365

    
2366
    /*
2367
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2368
        Shape shape = _jg.createShape();
2369

2370
        return shape.getBounds2D();
2371
    }
2372
    */
2373

    
2374
    private void printStruct(STRUCT st) {
2375
        logger.debug("----------------------------------------------");
2376

    
2377
        try {
2378
            Object[] att = st.getAttributes();
2379
            int l = att.length;
2380

    
2381
            for (int i = 0; i < l; i++) {
2382
                    logger.debug("ATT " + i + ": " + att[i].toString());
2383
            }
2384
        }
2385
        catch (Exception ex) {
2386
                logger.debug(
2387
                "- Error ---------------------------------------");
2388
        }
2389

    
2390
        logger.debug("----------------------------------------------");
2391
    }
2392

    
2393
    private static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
2394
        boolean isView, boolean _isGeogCS, String _oracleSRID, IConnection __conn) {
2395
        Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2396
        Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2397

    
2398
        if ((_isGeogCS) && (isView)) {
2399
            c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2400
            c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2401
        }
2402

    
2403
        STRUCT resp = null;
2404

    
2405
        try {
2406
            // System.out.println("ABIERTA: " + (!conn.isClosed()));
2407
            // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2408
            // Object[] old_obj = resp.getAttributes();
2409
            int size = 5;
2410
            Object[] new_obj = new Object[size];
2411

    
2412
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2413
            new_obj[0] = new NUMBER(2003);
2414

    
2415
            if (hasSrid) {
2416
                new_obj[1] = new NUMBER(_oracleSRID);
2417
            }
2418
            else {
2419
                new_obj[1] = null;
2420
            }
2421

    
2422
            new_obj[2] = null;
2423

    
2424
            NUMBER[] elem_info = new NUMBER[3];
2425
            elem_info[0] = new NUMBER(1);
2426
            elem_info[1] = new NUMBER(1003);
2427
            elem_info[2] = new NUMBER(3);
2428
            new_obj[3] = elem_info;
2429

    
2430
            NUMBER[] ords = null;
2431
            ords = new NUMBER[4];
2432
            ords[0] = new NUMBER(c1.getX());
2433
            ords[1] = new NUMBER(c1.getY());
2434
            ords[2] = new NUMBER(c2.getX());
2435
            ords[3] = new NUMBER(c2.getY());
2436
            new_obj[4] = ords;
2437

    
2438
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2439
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2440
                            ((ConnectionJDBC)__conn).getConnection());
2441

    
2442
            resp = new STRUCT(dsc,((ConnectionJDBC)__conn).getConnection(), new_obj);
2443
        }
2444
        catch (Exception ex) {
2445
            logger.error("Error while creating rect struct: " +
2446
                ex.getMessage(), ex);
2447
        }
2448

    
2449
        return resp;
2450
    }
2451

    
2452
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2453
        boolean hasSrid) throws ReadDriverException {
2454
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
2455
        String main_sel = "";
2456

    
2457
        if (fixsql == null) {
2458
            // main_sel = getMainSelect3(var_name);
2459
                String idswhere = getIdsQueryWhereClause(false);
2460
            main_sel = getMainSelect(sdo_intersect, idswhere);
2461
        }
2462
        else {
2463
            main_sel = fixsql;
2464
        }
2465

    
2466
        logger.debug("MAIN SEL = " + main_sel);
2467

    
2468
        ResultSet _rs = null;
2469
        Statement _stmnt = null;
2470
        Object[] _resp = new Object[2];
2471

    
2472
        try {
2473
            _stmnt = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
2474
                    ResultSet.CONCUR_READ_ONLY);
2475
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2476
            _stmnt.setFetchSize(FETCH_SIZE);
2477

    
2478
            _rs = _stmnt.executeQuery(main_sel);
2479

    
2480
            // stmnt.close();
2481
        }
2482
        catch (SQLException se) {
2483
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
2484
                se);
2485
            throw new ReadDriverException(getName(), se);
2486
        }
2487

    
2488
        // this method returns the statement too, so that it can be closed afterwards
2489
        _resp[0] = _rs;
2490
        _resp[1] = _stmnt;
2491

    
2492
        return _resp;
2493
    }
2494

    
2495
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2496
        String resp = "";
2497

    
2498
        try {
2499
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2500
            String mdsys_sdo_ordinate_array = "";
2501
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2502

    
2503
            for (int i = 0; i < vertices.length; i++) {
2504
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2505
                    vertices[i].doubleValue() + ", ";
2506
            }
2507

    
2508
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2509
                    mdsys_sdo_ordinate_array.length() - 2);
2510
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2511
                mdsys_sdo_ordinate_array + ")";
2512

    
2513
            String aux = "";
2514

    
2515
            if (hasSrid) {
2516
                aux = oracleSRID;
2517

    
2518
                if (_isGeogCS) {
2519
                    aux = "0";
2520
                }
2521
            }
2522
            else {
2523
                aux = "null";
2524
            }
2525

    
2526
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
2527
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
2528
                ")";
2529
        }
2530
        catch (Exception ex) {
2531
                logger.error("While getting sdo contructor: " +
2532
                ex.getMessage());
2533
        }
2534

    
2535
        return resp;
2536
    }
2537

    
2538
    private String getIdsQueryWhereClause(boolean with_where) {
2539
                String resp = "";
2540

    
2541
                String _where = "";
2542
                if (with_where) _where = " where ";
2543

    
2544
                if (workingAreaInTablesCSStruct == null) {
2545
                        if (emptyWhereClause) {
2546
                                // return "select rowid from " + getTableName();
2547
                        } else {
2548
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
2549
                                                + ")";
2550
                        }
2551
                } else {
2552
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
2553
                                        oracleSRID, tableHasSrid, isGeogCS);
2554

    
2555
                        if (emptyWhereClause) {
2556
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
2557
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2558
                        } else {
2559
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
2560
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
2561
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2562
                        }
2563
                }
2564

    
2565
                // resp = resp + " order by rowid";
2566
                return resp;
2567
        }
2568

    
2569
    public String getIdAndElemInfoFullResulltSetQuery() {
2570
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
2571
            getTableName() + " c";
2572

    
2573
        resp = resp + getIdsQueryWhereClause(true);
2574
        return resp;
2575
    }
2576

    
2577
    private String getSearchId() {
2578
        if (emptyWhereClause) {
2579
            return "select " + getStandardSelectExpression() + ", c." +
2580
            geoColName + " from " + getTableName() + " c where rowid = ?";
2581
        }
2582
        else {
2583
            return "select " + getStandardSelectExpression() + ", c." +
2584
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
2585
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
2586
        }
2587
    }
2588

    
2589
    public int getShapeType() {
2590
        return shapeType;
2591
    }
2592
    
2593
    public void setShapeType(int t) {
2594
        shapeType = t;
2595
    }
2596
    
2597

    
2598
    private String getWhereClauseWithoutWhere() {
2599
        String resp = "";
2600
        String old = getLyrDef().getWhereClause();
2601
        resp = old;
2602

    
2603
        if (old.length() <= 6) {
2604
            return old;
2605
        }
2606

    
2607
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2608
            resp = resp.substring(6, resp.length());
2609
        }
2610

    
2611
        return resp;
2612
    }
2613

    
2614
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2615
        if (r1.getMaxX() <= r2.getMinX()) {
2616
            return null;
2617
        }
2618

    
2619
        if (r2.getMaxX() <= r1.getMinX()) {
2620
            return null;
2621
        }
2622

    
2623
        if (r1.getMaxY() <= r2.getMinY()) {
2624
            return null;
2625
        }
2626

    
2627
        if (r2.getMaxY() <= r1.getMinY()) {
2628
            return null;
2629
        }
2630

    
2631
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2632
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2633
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2634
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2635

    
2636
        double w = maxx - minx;
2637
        double h = maxy - miny;
2638

    
2639
        return new Rectangle2D.Double(minx, miny, w, h);
2640
    }
2641

    
2642
    private static int maxSizeForFieldType(int _type) {
2643
        switch (_type) {
2644
        case Types.VARCHAR:
2645
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2646

    
2647
        case Types.LONGVARCHAR:
2648
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2649
        }
2650

    
2651
        return -1;
2652
    }
2653

    
2654
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2655
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2656

    
2657
        switch (fieldDesc.getFieldType()) {
2658
        case Types.SMALLINT:
2659
            aux = "NUMBER(5, 0)";
2660

    
2661
            break;
2662

    
2663
        case Types.INTEGER:
2664
            aux = "NUMBER(10, 0)";
2665

    
2666
            break;
2667

    
2668
        case Types.BIGINT:
2669
            aux = "NUMBER(38, 0)";
2670

    
2671
            break;
2672

    
2673
        case Types.BOOLEAN:
2674
            aux = "NUMBER(1, 0)";
2675

    
2676
            break;
2677

    
2678
        case Types.DECIMAL:
2679
            aux = "NUMBER";
2680

    
2681
            break;
2682

    
2683
        case Types.NUMERIC:
2684
            aux = "NUMBER";
2685

    
2686
            break;
2687

    
2688
        case Types.DOUBLE:
2689
            aux = "FLOAT";
2690

    
2691
            break;
2692

    
2693
        case Types.FLOAT:
2694
            aux = "FLOAT";
2695

    
2696
            break;
2697

    
2698
        case Types.CHAR:
2699
            aux = "CHAR(1 BYTE)";
2700

    
2701
            break;
2702

    
2703
        case Types.VARCHAR:
2704
            aux = "NVARCHAR2(" + nvarchar2Limited(fieldDesc.getFieldLength()) + ")";
2705

    
2706
            break;
2707

    
2708
        case Types.LONGVARCHAR:
2709
            aux = "NVARCHAR2(" + nvarchar2Limited(fieldDesc.getFieldLength()) + ")";
2710

    
2711
            break;
2712
        }
2713

    
2714
        return aux;
2715
    }
2716

    
2717
    // -----------------------------------------------------------
2718
    // -----------------------------------------------------------
2719
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2720
        return "DROP TABLE " + dbLayerDef.getTableName() +
2721
        " CASCADE CONSTRAINTS";
2722
    }
2723

    
2724
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2725
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2726

    
2727
        String type = "";
2728
        String name = "";
2729
        String table_name = dbLayerDef.getTableName().toUpperCase();
2730

    
2731
        String resp = "CREATE TABLE " + table_name + " ( ";
2732

    
2733
        for (int i = 0; i < flds.length; i++) {
2734
            name = flds[i].getFieldName();
2735

    
2736
            // -------------- FORBIDDEN FIELD NAMES -----------------
2737
            if (!isOracleAllowedFieldname(name)) {
2738
                continue;
2739
            }
2740

    
2741
            // ------------------------------------------------------
2742
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
2743
            }
2744
            else {
2745
                name = getValidOracleID(name, i, false);
2746
                resp = resp + "\"" + name + "\" ";
2747
                type = fieldTypeToSqlStringType(flds[i]);
2748
                resp = resp + type + ", ";
2749
            }
2750
        }
2751

    
2752
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2753
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2754
        resp = resp + ", ";
2755

    
2756
        String pk = "CONSTRAINT " + getDerivedNAme(table_name, "PK") +
2757
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE +
2758
            "\") ENABLE";
2759

    
2760
        resp = resp + pk + " )";
2761

    
2762
        return resp;
2763
    }
2764

    
2765
    private static String getDerivedNAme(String tname, String suffix) {
2766

    
2767
            int ind = tname.lastIndexOf(".");
2768
            if (ind == -1) {
2769

    
2770
                    int l = Math.min(28, tname.length());
2771
                    return tname.substring(0, l) + "_" + suffix;
2772

    
2773
            } else {
2774

    
2775
                    String pre = tname.substring(0, ind);
2776
                    String post = tname.substring(ind + 1, tname.length());
2777
                    int lpost = Math.min(24, post.length());
2778
                    int lpre = Math.min(3, pre.length());
2779
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
2780
            }
2781

    
2782
    }
2783

    
2784
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2785
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
2786
            " ON " + dbLayerDef.getTableName() + " (\"" +
2787
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
2788
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2789

    
2790
        return resp;
2791
    }
2792

    
2793
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2794

    
2795
            String tname = dbLayerDef.getTableName();
2796
            int ind = tname.lastIndexOf(".");
2797
            if (ind != -1) {
2798
                    String schema = tname.substring(0, ind);
2799
                    tname = tname.substring(ind + 1, tname.length());
2800
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
2801
            " WHERE TABLE_NAME = '" + tname + "'";
2802

    
2803
            } else{
2804
            return "DELETE FROM " + USER_ORACLE_GEOMETADATA_VIEW +
2805
            " WHERE TABLE_NAME = '" + tname + "'";
2806
            }
2807
    }
2808

    
2809
    /**
2810
     * UTility method to get the SQL sentence needed to update the geographic metadata table
2811
     * with a new bounding box and SRS
2812
     *
2813
     * @param tName table name
2814
     * @param ora_srid new SRS
2815
     * @param bbox new bounding box
2816
     * @param dim geometries dimension
2817
     * @param withsrid False if the SRS is set to NULL. True otherwise.
2818
     * @return the SQL sentence to perform the update
2819
     */
2820
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
2821
        Rectangle2D bbox, int dim, boolean withsrid) {
2822
            
2823
        String[] dim_name = new String[dim];
2824
        double tolerance = 0.5;
2825
        
2826
        String _ora_srid = ora_srid;
2827
        if (_ora_srid == null) _ora_srid = "NULL";
2828

    
2829
        if (_ora_srid.compareTo(GEODETIC_SRID) == 0) {
2830
            dim_name[0] = "LONGITUDE";
2831
            dim_name[1] = "LATITUDE";
2832
        }
2833
        else {
2834
            dim_name[0] = "X";
2835
            dim_name[1] = "Y";
2836

    
2837
            if (dim > 2) {
2838
                dim_name[2] = "Z";
2839

    
2840
                if (dim > 3) {
2841
                    dim_name[3] = "T";
2842
                }
2843
            }
2844
        }
2845
        
2846
        double minx = bbox.getMinX();
2847
        double miny = bbox.getMinY();
2848
        double maxx = bbox.getMaxX();
2849
        double maxy = bbox.getMaxY();
2850
        
2851
        String resp = "INSERT INTO " + USER_ORACLE_GEOMETADATA_VIEW + " " +
2852
            " ( TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
2853
            + "'" + tName + "', "
2854
            + "'" + DEFAULT_GEO_FIELD + "', " +
2855
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2856
            minx + ", " + maxx + ", " + tolerance + " ), " +
2857
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + miny + ", " +
2858
            maxy + ", " + tolerance + " ))";
2859

    
2860
        if (dim > 2) {
2861
            resp = resp.substring(0, resp.length() - 1) + ",";
2862
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
2863
                "', 0.0, 100.0, " + tolerance + " ))";
2864

    
2865
            if (dim > 3) {
2866
                resp = resp.substring(0, resp.length() - 1) + ",";
2867
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
2868
                    "', 0.0, 100.0, " + tolerance + " ))";
2869
            }
2870
        }
2871

    
2872
        if (withsrid) {
2873
            resp = resp + ", " + _ora_srid + " )";
2874
        }
2875
        else {
2876
            resp = resp + ", NULL )";
2877
        }
2878

    
2879
        return resp;
2880
    }
2881

    
2882
    /**
2883
     * Gets the SQL sentence to perform an insertion.
2884
     *
2885
     * @param feat feature to be added
2886
     * @param dbLayerDef layer definition
2887
     * @param rowInd row index
2888
     * @param _geoColName geometry field name
2889
     * @return the SQL sentence to perform the insertion
2890
     */
2891
    public static String getRowInsertSql(IFeature feat,
2892
        DBLayerDefinition dbLayerDef, int rowInd,
2893
        String _geoColName,
2894
        String geo_val) {
2895
            
2896
        String name = "";
2897
        int ftype = -1;
2898
        String aux_orig = "";
2899
        String aux_limited = "";
2900
        String aux_quotes_ok = "";
2901

    
2902
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2903

    
2904
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
2905

    
2906
        for (int i = 0; i < fieldsDescr.length; i++) {
2907
            name = fieldsDescr[i].getFieldName();
2908
            ftype = fieldsDescr[i].getFieldType();
2909

    
2910
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2911
            if (!isOracleAllowedFieldname(name)) continue;
2912
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2913
            // ------------------------------------------------------
2914
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2915
            }
2916
            else {
2917
                name = getValidOracleID(name, i, false);
2918
                resp = resp + "\"" + name + "\"" + " , ";
2919
            }
2920
        }
2921

    
2922
        resp = resp + _geoColName + " ) VALUES ( ";
2923

    
2924
        for (int i = 0; i < fieldsDescr.length; i++) {
2925
            name = fieldsDescr[i].getFieldName();
2926
            ftype = fieldsDescr[i].getFieldType();
2927

    
2928
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2929
            if (!isOracleAllowedFieldname(name)) continue;
2930
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2931
            // ------------------------------------------------------
2932
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2933

    
2934
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2935
            }
2936
            else {
2937
                if (name.compareTo(OracleSpatialDriver.DEFAULT_ID_FIELD_CASE_SENSITIVE) == 0) {
2938
                    resp = resp + rowInd + " , ";
2939
                }
2940
                else {
2941
                    Value attValue = feat.getAttribute(i);
2942

    
2943
                    if (attValue.toString() == null) {
2944
                        resp = resp + "NULL , ";
2945
                    }
2946
                    else {
2947
                        if (sur.length() > 0) {
2948
                            aux_orig = attValue.toString();
2949
                            aux_limited = cropStringValue(aux_orig, i,
2950
                                    fieldsDescr);
2951
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2952

    
2953
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2954
                        }
2955
                        else {
2956
                            String _aux = attValue.toString();
2957

    
2958
                            if (_aux.length() == 0) {
2959
                                _aux = "NULL";
2960
                            }
2961

    
2962
                            resp = resp + _aux + " , ";
2963
                        }
2964
                    }
2965
                }
2966
            }
2967
        }
2968

    
2969
        resp = resp + " " + geo_val + " )";
2970
        /*
2971
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
2972
                        + "2002, NULL, NULL,"
2973
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
2974
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
2975
                        + "), ? )";
2976

2977
        resp = resp + " " + test + " )";
2978
        */
2979
        return resp;
2980
    }
2981

    
2982
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
2983

    
2984
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
2985
                    return true;
2986
            }
2987

    
2988
            if ((ftype == Types.BINARY)
2989
                || (ftype == Types.ARRAY)
2990
                || (ftype == Types.BLOB)
2991
                || (ftype == Types.CLOB)
2992
                || (ftype == Types.STRUCT)
2993
            ) {
2994
                    return false;
2995
            }
2996
                return true;
2997
        }
2998

    
2999
        /**
3000
     * Gets the SQL sentence to perform an update.
3001
     *
3002
     * @param feat feature to be updated
3003
     * @param dbLayerDef layer definition
3004
     * @param rowInd row index
3005
     * @param geoFieldName geometry field name
3006
     * @return the SQL sentence to perform the update
3007
     */
3008
    public static String getRowUpdateSql(IFeature feat,
3009
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
3010
        String name = "";
3011
        String aux_orig = "";
3012
        String aux_limited = "";
3013
        String aux_quotes_ok = "";
3014

    
3015
        Value[] atts = feat.getAttributes();
3016
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
3017

    
3018
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
3019

    
3020
        for (int i = 0; i < _fieldsDescr.length; i++) {
3021
            name = _fieldsDescr[i].getFieldName();
3022

    
3023
            // -------------- FORBIDDEN FIELD NAMES -----------------
3024
            if (!isOracleAllowedFieldname(name)) {
3025
                logger.info("Field: " + name + " will not be updated.");
3026
                continue;
3027
            }
3028

    
3029
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
3030
                        geoFieldName)) {
3031
                logger.info("Field: " + name + " will not be updated (it's a struct).");
3032
                continue;
3033
            }
3034

    
3035
            // ------------------------------------------------------
3036
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
3037
                // resp = resp + "\"" + name + "\"" + " = ?, ";
3038
            }
3039
            else {
3040
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
3041
                aux_orig = atts[i].toString();
3042
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
3043
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
3044
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
3045
                    sur + ", ";
3046
            }
3047
        }
3048

    
3049
        resp = resp + "\"" + geoFieldName + "\" = ?";
3050
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
3051

    
3052
        return resp;
3053
    }
3054

    
3055
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
3056
        String geoname) {
3057
        if (ftype == Types.STRUCT) {
3058
            if (fldname.compareToIgnoreCase(geoname) != 0) {
3059
                return true;
3060
            }
3061
        }
3062

    
3063
        return false;
3064
    }
3065

    
3066
    /**
3067
     * Gets the SQL sentence to perform a deletion.
3068
     *
3069
     * @param dbLayerDef layer definition
3070
     * @param id ROWID of the record to be deleted
3071
     * @return the SQL sentence to perform the deletion
3072
     */
3073
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
3074
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
3075
        resp = resp + " WHERE ROWID ='" + id + "'";
3076

    
3077
        return resp;
3078
    }
3079

    
3080
    private static String cropStringValue(String orig_val, int i,
3081
        FieldDescription[] _flds) {
3082
            
3083
        if (orig_val == null) {
3084
            return "NULL";
3085
        }
3086
        
3087
        if (NumberUtilities.isNumeric(_flds[i].getFieldType())
3088
                    && (orig_val.length() == 0)) {
3089
                    return "NULL";
3090
        }
3091

    
3092
        int tpe = _flds[i].getFieldType();
3093
        int max_size = maxSizeForFieldType(tpe);
3094

    
3095
        if (max_size == -1) {
3096
            return orig_val;
3097
        }
3098

    
3099
        int or_size = orig_val.length();
3100

    
3101
        if (or_size <= max_size) {
3102
            return orig_val;
3103
        }
3104

    
3105
        return orig_val.substring(0, max_size);
3106
    }
3107

    
3108
    private static String avoidQuoteProblem(String str) {
3109
        return str.replaceAll("'", "''");
3110
    }
3111

    
3112
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3113
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3114
            return "";
3115
        }
3116

    
3117
        return "'";
3118
    }
3119

    
3120
    /**
3121
     * Utility function to translate a SRS code from EPSG to Oracle.
3122
     * Uses a datasource based on a DBF file.
3123
     *
3124
     * @param epsg the EPSG code
3125
     * @return the Oracle code
3126
     */
3127
    public static String epsgSridToOracleSrid(String _epsg) throws Exception {
3128
            
3129
            String epsg = removePrefix(_epsg);
3130
            
3131
        String resp = "8307";
3132

    
3133
        // --------------------------------------------
3134
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3135
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3136
        DataSource ds = null;
3137

    
3138
        try {
3139
            ds = LayerFactory.getDataSourceFactory()
3140
                             .executeSQL(sql,
3141
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3142

    
3143
            if (ds.getRowCount() == 0) {
3144
                logger.error("EPSG code not found in table: " + epsg);
3145
                throw new Exception("Unknown EPSG: " + epsg);
3146
            }
3147

    
3148
            if (ds.getRowCount() > 1) {
3149
                logger.error("===============");
3150
                logger.error(
3151
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
3152
                    epsg);
3153

    
3154
                for (int i = 0; i < ds.getRowCount(); i++) {
3155
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3156

    
3157
                    if (i == 0) {
3158
                        resp = "" + aux;
3159
                    }
3160

    
3161
                    logger.error("" + aux);
3162
                }
3163

    
3164
                logger.error("===============");
3165

    
3166
                return resp;
3167
            }
3168

    
3169
            resp = "" +
3170
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3171
        }
3172
        catch (Exception pe) {
3173
            logger.error("Error with SQL statement. " + pe.getMessage());
3174
        }
3175

    
3176
        return resp;
3177
    }
3178

    
3179
    /**
3180
     * Utility function to translate a SRS code from Oracle to EPSG.
3181
     * Uses a datasource based on a DBF file.
3182
     *
3183
     * @param ora the Oracle code
3184
     * @return the EPSG code
3185
     */
3186
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3187
            
3188
            if (ora == null) return null;
3189
            
3190
        String resp = "4326";
3191

    
3192
        // --------------------------------------------
3193
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3194
            " where ORACLE = " + ora + ";";
3195
        DataSource ds = null;
3196

    
3197
        try {
3198
            ds = LayerFactory.getDataSourceFactory()
3199
                             .executeSQL(sql,
3200
                    DataSourceFactory.AUTOMATIC_OPENING);
3201

    
3202
            if (ds.getRowCount() == 0) {
3203
                logger.error("Oracle Spatial code not found in table: " + ora);
3204
                throw new Exception("Unknown Oracle code: " + ora);
3205
            }
3206

    
3207
            if (ds.getRowCount() > 1) {
3208
                logger.error("===============");
3209
                logger.error(
3210
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3211
                    ora);
3212

    
3213
                for (int i = 0; i < ds.getRowCount(); i++) {
3214
                    String aux = "" +
3215
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3216

    
3217
                    if (i == 0) {
3218
                        resp = aux;
3219
                    }
3220

    
3221
                    logger.error("" + aux);
3222
                }
3223

    
3224
                logger.error("===============");
3225

    
3226
                return resp;
3227
            }
3228

    
3229
            resp = "" +
3230
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3231
        }
3232
        catch (Exception pe) {
3233
            logger.error("Error with SQL statement. " + pe.getMessage());
3234
        }
3235

    
3236
        return resp;
3237
    }
3238

    
3239
    /**
3240
     * This methos creates the datasource used to translate the SRS codes:
3241
     * EPSG <--> Oracle.
3242
     *
3243
     * It's called from several places, so checks that the datasource does not exist.
3244
     */
3245

    
3246

    
3247
    /**
3248
     * Utility method to get a valid Oracle identifier (in terms of length)
3249
     *
3250
     * @param str Proposed string
3251
     * @param ind field index of the given field name (used by the method to
3252
     * improve the renaming)
3253
     * @return an acceptable oracle identifier.
3254
     */
3255
    public static String getValidOracleID(String _str, int ind, boolean force_uppercase) {
3256
            
3257
            String str = _str;
3258
            if (force_uppercase) str = _str.toUpperCase();
3259
            
3260
        if (str.length() <= MAX_ID_LENGTH) {
3261
            return str;
3262
        }
3263

    
3264
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3265
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3266
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3267
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3268
        resp = resp + "_" + (ind % 1000);
3269

    
3270
        return resp;
3271
    }
3272

    
3273
    private static ArrayList ensureSensibleShell(ArrayList cc) {
3274
        if (sameCoordinate((Coordinate) cc.get(0),
3275
                    (Coordinate) cc.get(cc.size() - 1))) {
3276
            if (cc.size() == 2) {
3277
                ArrayList resp = new ArrayList();
3278
                resp.add(cc.get(0));
3279

    
3280
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3281
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3282
                resp.add(newcoo);
3283

    
3284
                newcoo = new Coordinate((Coordinate) cc.get(0));
3285
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3286
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
3287
                resp.add(newcoo);
3288

    
3289
                resp.add(cc.get(0));
3290

    
3291
                return resp;
3292
            }
3293

    
3294
            if (cc.size() == 3) {
3295
                cc.remove(1);
3296

    
3297
                return ensureSensibleShell(cc);
3298
            }
3299

    
3300
            return cc;
3301
        }
3302
        else {
3303
            cc.add(cc.get(0));
3304

    
3305
            return cc;
3306
        }
3307
    }
3308

    
3309
    private static ArrayList ensureSensibleHole(ArrayList cc) {
3310
        if (sameCoordinate((Coordinate) cc.get(0),
3311
                    (Coordinate) cc.get(cc.size() - 1))) {
3312
            if (cc.size() == 2) {
3313
                ArrayList resp = new ArrayList();
3314
                resp.add(cc.get(0));
3315

    
3316
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3317
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3318
                resp.add(newcoo);
3319

    
3320
                newcoo = new Coordinate((Coordinate) cc.get(0));
3321
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3322
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3323
                resp.add(newcoo);
3324

    
3325
                resp.add(cc.get(0));
3326

    
3327
                return resp;
3328
            }
3329

    
3330
            if (cc.size() == 3) {
3331
                cc.remove(1);
3332

    
3333
                return ensureSensibleHole(cc);
3334
            }
3335

    
3336
            return cc;
3337
        }
3338
        else {
3339
            cc.add(cc.get(0));
3340

    
3341
            return cc;
3342
        }
3343
    }
3344

    
3345
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
3346
        if (cc.size() == 2) {
3347
            if (sameCoordinate((Coordinate) cc.get(0),
3348
                        (Coordinate) cc.get(cc.size() - 1))) {
3349
                ArrayList resp = new ArrayList();
3350
                resp.add(cc.get(0));
3351

    
3352
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3353
                newc.x = newc.x + IRRELEVANT_DISTANCE;
3354
                resp.add(newc);
3355

    
3356
                return resp;
3357
            }
3358
        }
3359

    
3360
        return cc;
3361
    }
3362

    
3363
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3364
        if (c1.x != c2.x) {
3365
            return false;
3366
        }
3367

    
3368
        if (c1.y != c2.y) {
3369
            return false;
3370
        }
3371

    
3372
        return true;
3373
    }
3374

    
3375
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3376
        if (cc.size() == 2) {
3377
            return null;
3378
        }
3379

    
3380
        if (cc.size() == 3) {
3381
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3382
                return null;
3383
            }
3384

    
3385
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3386
                return null;
3387
            }
3388

    
3389
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3390
                return null;
3391
            }
3392

    
3393
            cc.add(cc.get(0));
3394

    
3395
            return cc;
3396
        }
3397

    
3398
        if (!sameCoordinate((Coordinate) cc.get(0),
3399
                    (Coordinate) cc.get(cc.size() - 1))) {
3400
            cc.add(cc.get(0));
3401
        }
3402

    
3403
        return cc;
3404
    }
3405

    
3406
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3407
        Coordinate[] p = new Coordinate[4];
3408
        p[0] = c;
3409

    
3410
        Coordinate nc = new Coordinate(c);
3411
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3412

    
3413
        Coordinate nc2 = new Coordinate(nc);
3414
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3415
        p[1] = nc;
3416
        p[2] = nc2;
3417
        p[3] = new Coordinate(c);
3418

    
3419
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3420
        LinearRing ls = new LinearRing(cs, geomFactory);
3421
        Polygon po = new Polygon(ls, null, geomFactory);
3422
        Polygon[] pos = new Polygon[1];
3423
        pos[0] = po;
3424

    
3425
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3426

    
3427
        return mpo;
3428
    }
3429

    
3430
    public String getSourceProjection(IConnection conn, DBLayerDefinition lyrDef) {
3431
            
3432
            String resp = null;
3433
        try {
3434
            Statement _st = ((ConnectionJDBC) conn).getConnection().createStatement();
3435
            String[] tokens = lyrDef.getName().split("\\u002E", 2);
3436
            String qry;
3437
            if (tokens.length > 1) {
3438
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
3439
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
3440
                tokens[1] + "'";
3441
            } else {
3442
                    qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
3443
                " where TABLE_NAME = " + "'" + lyrDef.getName() + "'";
3444
            }
3445
            ResultSet _rs = _st.executeQuery(qry);
3446

    
3447
            if (_rs.next()) {
3448
                String aux = getOracleSridFromCurrentRecord(_rs);
3449
                try {
3450
                                        resp = oracleSridToEpsgSrid(aux);
3451
                                } catch (Exception e) {
3452
                                        logger.error("Unknown oracle SRID: " + aux);
3453
                                }
3454
            } else {
3455
                    
3456
            }
3457
        } catch (Exception ex) {
3458
                logger.error("While getting Source Projection: " + ex.getMessage());
3459
        }
3460
        
3461
        if (resp != null) {
3462
                return resp;
3463
        } else {
3464
                return getDestProjection();
3465
        }
3466
        
3467
    }
3468

    
3469
    public String getDestProjection() {
3470
        return removePrefix(destProj);
3471
    }
3472

    
3473
    public void setDestProjection(String toEPSG) {
3474
        destProj = toEPSG;
3475
        try {
3476
                        destProjOracle = epsgSridToOracleSrid(destProj);
3477
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3478

    
3479
                } catch (Exception e) {
3480
                        logger.error("Unknown EPSG code: " + destProj);
3481
                        destProjOracle = oracleSRID;
3482
                        isDestGeogCS = false;
3483
                }
3484

    
3485
    }
3486

    
3487
    public String getDestProjectionOracleCode() {
3488
            return destProjOracle;
3489
    }
3490

    
3491
    public boolean getIsDestProjectionGeog() {
3492
            return isDestGeogCS;
3493
    }
3494

    
3495
    public String getTableProjectionOracleCode() {
3496
            return oracleSRID;
3497
    }
3498

    
3499
    public boolean canReproject(String toEPSGdestinyProjection) {
3500
        return false;
3501
    }
3502

    
3503
    /**
3504
     * Utility function. Says whether a given field name can be a user field name
3505
     * or not (for example, "ROWID" is not a valid one because it's a system
3506
     * reserved word).
3507
     *
3508
     * @param str proposed firld name
3509
     * @return whether it is valid or not for Oracle databases
3510
     */
3511
    private static boolean isOracleAllowedFieldname(String str) {
3512
        if (str.compareToIgnoreCase("rowid") == 0) {
3513
            return false;
3514
        }
3515

    
3516
        if (str.compareToIgnoreCase("rownum") == 0) {
3517
            return false;
3518
        }
3519

    
3520
        return true;
3521
    }
3522

    
3523
    public Hashtable getHashRelate() {
3524
        return hashRelate;
3525
    }
3526

    
3527
    public void setHashRelate(Hashtable m) {
3528
        hashRelate = m;
3529
    }
3530

    
3531
    public void setNumReg(int n) {
3532
        numReg = n;
3533
    }
3534

    
3535
    private int[] getRandomSample(int maxn_one_based, int n) {
3536
        int[] resp = new int[n];
3537

    
3538
        if (maxn_one_based <= n) {
3539
            resp = new int[maxn_one_based];
3540

    
3541
            for (int i = 0; i < maxn_one_based; i++) {
3542
                resp[i] = i;
3543
            }
3544
        }
3545
        else {
3546
            Random rnd = new Random();
3547

    
3548
            for (int i = 0; i < n; i++) {
3549
                resp[i] = rnd.nextInt(maxn_one_based);
3550
            }
3551
        }
3552

    
3553
        return resp;
3554
    }
3555

    
3556
    private String getRowIdRestrictionCondition(int nrecords) {
3557
        int[] zero_based_rows = getRandomSample(nrecords,
3558
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3559
        String resp = "(";
3560
        Object aux = "";
3561
        ROWID riaux = null;
3562

    
3563
        for (int i = 0; i < zero_based_rows.length; i++) {
3564
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3565
            riaux = (ROWID) aux;
3566
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3567
        }
3568

    
3569
        resp = resp.substring(0, resp.length() - 4);
3570
        resp = resp + ")";
3571

    
3572
        return resp;
3573
    }
3574

    
3575
    private Rectangle2D getBoundingFromSample(int n_max) {
3576
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3577
            " WHERE " + getRowIdRestrictionCondition(n_max);
3578
        STRUCT auxstr = null;
3579
        IGeometry theGeom = null;
3580
        Rectangle2D resp = null;
3581

    
3582
        try {
3583
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3584
            ResultSet rs = st.executeQuery(_qry);
3585

    
3586
            if (rs.next()) {
3587
                auxstr = (STRUCT) rs.getObject(1);
3588

    
3589
                if (auxstr != null) {
3590
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3591

    
3592
                    if (resp == null) {
3593
                        resp = theGeom.getBounds2D();
3594
                    }
3595
                    else {
3596
                        resp.add(theGeom.getBounds2D());
3597
                    }
3598
                }
3599

    
3600
                while (rs.next()) {
3601
                    auxstr = (STRUCT) rs.getObject(1);
3602

    
3603
                    if (auxstr != null) {
3604
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3605

    
3606
                        if (resp == null) {
3607
                            resp = theGeom.getBounds2D();
3608
                        }
3609
                        else {
3610
                            resp.add(theGeom.getBounds2D());
3611
                        }
3612
                    }
3613
                }
3614

    
3615
                rs.close();
3616
                st.close();
3617
            }
3618
            else {
3619
                throw new SQLException("Empty resultset from this query: " +
3620
                    _qry);
3621
            }
3622
        }
3623
        catch (SQLException se) {
3624
                logger.error("While getting sample full extent: " +
3625
                se.getMessage());
3626
        }
3627

    
3628
        if (resp == null) {
3629
            logger.warn(
3630
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3631

    
3632
            return new Rectangle2D.Double(-180, -90, 360, 180);
3633
        }
3634

    
3635
        return resp;
3636
    }
3637

    
3638
    /**
3639
     * Does what it says, puts the LinearRing in counter clock wise
3640
     * order.
3641
     * @param ls The ring to set.
3642
     * @param gf a GeometryFactory object
3643
     * @return A new ring in CCW order.
3644
     *
3645
     */
3646
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3647
        Coordinate[] cc = ls.getCoordinates();
3648

    
3649
        if (CGAlgorithms.isCCW(cc)) {
3650
            return gf.createLinearRing(cc);
3651
        }
3652
        else {
3653
            if (ls instanceof LinearRing) {
3654
                return reverseRing((LinearRing) ls, gf);
3655
            }
3656
            else {
3657
                return reverseLineString(ls, gf);
3658
            }
3659
        }
3660
    }
3661

    
3662
    /**
3663
     * Does what it says, reverses the order of the Coordinates in the ring.
3664
     * @param lr The ring to reverse.
3665
     * @return A new ring with the reversed Coordinates.
3666
     *
3667
     */
3668
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3669
        int numPoints = lr.getNumPoints() - 1;
3670
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3671

    
3672
        for (int t = numPoints; t >= 0; t--) {
3673
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3674
        }
3675

    
3676
        return gf.createLinearRing(newCoords);
3677
    }
3678

    
3679
    /**
3680
     * Does what it says, reverses the order of the Coordinates in the linestring.
3681
     * @param ls The ls to reverse.
3682
     * @param gf a GeometryFactory object
3683
     * @return A new ls with the reversed Coordinates.
3684
     *
3685
     */
3686
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3687
        int numPoints = ls.getNumPoints() - 1;
3688
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3689

    
3690
        for (int t = numPoints; t >= 0; t--) {
3691
            newCoords[t] = ls.getCoordinateN(numPoints - t);
3692
        }
3693

    
3694
        return gf.createLinearRing(newCoords);
3695
    }
3696

    
3697
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3698
        if (ge instanceof MultiPolygon) {
3699
            MultiPolygon mp = (MultiPolygon) ge;
3700
            int size = ge.getNumGeometries();
3701
            Polygon[] pols = new Polygon[size];
3702

    
3703
            for (int i = 0; i < size; i++)
3704
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3705
                        gf);
3706

    
3707
            return new MultiPolygon(pols, gf);
3708
        }
3709
        else {
3710
            if (ge instanceof Polygon) {
3711
                Polygon p = (Polygon) ge;
3712
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3713
                int nholes = p.getNumInteriorRing();
3714

    
3715
                if (nholes > 0) {
3716
                    LinearRing[] holes = new LinearRing[nholes];
3717

    
3718
                    for (int i = 0; i < nholes; i++) {
3719
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3720
                    }
3721

    
3722
                    return gf.createPolygon(exterior, holes);
3723
                }
3724
                else {
3725
                    return gf.createPolygon(exterior, null);
3726
                }
3727
            }
3728
            else {
3729
                return ge;
3730
            }
3731
        }
3732
    }
3733

    
3734
    /**
3735
     * Converts from IGeometry to STRUCT
3736
     *
3737
     * @param ig the geometry to convert
3738
     * @param _forced_type forced type to use
3739
     * @param _conn connection
3740
     * @param _o_srid  SRS (oracle code)
3741
     * @param withSrid whether this STRUCT has a non-NULL SRS
3742
     * @param agu_bien whether or not to check the correctness of the holes
3743
     * @param _isGeoCS whether the SRS is geodetic or not
3744
     * @return the generated STRUCT
3745
     */
3746
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
3747
        IConnection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
3748
        boolean _isGeoCS) {
3749
        if (ig instanceof FGeometryCollection) {
3750
            FGeometryCollection coll = (FGeometryCollection) ig;
3751

    
3752
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3753
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3754

    
3755
            // logger.error("Collections no soportadas por ahora.");
3756
            // return null;
3757
        }
3758
        else {
3759
            Shape shp = ig.getInternalShape();
3760

    
3761
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3762
                agu_bien, false, _isGeoCS);
3763
        }
3764
    }
3765

    
3766
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3767
        boolean agu_bien, boolean isView) {
3768

    
3769
            if (shp == null) return null;
3770
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3771
            agu_bien, isView, isGeogCS);
3772
    }
3773

    
3774
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3775
        IConnection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3776
        boolean isView, boolean _isGeoCS) {
3777
        int _srid = -1;
3778

    
3779
        if ((o_srid != null) && (o_srid.length() > 0)) {
3780
            _srid = Integer.parseInt(o_srid);
3781
        }
3782

    
3783
        if (shp == null) {
3784
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3785

    
3786
            return null;
3787
        }
3788

    
3789
        if (shp instanceof Rectangle2D) {
3790
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3791
                _isGeoCS, o_srid, _conn);
3792
        }
3793

    
3794
        try {
3795
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3796
                    _srid, agu_bien, hasSrid);
3797

    
3798
            return the_struct;
3799
        }
3800
        catch (SQLException ex) {
3801
            logger.error("While creating STRUCT: " + ex.getMessage());
3802

    
3803
            return null;
3804
        }
3805
    }
3806

    
3807
    // -------------------------- not ready yet ----------------
3808
    public int getRowIndexByFID(IFeature _fid) {
3809
        if (isNotAvailableYet) {
3810
            return -1;
3811
        }
3812
        else {
3813
            return super.getRowIndexByFID(_fid);
3814
        }
3815
    }
3816

    
3817
    public int getShapeCount() throws ReadDriverException { 
3818
        if (isNotAvailableYet) {
3819
            return 0;
3820
        }
3821
        else {
3822
            return numReg;
3823
        }
3824
    }
3825

    
3826
    public void setNotAvailableYet(boolean nav) {
3827
        isNotAvailableYet = nav;
3828
    }
3829

    
3830
    // -------------------------------------------------------
3831
    // -------------------------------------------------------
3832
    public String[] getTableNames(IConnection conn, String catalog)
3833
        throws DBException {
3834
        try{
3835
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
3836
        String[] types = { "TABLE", "VIEW" };
3837
        // String[] types = { "VIEW" };
3838

    
3839
        ResultSet rs = null;
3840
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3841
                    ALL_ORACLE_GEOMETADATA_VIEW, types), ((ConnectionJDBC)conn).getConnection());
3842
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3843
//                          ORACLE_GEOMETADATA_VIEW, types);
3844
        TreeMap ret = new TreeMap();
3845

    
3846
        while (rs.next()) {
3847
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
3848
            ret.put(nomCompleto, nomCompleto);
3849
        }
3850

    
3851
        return (String[]) ret.keySet().toArray(new String[0]);
3852
        }catch (SQLException e) {
3853
                        throw new DBException(e);
3854
                }
3855
    }
3856

    
3857
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3858
        throws SQLException {
3859
        String tablename = "";
3860

    
3861

    
3862

    
3863
        if (res.next()) {
3864
            tablename = res.getString("TABLE_NAME");
3865

    
3866
            // debug
3867
            writeMetaTableToLog(con, tablename);
3868

    
3869
            Statement __st = con.createStatement();
3870

    
3871
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3872
                "union (select VIEW_NAME from USER_VIEWS)) " +
3873
                "intersect (select TABLE_NAME from " + tablename + ")";
3874
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
3875
            ResultSet rs = __st.executeQuery(sql);
3876

    
3877
            return rs;
3878
        }
3879
        else {
3880
            logger.error("Error while getting geometry tables.");
3881

    
3882
            return null;
3883
        }
3884
    }
3885

    
3886
    private void writeMetaTableToLog(Connection con, String tname) {
3887

    
3888
            logger.debug("======================================================");
3889
            logger.debug("=     " + ALL_ORACLE_GEOMETADATA_VIEW + "  (1 EVERY 10 TABLES) ========");
3890
            logger.debug("======================================================");
3891

    
3892
            try {
3893
            Statement _stmt = con.createStatement();
3894
            String sql = "SELECT * FROM " + tname;
3895
            ResultSet res = _stmt.executeQuery(sql);
3896
            
3897
            int count = 0;
3898
            while (res.next()) {
3899
                    
3900
                    if ((count % 10) == 0) {
3901
                        logger.debug(
3902
                                        "OWNER: " + res.getString("OWNER")
3903
                                        + ", TABLE_NAME: " + res.getString("TABLE_NAME")
3904
                                        + ", COLUMN_NAME: " + res.getString("COLUMN_NAME")
3905
                                        + ", SRID: " + res.getString("SRID"));
3906
                        ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3907
                        String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3908
                        logger.debug("DIMINFO: " + dinfo);
3909
                        logger.debug("=========");
3910
                    }
3911
                    count++;
3912
                    
3913
            }
3914
            } catch (Throwable th) {
3915

    
3916
            }
3917
        }
3918

    
3919
        /**
3920
     * Gets the field names that can act as row id (always ROWID)
3921
     */
3922
    public String[] getIdFieldsCandidates(IConnection conn, String table_name)
3923
        throws DBException {
3924
            try{
3925
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
3926
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3927
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3928
            _rs.close();
3929
            _st.close();
3930

    
3931
            String[] resp = { "ROWID" };
3932
        return resp;
3933
            }catch (SQLException e) {
3934
                        throw new DBException(e);
3935
                }
3936
    }
3937

    
3938
    /**
3939
     * Gets the field names that can act as geometry fields
3940
     * (queries the user's geographic metadata).
3941
     */
3942
    public String[] getGeometryFieldsCandidates(IConnection conn,
3943
        String table_name) throws DBException {
3944
            try{
3945
        Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3946
        String[] tokens = table_name.split("\\u002E", 2);
3947
        String qry;
3948
        if (tokens.length > 1)
3949
        {
3950
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
3951
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
3952
            tokens[1] + "'";
3953
        }
3954
        else
3955
        {
3956
                qry = "select * from " + ALL_ORACLE_GEOMETADATA_VIEW +
3957
            " where TABLE_NAME = " + "'" + table_name + "'";
3958

    
3959
        }
3960
        ResultSet _rs = _st.executeQuery(qry);
3961

    
3962
        ArrayList aux = new ArrayList();
3963

    
3964
        while (_rs.next()) {
3965
            String _geo = _rs.getString("COLUMN_NAME");
3966
            aux.add(_geo);
3967
        }
3968

    
3969
        _rs.close();
3970
        _st.close();
3971

    
3972
        String[] resp = (String[]) aux.toArray(new String[0]);
3973

    
3974
        return checkIndexes(conn, resp, table_name);
3975
            }catch (SQLException e) {
3976
                        throw new DBException(e);
3977
                }
3978
    }
3979

    
3980
    private String[] checkIndexes(IConnection c, String[] all, String long_table_name) throws DBException {
3981

    
3982
            ArrayList good_ones = new ArrayList();
3983
            try{
3984
            String t = long_table_name;
3985
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
3986

    
3987
            for (int i=0; i<all.length; i++) {
3988

    
3989
                String qry = "SELECT SRID, DIMINFO FROM " + ALL_ORACLE_GEOMETADATA_VIEW +
3990
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
3991
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
3992

    
3993
                Statement _st = ((ConnectionJDBC)c).getConnection().createStatement();
3994
                ResultSet _rs = _st.executeQuery(qry);
3995
                if (_rs.next()) {
3996
                        String _srid = toString((BigDecimal) _rs.getObject(1));
3997
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
3998
                        int len = diminfo.getOracleArray().length;
3999
                        if (allowsGeoQueries(((ConnectionJDBC)c).getConnection(), long_table_name, all[i], _srid, len)) {
4000
                                good_ones.add(all[i]);
4001
                        }
4002
                }
4003
                _rs.close();
4004
                _st.close();
4005
            }
4006

    
4007
            if (good_ones.size() == 0) {
4008
                    throw new SQLException("no_indexes_on_declared_geo_fields");
4009
            }
4010
            }catch (SQLException e) {
4011
                        throw new DBException(e);
4012
                }
4013
            return (String[]) good_ones.toArray(new String[0]);
4014
    }
4015

    
4016
    private String toString(BigDecimal number) {
4017

    
4018
            if (number == null) return "NULL";
4019
            return "" + number.intValue();
4020
        }
4021

    
4022
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
4023
            String p = getPointConstructor(dims, _srid);
4024
            String qry = "";
4025
            qry = "SELECT * FROM " + _t.toUpperCase()
4026
            + " WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'"
4027
            + " AND ROWNUM = 1";
4028

    
4029
            try {
4030
                        Statement _st = c.createStatement();
4031
                        ResultSet _rs = _st.executeQuery(qry);
4032
                        _rs.close();
4033
                        _st.close();
4034
                } catch (Exception ex) {
4035
                        return false;
4036
                }
4037
                return true;
4038
        }
4039

    
4040
        private String getPointConstructor(int dims, String _srid) {
4041

    
4042
                String coord = "";
4043
                for (int i=0; i<dims; i++) coord = coord + "0, ";
4044
                coord = coord.substring(0, coord.length() - 2);
4045

    
4046
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
4047
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
4048
        }
4049

    
4050
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
4051

    
4052
            if (l == null) return false;
4053
            if (str == null) return false;
4054

    
4055
            String item = "";
4056
            for (int i=0; i<l.size(); i++) {
4057
                    if (l.get(i) instanceof String) {
4058
                            item = (String) l.get(i);
4059
                            if (item.compareToIgnoreCase(str) == 0) return true;
4060
                    }
4061
            }
4062
            return false;
4063
    }
4064

    
4065
        /**
4066
     * Utility method to check if a given table is empty.
4067
     */
4068
    public boolean isEmptyTable(Connection conn, String tableName) {
4069
        boolean res = true;
4070

    
4071
        try {
4072
            Statement st = conn.createStatement();
4073
            ResultSet rs = null;
4074
            rs = st.executeQuery("select * from " + tableName +
4075
                    " where rownum = 1");
4076
            res = !rs.next();
4077
            rs.close();
4078
            st.close();
4079
        }
4080
        catch (Exception ex) {
4081
            res = true;
4082
        }
4083

    
4084
        return res;
4085
    }
4086

    
4087
    /**
4088
     * Gets all the fields from a table name.
4089
     */
4090
    public String[] getAllFields(IConnection conn, String table_name)
4091
        throws DBException {
4092
            try{
4093
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
4094
        ResultSet rs = st.executeQuery("select * from " + table_name +
4095
                " where rownum = 1");
4096
        ResultSetMetaData rsmd = rs.getMetaData();
4097
        String[] ret = new String[rsmd.getColumnCount()];
4098

    
4099
        for (int i = 0; i < ret.length; i++) {
4100
            ret[i] = rsmd.getColumnName(i + 1);
4101
        }
4102

    
4103
        rs.close();
4104
        st.close();
4105

    
4106
        return ret;
4107
            }catch (SQLException e) {
4108
                        throw new DBException(e);
4109
                }
4110
    }
4111

    
4112
    /**
4113
     * Gets all field type names from a table.
4114
     */
4115
    public String[] getAllFieldTypeNames(IConnection conn, String table_name)
4116
        throws DBException {
4117
            try{
4118
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
4119
        ResultSet rs = st.executeQuery("select * from " + table_name +
4120
                " where rownum = 1");
4121
        ResultSetMetaData rsmd = rs.getMetaData();
4122
        String[] ret = new String[rsmd.getColumnCount()];
4123

    
4124
        for (int i = 0; i < ret.length; i++) {
4125
            if (rsmd.getColumnType(i + 1) == Types.NUMERIC) {
4126
                    int scale = rsmd.getScale(i+1);
4127
                    if (scale >= 0) {
4128
                        String prec_dec = " (" + rsmd.getPrecision(i+1) + ", " + scale + ")";  
4129
                        ret[i] = rsmd.getColumnTypeName(i + 1) + prec_dec;
4130
                    } else {
4131
                            ret[i] = rsmd.getColumnTypeName(i + 1);
4132
                    }
4133
            } else {
4134
                ret[i] = rsmd.getColumnTypeName(i + 1);
4135
            }
4136
        }
4137

    
4138
        rs.close();
4139
        st.close();
4140

    
4141
        close();
4142

    
4143
        return ret;
4144
            }catch (SQLException e) {
4145
                        throw new DBException(e);
4146
                }
4147
    }
4148

    
4149
    /**
4150
     * Gets Oracle's specific connection string for the given parameters.
4151
     */
4152
    public String getConnectionString(String host, String port, String dbname,
4153
        String user, String pw) {
4154
        String _pw = pw;
4155

    
4156
        if (_pw == null) {
4157
            _pw = "null";
4158
        }
4159

    
4160
        String fullstr = CONN_STR_BEGIN;
4161
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
4162
        fullstr = fullstr + "@" + host.toLowerCase();
4163
        fullstr = fullstr + ":" + port;
4164
        fullstr = fullstr + ":" + dbname.toLowerCase();
4165

    
4166
        return fullstr;
4167
    }
4168

    
4169
    /**
4170
     * Gets the Pracle geometries writer associated with this driver.
4171
     */
4172
    public IWriter getWriter() {
4173
        // on(VectorialEditableDBAdapter.java:290)
4174
        if (writer == null) {
4175

    
4176
                long count = 0;
4177
                        try {
4178
                                count = getRowCount();
4179
                        } catch (ReadDriverException e1) {
4180
                                logger.error("While getting row count: " + e1.getMessage());
4181
                        }
4182
                
4183
            writer = new OracleSpatialWriter(count);
4184
            writer.setDriver(this);
4185
            writer.setLyrShapeType(getShapeType());
4186
            writer.setGeoCS(isGeogCS());
4187
            writer.setGeoColName(geoColName);
4188
            writer.setSRID(oracleSRID);
4189

    
4190
            try {
4191
                    DBLayerDefinition db_lyr_def = getLyrDef();
4192
                    if (db_lyr_def == null) {
4193
                            logger.warn("Found a null DB layer definition, method initialize of OracleWriter not called.");
4194
                    } else {
4195
                            writer.initialize(getLyrDef());
4196
                    }
4197
                
4198
            } catch (InitializeWriterException e) {
4199
                logger.error("While initializing OS Writer: " + e.getMessage(), e);
4200
            }
4201

    
4202
            writer.setStoreWithSrid(tableHasSrid);
4203
        }
4204

    
4205
        return writer;
4206
    }
4207

    
4208
    /**
4209
     * Tells whether the SRS is geodetic or not-
4210
     * @return whether the SRS is geodetic or not
4211
     */
4212
    public boolean isGeogCS() {
4213
        return isGeogCS;
4214
    }
4215

    
4216
    /**
4217
     * Adds a row id to the inner set od IDs.
4218
     * @param id
4219
     */
4220
    public void addRow(String id) {
4221
        Value aux = ValueFactory.createValue(id);
4222
        Integer intobj = new Integer(numReg);
4223
        hashRelate.put(aux, intobj);
4224
        rowToId.put(intobj, id);
4225

    
4226
        numReg++;
4227
    }
4228

    
4229
    /**
4230
     * Removes a row id to the inner set od IDs.
4231
     * @param id
4232
     */
4233
    public void deleteRow(String id) {
4234
        Value aux = ValueFactory.createValue(id);
4235
        Integer intobj = (Integer) hashRelate.get(aux);
4236
        hashRelate.remove(aux);
4237
        rowToId.remove(intobj);
4238

    
4239
        numReg--;
4240
    }
4241

    
4242
    private String getStandardSelectExpression() {
4243

    
4244
                String resp = "";
4245

    
4246
                String[] flds = getLyrDef().getFieldNames();
4247
                int size = flds.length;
4248

    
4249
                for (int i = 0; i < size; i++) {
4250
                        if (i > 0) {
4251
                                resp = resp + "c.\"" + flds[i] + "\", ";
4252
                        } else {
4253
                                resp = resp + flds[i] + ", ";
4254
                        }
4255
                }
4256

    
4257
                resp = resp.substring(0, resp.length() - 2);
4258
                return resp;
4259
        }
4260

    
4261
    /**
4262
         * Allows the method to decide what to do with the geometry field name
4263
         * (remove/add it from the user selected fields).
4264
         * 
4265
         * @param flds
4266
         * @param geof
4267
         * @return the possibly modified field names
4268
         */
4269
    public String[] manageGeometryField(String[] flds, String geof) {
4270
        return addEndIfNotContained(flds, geof);
4271
    }
4272

    
4273
    /**
4274
     * Allows the method to decide what to do with the ID field name
4275
     * (remove/add it from the user selected fields).
4276
     *
4277
     * @param flds
4278
     * @param idf
4279
     * @return the possibly modified field names
4280
     */
4281
    public String[] manageIdField(String[] flds, String idf) {
4282
        return addStartIfNotContained(flds, idf);
4283
    }
4284

    
4285
    private String[] addEndIfNotContained(String[] arr, String item) {
4286
        if (contains(arr, item)) {
4287
            return arr;
4288
        }
4289
        else {
4290
            int size = arr.length;
4291
            String[] resp = new String[size + 1];
4292

    
4293
            for (int i = 0; i < size; i++) {
4294
                resp[i] = arr[i];
4295
            }
4296

    
4297
            resp[size] = item;
4298

    
4299
            return resp;
4300
        }
4301
    }
4302

    
4303
    private String[] addStartIfNotContained(String[] arr, String item) {
4304
        if (contains(arr, item)) {
4305
            return arr;
4306
        }
4307
        else {
4308
            int size = arr.length;
4309
            String[] resp = new String[size + 1];
4310

    
4311
            for (int i = 1; i <= size; i++) {
4312
                resp[i] = arr[i];
4313
            }
4314

    
4315
            resp[0] = item;
4316

    
4317
            return resp;
4318
        }
4319
    }
4320

    
4321
    private boolean contains(String[] arr, String item) {
4322
        for (int i = 0; i < arr.length; i++) {
4323
            if (arr[i].compareTo(item) == 0) {
4324
                return true;
4325
            }
4326
        }
4327

    
4328
        return false;
4329
    }
4330

    
4331
    /**
4332
     * This method is called when the user removes the layer from the view.
4333
     * If the IDs were being loaded, the driver will check this field and will
4334
     * let the thread 'die' quietly.
4335
     *
4336
     */
4337
    public void remove() {
4338
        cancelIDLoad = true;
4339
    }
4340

    
4341
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4342
            // if (!isgeodetic) return true;
4343
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true;
4344
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true;
4345
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true;
4346
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true;
4347
            return false;
4348
    }
4349

    
4350
    private Rectangle2D getFastEstimatedExtent(
4351
                    String tname,
4352
                    String gfield,
4353
                    IConnection c,
4354
                    int sample_size,
4355
                    double enlargement,
4356
                    boolean is_geo) {
4357

    
4358
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4359
            Rectangle2D resp_aux = null;
4360
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4361
            ResultSet _rs = null;
4362

    
4363
            try {
4364
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
4365
                        _rs = _st.executeQuery();
4366
                        while (_rs.next()) {
4367
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4368
                                IGeometry ig = getGeometryUsing(aux, false);
4369

    
4370
                                if (ig == null) continue;
4371

    
4372
                                if (resp_aux == null) {
4373
                                        resp_aux = ig.getBounds2D();
4374
                                } else {
4375
                                        resp_aux.add(ig.getBounds2D());
4376
                                }
4377

    
4378
                        }
4379
                } catch (Exception ex) {
4380
                        logger.error("While getting random sample: " + ex.getMessage());
4381
                }
4382

    
4383
                if (resp_aux == null) {
4384
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
4385
                        return world;
4386
                }
4387
                
4388
                double w = resp_aux.getWidth();
4389
                double h = resp_aux.getHeight();
4390
                double x = resp_aux.getMinX();
4391
                double y = resp_aux.getMinY();
4392

    
4393
                // enlarge n times:
4394
                double newx = x - (0.5 * (enlargement - 1)) * w;
4395
                double newy = y - (0.5 * (enlargement - 1)) * h;
4396
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4397
                                enlargement * w,
4398
                                enlargement * h);
4399

    
4400
                if (is_geo) {
4401
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4402
                        logger.debug("FAST BB: " + resp_aux.toString());
4403
                        return resp_aux;
4404
                } else {
4405
                        logger.debug("FAST BB: " + resp_aux_large.toString());
4406
                        return resp_aux_large;
4407
                }
4408

    
4409
    }
4410

    
4411
    private Rectangle2D getEstimatedExtent(
4412
                    String tname,
4413
                    String gfield,
4414
                    IConnection c,
4415
                    int sample_size,
4416
                    double enlargement,
4417
                    boolean is_geo) {
4418

    
4419
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4420

    
4421
            ArrayList ids = new ArrayList();
4422
            int _rnd_index = 0;
4423
            ROWID _id = null;
4424
            Random rnd = new Random(System.currentTimeMillis());
4425

    
4426
            for (int i=0; i<sample_size; i++) {
4427
                    _rnd_index = rnd.nextInt(numReg);
4428
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
4429
                    ids.add(_id.stringValue());
4430
            }
4431

    
4432
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
4433
            for (int i=0; i<ids.size(); i++) {
4434
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR ";
4435
            }
4436
            qry = qry.substring(0, qry.length() - 4) + ")";
4437

    
4438
            Rectangle2D resp_aux = null;
4439
            ResultSet _rs = null;
4440

    
4441
            try {
4442
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
4443
                        _rs = _st.executeQuery();
4444
                        while (_rs.next()) {
4445
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4446
                                IGeometry ig = getGeometryUsing(aux, false);
4447

    
4448
                                if (ig == null) continue;
4449

    
4450
                                if (resp_aux == null) {
4451
                                        resp_aux = ig.getBounds2D();
4452
                                } else {
4453
                                        resp_aux.add(ig.getBounds2D());
4454
                                }
4455

    
4456
                        }
4457
                } catch (Exception ex) {
4458
                        logger.error("While getting random sample: " + ex.getMessage());
4459
                }
4460

    
4461
                if (resp_aux == null) {
4462
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
4463
                        return world;
4464
                }
4465
                
4466
                double w = resp_aux.getWidth();
4467
                double h = resp_aux.getHeight();
4468
                double x = resp_aux.getMinX();
4469
                double y = resp_aux.getMinY();
4470

    
4471
                // enlarge 10 times:
4472
                double newx = x - (0.5 * (enlargement - 1)) * w;
4473
                double newy = y - (0.5 * (enlargement - 1)) * h;
4474
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4475
                                enlargement * w,
4476
                                enlargement * h);
4477

    
4478
                if (is_geo) {
4479
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4480
                        logger.debug("ESTIMATED BB: " + resp_aux.toString());
4481
                        return resp_aux;
4482
                } else {
4483
                        logger.debug("ESTIMATED BB: " + resp_aux_large.toString());
4484
                        return resp_aux_large;
4485
                }
4486

    
4487
    }
4488

    
4489
    public void setUserName(String u) {
4490
            userName = u;
4491
    }
4492

    
4493
    public String getUserName() {
4494
            return userName;
4495
    }
4496

    
4497
    public static final int JGeometry_GTYPE_COLLECTION = 4;
4498
    public static final int JGeometry_GTYPE_CURVE = 2;
4499
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
4500
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
4501
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
4502
    public static final int JGeometry_GTYPE_POINT = 1;
4503
    public static final int JGeometry_GTYPE_POLYGON = 3;
4504
        
4505

    
4506
    // ------------------------------
4507
    
4508
    public void setXMLEntity(XMLEntity xml) throws XMLException {
4509
            
4510
            super.setXMLEntity(xml);
4511
            workingAreaInTablesCS = workingArea;
4512
            
4513
            try {
4514
                    int[] ftypes = xml.getIntArrayProperty("fieldTypes");
4515
                    setLyrDefFieldTypes(ftypes);
4516
            } catch (Exception ex) {
4517
                    logger.warn("Apparently, an old GVP file has been opened," +
4518
                                    " field type values are not accurate after this point.");
4519
            }
4520
            
4521
    }
4522
    
4523
    public XMLEntity getXMLEntity() {
4524
                // ---------------------
4525

    
4526
                XMLEntity xml = new XMLEntity();
4527
                xml.putProperty("className", getClass().getName());
4528

    
4529
                xml.putProperty("catalog", getLyrDef().getCatalogName());
4530

    
4531
                int aux = userName.indexOf("@");
4532
                if (aux != -1)
4533
                        userName = userName.substring(0, aux);
4534
                xml.putProperty("username", userName);
4535

    
4536
                xml.putProperty("driverclass", ORACLE_JAR_FILE_NAME);
4537

    
4538
                xml.putProperty("tablename", getTableName());
4539
                xml.putProperty("fields", lyrDef.getFieldNames());
4540
                xml.putProperty("fieldTypes", getLyrDefFieldTypes());
4541
                xml.putProperty("FID", lyrDef.getFieldID());
4542
                xml.putProperty("THE_GEOM", lyrDef.getFieldGeometry());
4543
                xml.putProperty("whereclause", getWhereClause());
4544
                xml.putProperty("SRID", lyrDef.getSRID_EPSG());
4545

    
4546
                xml.putProperty("host", host);
4547
                xml.putProperty("port", port);
4548
                xml.putProperty("dbName", dbName);
4549
                xml.putProperty("connName", connName);
4550

    
4551
                if (workingAreaInTablesCS != null) {
4552
                        xml.putProperty("minXworkArea", workingAreaInTablesCS.getMinX());
4553
                        xml.putProperty("minYworkArea", workingAreaInTablesCS.getMinY());
4554
                        xml.putProperty("HworkArea", workingAreaInTablesCS.getHeight());
4555
                        xml.putProperty("WworkArea", workingAreaInTablesCS.getWidth());
4556
                }
4557

    
4558
                return xml;
4559
        }
4560
    
4561
    private int[] getLyrDefFieldTypes() {
4562
            FieldDescription[] fd = lyrDef.getFieldsDesc();
4563
            int sz = fd.length;
4564
            int[] resp = new int[sz];
4565
            for (int i=0; i<sz; i++) resp[i] = fd[i].getFieldType();
4566
                return resp;
4567
        }
4568
    
4569
    private void setLyrDefFieldTypes(int[] tt) {
4570
            FieldDescription[] fd = lyrDef.getFieldsDesc();
4571
            
4572
            int sz_fd = fd.length;
4573
            int sz_tt = tt.length;
4574
            int sz = sz_tt;
4575
            
4576
            if (sz_tt != sz_fd) {
4577
                    logger.error("Field count does not match. lyrDef has " + sz_fd + " fields," +
4578
                                    " but this method was called with " + sz_tt + " items (?)");
4579
                    sz = Math.min(sz_fd, sz_tt);
4580
            }
4581
            
4582
            for (int i=0; i<sz; i++) lyrDef.getFieldsDesc()[i].setFieldType(tt[i]);
4583
    }
4584

    
4585
        public String[] getTableFields(IConnection conex, String table) throws DBException {
4586
                try{
4587
                Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
4588
        // ResultSet rs = dbmd.getTables(catalog, null, dbLayerDefinition.getTable(), null);
4589
                ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
4590
                ResultSetMetaData rsmd = rs.getMetaData();
4591

    
4592
                String[] ret = new String[rsmd.getColumnCount()];
4593

    
4594
                for (int i = 0; i < ret.length; i++) {
4595
                        ret[i] = rsmd.getColumnName(i+1);
4596
                }
4597

    
4598
                return ret;
4599
                }catch (SQLException e) {
4600
                        throw new DBException(e);
4601
                }
4602
        }
4603

    
4604
    // Overwritten to keep old behavior: returns "schema.table_name" if
4605
    // schema is not current user
4606
        public String getTableName() {
4607
            return fullTableName; 
4608
        }
4609
        
4610
    private Timestamp flexibleTimeStamp(String s) {
4611
            
4612
            String aux = s.replace('-', ' ');
4613
            aux = aux.replace(':', ' ');
4614
            aux = aux.replace('.', ' ');
4615
            // sample: 2007 12 31 23 59 59 9999
4616
            String[] parts = aux.trim().split(" ");
4617
            
4618
            int year;
4619
            int month;
4620
            int day;
4621
            int hour;
4622
            int minute;
4623
            int second;
4624
            int a_nanos;
4625

    
4626
            if (parts.length == 7) {
4627

    
4628
                    try {
4629

    
4630
                            year = Integer.parseInt(parts[0]) - 1900;
4631
                            month = Integer.parseInt(parts[1]) - 1;
4632
                            day = Integer.parseInt(parts[2]);
4633
                            hour = Integer.parseInt(parts[3]);
4634
                            minute = Integer.parseInt(parts[4]);
4635
                            second = Integer.parseInt(parts[5]);
4636
                            a_nanos = Integer.parseInt(parts[6]);
4637
                            
4638
                    } catch (Exception ex) {
4639
                        logger.debug("Bad time stamp: " + ex.getMessage());
4640
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4641
                    }
4642

    
4643
            } else {
4644
                    
4645
                if (parts.length == 6) {
4646
                        
4647
                        try {
4648
                            year = Integer.parseInt(parts[0]) - 1900;
4649
                            month = Integer.parseInt(parts[1]) - 1;
4650
                            day = Integer.parseInt(parts[2]);
4651
                            hour = Integer.parseInt(parts[3]);
4652
                            minute = Integer.parseInt(parts[4]);
4653
                            second = Integer.parseInt(parts[5]);
4654
                            a_nanos = 0;
4655
                            
4656
                        } catch (Exception ex) {
4657
                                
4658
                            logger.debug("Bad time stamp: " + ex.getMessage());
4659
                            return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4660
                        }
4661

    
4662
                } else {
4663
                        
4664
                        logger.debug("Bad time stamp: " + s);
4665
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4666
                        
4667
                }
4668
            }
4669
            
4670
            return new Timestamp(year, month, day, hour, minute, second, a_nanos);
4671
    }
4672

    
4673
        public void write(DataWare arg0) throws WriteDriverException, ReadDriverException {
4674
        }
4675
        
4676
        public static int nvarchar2Limited(int n) {
4677
                
4678
                if (n <= VARCHAR2_STANDARD_SIZE) return VARCHAR2_STANDARD_SIZE;
4679
                if (n <= VARCHAR2_LONG_SIZE) return n;
4680
                
4681
                return VARCHAR2_LONG_SIZE;
4682
        }
4683
        
4684
    private boolean isSimpleCollectionOfLines(Datum[] all_elem) {
4685
            
4686
            try {
4687
                int size = all_elem.length;
4688
                if (all_elem[1].intValue() != 4) return false;
4689
                int size3 = size / 3;
4690
                
4691
                for (int i=1; i<size3; i++) {
4692
                        if (all_elem[3 * i + 1].intValue() != 2) return false; 
4693
                }
4694
                return true;
4695
                
4696
            } catch (SQLException ex) {
4697
                    logger.error("While is simple line collection: " + ex.getMessage());
4698
            }
4699
            
4700
            return false;
4701
    }
4702
    
4703
    private Datum[] removeThreeFirst(Datum[] elem) {
4704
            int sz = elem.length;
4705
            Datum[] resp = new Datum[sz - 3];
4706
            for (int i=3; i<sz; i++) resp[i - 3] = elem[i];
4707
            return resp;
4708
    }
4709
        
4710
        public static String removePrefix(String str) {
4711
                
4712
                int colon_ind = str.indexOf(":");
4713
                if (colon_ind != -1) {
4714
                        return str.substring(colon_ind + 1);
4715
                } else {
4716
                        return str;
4717
                }
4718
        }
4719

    
4720
    
4721
            
4722
            private class AnEmptyFeatureIterator implements IFeatureIterator {
4723
                public boolean hasNext() throws ReadDriverException { return false; }
4724
                public IFeature next() throws ReadDriverException { return null; }
4725
                public void closeIterator() throws ReadDriverException { }                
4726
        }
4727
            
4728
        private Value objToValue(Object obj, int idFld) {
4729
                
4730
            if (obj == null) {
4731
                    return ValueFactory.createNullValue();
4732
            } else {
4733
                    
4734
                    String objToString = obj.toString();
4735

    
4736
                if (obj instanceof String) {
4737
                    objToString = (String) obj;
4738
                    return ValueFactory.createValue(objToString);
4739
                } else {
4740
                    if (obj instanceof ROWID) {
4741
                        objToString = ((ROWID) obj).stringValue();
4742
                        return ValueFactory.createValue(objToString);
4743
                    } else {
4744
                        if (obj instanceof STRUCT) {
4745
                            objToString = "STRUCT";
4746
                            return ValueFactory.createValue(objToString);
4747
                        } else {
4748
                            if (obj instanceof TIMESTAMP) {
4749
                                    TIMESTAMP aux = (TIMESTAMP) obj;
4750
                                objToString = aux.stringValue();
4751
                                Timestamp ts = flexibleTimeStamp(objToString);
4752
                                return ValueFactory.createValue(ts);
4753

    
4754
                            } else {
4755

    
4756
                                    // last try
4757
                                    int _type = -1;
4758
                                                            try {
4759
                                                                    _type = getFieldType(idFld);
4760
                                        if (_type == Types.DATE) {
4761
                                                objToString = objToString.replace('-', '/');
4762
                                        }
4763
                                        return ValueFactory.createValueByType(objToString, _type);
4764
                                } catch (Exception ex) {
4765
                                        logger.debug("Failed to create Value: _type = "
4766
                                                        + _type + ", objToString = " + objToString);
4767
                                        return ValueFactory.createNullValue();
4768
                                }
4769
                                
4770
                            }
4771
                        }
4772
                    }
4773
                }
4774
            }
4775
        }
4776

    
4777
        public Value[] getAttributes(ResultSet rs, boolean use_main_metadata) {
4778
            Value[] res = null;
4779

    
4780
            int fcount = 0;
4781

    
4782
            try {
4783
                    if (use_main_metadata) {
4784
                            fcount = metaData.getColumnCount();
4785
                    } else {
4786
                            fcount = rs.getMetaData().getColumnCount();
4787
                    }
4788
                
4789
                res = new Value[fcount];
4790

    
4791
                for (int i = 0; i < fcount; i++) {
4792
                    Object obj = rs.getObject(i + 1);
4793
                    res[i] = objToValue(obj, i);
4794
                }
4795

    
4796
            } catch (Exception se) {
4797
                    logger.error("While getting resultset attribute values: " + se.getMessage());
4798
                    res = new Value[fcount];
4799
                    for (int i=0; i<fcount; i++) res[i] = ValueFactory.createNullValue();
4800
            }
4801

    
4802
            return res;
4803
        }            
4804
        
4805
        public boolean canWriteGeometry(int gvSIGgeometryType) {
4806
                if (writer == null) {
4807
                        return true;
4808
                } else {
4809
                        return writer.canWriteGeometry(gvSIGgeometryType);
4810
                }
4811
                
4812
        }
4813
        
4814
    
4815

    
4816
}