Statistics
| Revision:

svn-gvsig-desktop / branches / v10 / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialDriver.java @ 14053

History | View | Annotate | Download (136 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 com.hardcode.driverManager.IDelayedDriver;
46

    
47
import com.hardcode.gdbms.engine.data.DataSource;
48
import com.hardcode.gdbms.engine.data.DataSourceFactory;
49
import com.hardcode.gdbms.engine.data.SourceInfo;
50
import com.hardcode.gdbms.engine.data.edition.DataWare;
51
import com.hardcode.gdbms.engine.data.file.FileSourceInfo;
52
import com.hardcode.gdbms.engine.spatial.fmap.FShapeGeneralPathX;
53
import com.hardcode.gdbms.engine.values.DoubleValue;
54
import com.hardcode.gdbms.engine.values.Value;
55
import com.hardcode.gdbms.engine.values.ValueFactory;
56

    
57
import com.iver.cit.gvsig.fmap.DriverException;
58
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
59
import com.iver.cit.gvsig.fmap.core.FGeometry;
60
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
61
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
62
import com.iver.cit.gvsig.fmap.core.FNullGeometry;
63
import com.iver.cit.gvsig.fmap.core.FPoint2D;
64
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
65
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
66
import com.iver.cit.gvsig.fmap.core.FShape;
67
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
68
import com.iver.cit.gvsig.fmap.core.ICanReproject;
69
import com.iver.cit.gvsig.fmap.core.IFeature;
70
import com.iver.cit.gvsig.fmap.core.IGeometry;
71
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
72
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
73
import com.iver.cit.gvsig.fmap.crs.CRSFactory;
74
import com.iver.cit.gvsig.fmap.drivers.ConnectionJDBC;
75
import com.iver.cit.gvsig.fmap.drivers.DBException;
76
import com.iver.cit.gvsig.fmap.drivers.DBLayerDefinition;
77
import com.iver.cit.gvsig.fmap.drivers.DefaultJDBCDriver;
78
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
79
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
80
import com.iver.cit.gvsig.fmap.drivers.IConnection;
81
import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator;
82
import com.iver.cit.gvsig.fmap.drivers.db.utils.ConnectionWithParams;
83
import com.iver.cit.gvsig.fmap.drivers.db.utils.SingleVectorialDBConnectionManager;
84
import com.iver.cit.gvsig.fmap.drivers.dbf.DBFDriver;
85
import com.iver.cit.gvsig.fmap.edition.EditableAdapter;
86
import com.iver.cit.gvsig.fmap.edition.EditionException;
87
import com.iver.cit.gvsig.fmap.edition.IWriteable;
88
import com.iver.cit.gvsig.fmap.edition.IWriter;
89
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
90
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
91
import com.iver.cit.gvsig.fmap.layers.XMLException;
92
import com.iver.cit.gvsig.project.documents.table.ProjectTable;
93
import com.iver.cit.gvsig.project.documents.table.ProjectTableFactory;
94
import com.iver.utiles.NumberUtilities;
95
import com.iver.utiles.XMLEntity;
96

    
97
import com.vividsolutions.jts.algorithm.CGAlgorithms;
98
import com.vividsolutions.jts.geom.Coordinate;
99
import com.vividsolutions.jts.geom.Geometry;
100
import com.vividsolutions.jts.geom.GeometryFactory;
101
import com.vividsolutions.jts.geom.LineString;
102
import com.vividsolutions.jts.geom.LinearRing;
103
import com.vividsolutions.jts.geom.MultiPolygon;
104
import com.vividsolutions.jts.geom.Polygon;
105
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
106

    
107
import oracle.jdbc.OracleConnection;
108

    
109
// import oracle.spatial.geometry.JGeometry;
110

    
111
import oracle.sql.ARRAY;
112
import oracle.sql.DATE;
113
import oracle.sql.Datum;
114
import oracle.sql.NUMBER;
115
import oracle.sql.ROWID;
116
import oracle.sql.STRUCT;
117
import oracle.sql.StructDescriptor;
118
import oracle.sql.TIMESTAMP;
119

    
120
import org.apache.log4j.Logger;
121
import org.cresques.cts.ICoordTrans;
122
import org.cresques.cts.IProjection;
123

    
124
//import org.geotools.data.oracle.sdo.GeometryConverter;
125

    
126
import java.awt.Shape;
127
import java.awt.geom.Point2D;
128
import java.awt.geom.Rectangle2D;
129

    
130
import java.io.File;
131
import java.io.IOException;
132
import java.math.BigDecimal;
133

    
134
import java.sql.Connection;
135
import java.sql.DatabaseMetaData;
136
import java.sql.Date;
137
import java.sql.Driver;
138
import java.sql.DriverManager;
139
import java.sql.PreparedStatement;
140
import java.sql.ResultSet;
141
import java.sql.ResultSetMetaData;
142
import java.sql.SQLException;
143
import java.sql.Statement;
144
import java.sql.Timestamp;
145
import java.sql.Types;
146

    
147
import java.text.ParseException;
148

    
149
import java.util.ArrayList;
150
import java.util.HashMap;
151
import java.util.Hashtable;
152
import java.util.Iterator;
153
import java.util.Random;
154
import java.util.TreeMap;
155

    
156

    
157
/**
158
 * Vectorial driver to access Oracle databases geometries.
159
 * Should work on Oracle Locator.
160
 *
161
 * It contains switches to test different modules to perform the
162
 * translation oracle structs --> gvsig geometries:
163
 *
164
 * - Parsing the structs directly.
165
 * - Using Oracle's JGeometry static methods
166
 * - Using Geotools utilities
167
 *
168
 *  (currently, the driver parses the structs directly)
169
 *
170
 * @author jldominguez
171
 *
172
 */
173
public class OracleSpatialDriver extends DefaultJDBCDriver
174
    implements IDelayedDriver, ICanReproject, IWriteable {
175
    private static Logger logger = Logger.getLogger(OracleSpatialDriver.class.getName());
176
    private static int FETCH_SIZE = 15000;
177

    
178
    // constants
179
    public static final int GEODETIC_FULLEXTENT_SAMPLE_SIZE = 50;
180
    public static final String GEODETIC_SRID = "8307";
181
    public static final String ASSUMED_ORACLE_SRID = "8307";
182
    
183
    // ------------------------------------------------
184
    public static final String NAME = "Oracle Spatial Database Driver";
185
    public static final int ID_COLUMN_INDEX = 1;
186
    public static final String ORACLE_GEOMETADATA_VIEW = "ALL_SDO_GEOM_METADATA";
187
    public static final String ORACLE_EPSG_TABLE_NAME = "ORA_EPSG";
188
    public static final String ORACLE_EPSG_FILE_NAME = "ORA_EPSG.DBF";
189
    public static final String DEFAULT_GEO_FIELD = "GEOMETRY";
190
    // public static final String DEFAULT_GEO_FIELD = "MERGEDGEOMETRY";
191

    
192
    public static final String ORACLE_ID_FIELD = "ROWID";
193
    public static final String DEFAULT_ID_FIELD = "GID";
194
    public static final String ORACLE_GEO_SCHEMA = "MDSYS";
195
    public static final String CONN_STR_BEGIN = "jdbc:oracle:thin:";
196
    public static final int VARCHAR2_STANDARD_SIZE = 80;
197
    public static final int VARCHAR2_LONG_SIZE = 256;
198
    public static final int MAX_ID_LENGTH = 30;
199
    private final static GeometryFactory geomFactory = new GeometryFactory();
200
    public static final double IRRELEVANT_DISTANCE = 0.00000001;
201
        private static final long ID_MIN_DELAY = 1000;
202

    
203
        public static final String ORACLE_JAR_FILE_NAME = "oracle.jdbc.driver.OracleDriver";
204

    
205
    static {
206
        try {
207
            Class.forName(ORACLE_JAR_FILE_NAME);
208
        }
209
        catch (ClassNotFoundException e) {
210
            throw new RuntimeException(e);
211
        }
212
    }
213

    
214
    private OracleSpatialWriter writer = null;
215

    
216
    // utility object to convert geometries.
217
//    private GeometryConverter geotools_conv;
218

    
219
    // switch variable
220
    private boolean use_geotools = false;
221
    private boolean tableHasSrid = true;
222

    
223
    // ------------------------------------------------
224
    private boolean isNotAvailableYet = true;
225
    private IGeometry nullGeom = new FNullGeometry();
226
    private Value nullVal = ValueFactory.createNullValue();
227
    private IdLoaderThread idLoader;
228
    private DriverAttributes drvAtts;
229
    private int[] pkOneBasedIndexes;
230
    private String[] fieldNames;
231
    private String not_restricted_sql = "";
232

    
233
    private Rectangle2D workingAreaInViewsCS = null;
234
    private Rectangle2D workingAreaInTablesCS = null;
235
    private STRUCT workingAreaInTablesCSStruct = null;
236

    
237
    private String idFieldNames;
238
    private int oneBasedGeoColInd = 0;
239
    private int shapeType = -1;
240
    private boolean needsCollectionLayer = true;
241

    
242
    // ----------------------------------------------
243
    // one feature is cached to avoid querying for each attribute request:
244
    private IFeature singleCachedFeature = null;
245
    private long singleCachedFeatureRowNum = -1;
246

    
247
    // ----------------------------------------------
248
    private boolean cancelIDLoad = false;
249

    
250
    // ----------------------------------------------
251
    private String fullTableName = "";
252
    private String geoColName = "";
253
    private String oracleSRID;
254
    private String epsgSRID;
255
    private String destProj = "";
256
    private Rectangle2D full_Extent = null;
257
    private boolean emptyWhereClause = true;
258
    private boolean isGeogCS = false;
259
    private boolean hasRealiableExtent = true;
260

    
261
    // new hash map to perform queries by row number:
262
    private HashMap rowToId = new HashMap();
263
    private String standardSelectExpressionFalse = null;
264
        private String destProjOracle;
265
        private boolean isDestGeogCS = false;
266

    
267
    public OracleSpatialDriver() {
268
        drvAtts = new DriverAttributes();
269
        drvAtts.setLoadedInMemory(false);
270
    }
271

    
272
        public String getWhereClause() {
273
            return lyrDef.getWhereClause();
274
        }
275

    
276

    
277
    /**
278
     * This method is called when the user creates a new oracle
279
     * table from a vectorial layer
280
     *
281
     * @param params this array simply contains the parameters <tt>Connection</tt> and
282
     * <tt>DBLayerDefinition</tt>
283
     */
284
    public void setData(Object[] params) {
285
        setData((IConnection) params[0], (DBLayerDefinition) params[1]);
286
    }
287

    
288
    private void adjustLyrDef() throws SQLException {
289
        DBLayerDefinition ldef = getLyrDef();
290
        int cnt = metaData.getColumnCount();
291

    
292
        FieldDescription[] _new = new FieldDescription[cnt];
293

    
294
        for (int i = 0; i < cnt; i++) {
295
            _new[i] = new FieldDescription();
296
            _new[i].setFieldName(metaData.getColumnName(i + 1));
297
            _new[i].setDefaultValue(ValueFactory.createNullValue());
298
            _new[i].setFieldAlias(_new[i].getFieldName());
299
            _new[i].setFieldLength(getFieldWidth(i));
300

    
301
            int _type = metaData.getColumnType(i + 1);
302
            _new[i].setFieldType(_type);
303

    
304
            if ((_type == Types.FLOAT) || (_type == Types.DOUBLE) ||
305
                    (_type == Types.DECIMAL) || (_type == Types.REAL)) {
306
                _new[i].setFieldDecimalCount(6);
307
            }
308
            else {
309
                _new[i].setFieldDecimalCount(0);
310
            }
311
        }
312

    
313
        ldef.setFieldsDesc(_new);
314
        setLyrDef(ldef);
315
    }
316

    
317
    /**
318
     * Standard initializing method.
319
     */
320
    public void setData(IConnection _conn, DBLayerDefinition lyrDef) {
321
        conn = _conn;
322
        
323
        // This metadata is required to store layer in GVP
324
        // without problems:
325
        ConnectionWithParams _cwp =
326
                SingleVectorialDBConnectionManager.instance().findConnection(conn);
327
                host = _cwp.getHost();
328
                port = _cwp.getPort();
329
                dbName = _cwp.getDb();
330
                connName = _cwp.getName();
331
                
332
        // ------------------
333

    
334
        lyrDef.setConnection(conn);
335

    
336
        setLyrDef(lyrDef);
337

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

    
358
        // various metadata settings
359
        // getMetaDataInThisThread();
360
        cleanWhereClause();
361
        loadSdoMetadata();
362
        oneRowMetadata();
363

    
364
        setDestProjection(lyrDef.getSRID_EPSG());
365

    
366
        IProjection viewProj = CRSFactory.getCRS("EPSG:" + destProj);
367
        IProjection tableProj = CRSFactory.getCRS("EPSG:" + epsgSRID);
368
        ICoordTrans reprojecter = viewProj.getCT(tableProj);
369

    
370
        workingAreaInViewsCS = lyrDef.getWorkingArea();
371
        if (workingAreaInViewsCS != null) {
372
                workingAreaInTablesCS = reprojecter.convert(workingAreaInViewsCS);
373
        }
374
        workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
375
                FShape.NULL, tableHasSrid, false, true);
376

    
377
        cancelIDLoad = false;
378
        idLoader = new IdLoaderThread(this);
379
        idLoader.start();
380
    }
381

    
382
        /**
383
     * Utility method to load IDs in a different thred, so that gvsig's gui
384
     * does not get blocked.
385
     *
386
     */
387
    public void getMetaDataInThisThread() {
388
        getMetadata();
389
    }
390

    
391
    private void getMetadata() {
392

    
393
            long id_load_start = System.currentTimeMillis();
394
        setIdRowTable();
395
        long id_load_end = System.currentTimeMillis();
396

    
397
        long delay = id_load_end - id_load_start;
398
        if (delay < ID_MIN_DELAY) {
399
                logger.info("Ids thread delayed by: " + (ID_MIN_DELAY - delay) + " ms.");
400
                try {
401
                                Thread.sleep(ID_MIN_DELAY - delay);
402
                        } catch (InterruptedException e) {
403
                                logger.error("While delaying ids thread: " + e.getMessage());
404
                        }
405
        }
406

    
407
        if (!hasRealiableExtent) {
408
                full_Extent = getEstimatedGeodeticExtent(
409
                                getTableName(), geoColName, conn, 20, 1.5);
410
        }
411

    
412
        if (cancelIDLoad) {
413
            return;
414
        }
415
    }
416

    
417
    private boolean needsCollectionLayer() {
418
        try {
419
            // SELECT DISTINCT(C.GEOM.SDO_GTYPE) FROM COMUICV C
420
            // String qry = "select distinct(c."  + geoColName + ".SDO_GTYPE) from " + getTableName() + " c";
421
            String qry = "select c." + geoColName + ".SDO_ELEM_INFO from " +
422
                getTableName() + " c";
423

    
424
            // SDO_ELEM_INFO
425
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
426
            ResultSet _rs = _st.executeQuery(qry);
427

    
428
            ArrayList types = new ArrayList();
429
            int aux = 0;
430

    
431
            ARRAY info_aux;
432
            int[] info_aux_int;
433
            int size;
434

    
435
            while (_rs.next()) {
436
                // aux = _rs.getInt(1);
437
                info_aux = (ARRAY) _rs.getObject(1);
438
                info_aux_int = info_aux.getIntArray();
439
                size = info_aux_int.length / 3;
440

    
441
                for (int i = 0; i < size; i++) {
442
                    aux = info_aux_int[(3 * i) + 1];
443
                }
444

    
445
                types.add(new Integer(aux % 1000));
446

    
447
                if ((aux % 1000) != 3) {
448
                    System.err.println("x");
449
                }
450
            }
451

    
452
            _rs.close();
453
            _st.close();
454

    
455
            boolean resp = hasSeveralGeometryTypes(types, false);
456

    
457
            return resp;
458
        }
459
        catch (Exception se) {
460
            System.err.println("Error while getting SDO metadata: " +
461
                se.getMessage());
462
        }
463

    
464
        return false;
465
    }
466

    
467
    private boolean hasSeveralGeometryTypes(ArrayList tt, boolean are_dims) {
468
        if (tt.size() == 0) {
469
            return false;
470
        }
471

    
472
        HashMap m = new HashMap();
473

    
474
        for (int i = 0; i < tt.size(); i++) {
475
            Integer integ = (Integer) tt.get(i);
476
            int val = integ.intValue();
477

    
478
            if ((val == 4) && (!are_dims)) {
479
                return true;
480
            }
481

    
482
            m.put("" + (val % 4), "a type");
483
        }
484

    
485
        Iterator iter = m.keySet().iterator();
486
        iter.next();
487

    
488
        return iter.hasNext();
489
    }
490

    
491
    private String getOracleSridFromCurrentRecord(ResultSet _rs)
492
        throws SQLException {
493
        Object obj = _rs.getObject("SRID");
494

    
495
        if (obj == null) {
496
            logger.warn("No SRID found for this table.");
497
            tableHasSrid = false;
498

    
499
            return ASSUMED_ORACLE_SRID;
500
        }
501

    
502
        return obj.toString();
503
    }
504

    
505
    private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
506
        throws SQLException {
507
        ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
508

    
509
        if (dim_info_array == null) {
510
            // no full extent found:
511
            return null;
512
        }
513
        else {
514
            Datum[] da = dim_info_array.getOracleArray();
515

    
516
            STRUCT sx = (STRUCT) da[0];
517
            STRUCT sy = (STRUCT) da[1];
518

    
519
            try {
520
                double minx = Double.parseDouble(sx.getAttributes()[1].toString());
521
                double maxx = Double.parseDouble(sx.getAttributes()[2].toString());
522
                double miny = Double.parseDouble(sy.getAttributes()[1].toString());
523
                double maxy = Double.parseDouble(sy.getAttributes()[2].toString());
524

    
525
                if (minx > maxx) {
526
                    double aux = minx;
527
                    minx = maxx;
528
                    maxx = aux;
529
                }
530

    
531
                if (miny > maxy) {
532
                    double aux = miny;
533
                    miny = maxy;
534
                    maxy = aux;
535
                }
536

    
537
                return getRectangle(minx, maxx, miny, maxy);
538

    
539
                // fullExtentJTS = shapeToGeometry(fullExtent);
540
            }
541
            catch (Exception ex) {
542
                System.err.println(
543
                    "Error while getting full extent from metadata table.");
544

    
545
                return null;
546

    
547
                // fullExtentJTS = null;
548
            }
549
        }
550
    }
551

    
552
    private void loadSdoMetadata() {
553
        try {
554
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
555
            String[] tokens = getTableName().split("\\u002E", 2);
556
            String qry;
557
            if (tokens.length > 1)
558
            {
559
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
560
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
561
                tokens[1] + "'";
562
            }
563
            else
564
            {
565
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
566
                " where TABLE_NAME = " + "'" + getTableName() + "'";
567

    
568
            }
569
//            String qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
570
//                " where TABLE_NAME = " + "'" + getTableName() + "'";
571
            ResultSet _rs = _st.executeQuery(qry);
572

    
573
            if (_rs.next()) {
574
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
575

    
576
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
577

    
578
                try {
579
                                        epsgSRID = oracleSridToEpsgSrid(oracleSRID);
580
                                } catch (Exception e) {
581
                                        logger.error("Unknown oracle SRID: " + oracleSRID);
582
                                        tableHasSrid = false;
583
                                }
584
                full_Extent = getFullExtentFromCurrentRecord(_rs);
585

    
586
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS);
587

    
588
                if (!hasRealiableExtent) {
589
                        full_Extent = getFastEstimatedGeodeticExtent(
590
                                        getTableName(), geoColName, conn, 20, 10);
591
                }
592

    
593
                _rs.close();
594
                _st.close();
595
            }
596
            else {
597
                throw new SQLException("Empty resultset from this query: " +
598
                    qry);
599
            }
600
        }
601
        catch (SQLException se) {
602
            System.err.println("Error while getting SDO metadata: " +
603
                se.getMessage());
604
        }
605
    }
606

    
607
    /**
608
     * Utility method to find out if a coordinate system is geodetic or not.
609
     *
610
     * @param oracleSRID2 the coordinate system's oracle code
611
     * @param thas whether the table has a coordinate system set.
612
     * if not, the method returns false.
613
     * @return whether the coordinate system is geodetic or not.
614
     */
615
    public static boolean getIsGCS(String oracleSRID2, boolean thas) {
616

    
617
        if (!thas) return false;
618
        int ora_cs = 0;
619

    
620
        try {
621
            ora_cs = Integer.parseInt(oracleSRID2);
622
        }
623
        catch (Exception ex) {
624
            return false;
625
        }
626

    
627
        if (((ora_cs >= 8000) && (ora_cs <= 8999)) || (ora_cs == 524288)) {
628
            return true;
629
        } else {
630
                return false;
631
        }
632
    }
633

    
634
    private Rectangle2D getRectangle(double minx, double maxx, double miny,
635
        double maxy) {
636
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
637
                maxy - miny);
638

    
639
        return resp;
640
    }
641

    
642
    private void oneRowMetadata() {
643
        try {
644
            String _sql = "select " + getStandardSelectExpression() + ", c." +
645
                geoColName + " from " + getTableName() + " c ";
646

    
647
            st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
648
                    ResultSet.CONCUR_READ_ONLY);
649

    
650
            ResultSet _rs = st.executeQuery(_sql + " where (rownum = 1)");
651

    
652
            if (_rs.next()) {
653
                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
654
                shapeType = getShapeTypeOfStruct(sample_geo);
655
            }
656
            else {
657
                shapeType = FShape.MULTI;
658
            }
659

    
660
            // -----------------------
661
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
662
            metaData = _rs.getMetaData();
663

    
664
            userName = ((ConnectionJDBC)conn).getConnection().getMetaData().getUserName();
665

    
666
            // geoColInd = _rs.findColumn(geoColName);
667
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
668

    
669
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
670
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
671

    
672
            int cnt = metaData.getColumnCount();
673
            fieldNames = new String[cnt];
674

    
675
            for (int i = 0; i < cnt; i++) {
676
                fieldNames[i] = metaData.getColumnName(i + 1);
677
            }
678

    
679
            getIdFieldNames();
680

    
681
            adjustLyrDef();
682

    
683
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan
684
        }
685
        catch (SQLException se) {
686
            logger.error("While getting metadata. " + se.getMessage());
687
        }
688
    }
689

    
690
    private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
691

    
692
        int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue();
693
        
694
        int type_part = code % 10;
695
        int dim_part = code / 1000;
696

    
697
        int z_added = 0;
698
        if ((dim_part == 3) || (dim_part == 4)) {
699
                z_added = 512;
700
        }
701

    
702
        switch (type_part) {
703
        case 1:
704
            return z_added + FShape.POINT;
705

    
706
        case 2:
707
            return z_added + FShape.LINE;
708

    
709
        case 3:
710
            return z_added + FShape.POLYGON;
711

    
712
        case 4:
713
            return z_added + FShape.MULTI;
714

    
715
        case 5:
716
            return z_added + FShape.MULTIPOINT;
717

    
718
        case 6:
719
            return z_added + FShape.LINE;
720

    
721
        case 7:
722
            return z_added + FShape.POLYGON;
723
        }
724

    
725
        logger.error("Unknown geometry type: " + code);
726

    
727
        return FShape.NULL;
728
    }
729

    
730
    private String getIdFieldNames() {
731
        try {
732
            idFieldNames = "";
733

    
734
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
735
                idFieldNames = idFieldNames +
736
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
737
            }
738
        }
739
        catch (SQLException se) {
740
        }
741

    
742
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
743

    
744
        return idFieldNames;
745
    }
746

    
747
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
748
        int[] _res = new int[1];
749
        _res[0] = 1;
750

    
751
        return _res;
752
    }
753

    
754
    public String getSqlTotal() {
755
        // TODO Auto-generated method stub
756
        return "";
757
    }
758

    
759
    public String getCompleteWhere() {
760
        // TODO Auto-generated method stub
761
        return "";
762
    }
763

    
764
    /**
765
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
766
     * and uses directly that sentence to query the table).
767
     */
768
    public IFeatureIterator getFeatureIterator(String sql)
769
        throws DriverException {
770
        if (isNotAvailableYet) {
771
            return null;
772
        }
773

    
774
        singleCachedFeatureRowNum = -1;
775

    
776
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
777

    
778
        ResultSet localrs = (ResultSet) rs_st[0];
779
        Statement _st = (Statement) rs_st[1];
780

    
781
        return new OracleSpatialFeatureIterator(this, localrs, _st,
782
            oneBasedGeoColInd, use_geotools);
783
    }
784

    
785
    /**
786
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
787
     */
788
    public String getConnectionStringBeginning() {
789
        // oracle
790
        return CONN_STR_BEGIN;
791
    }
792

    
793
    public void open() throws DriverException {
794
    }
795

    
796
    /**
797
     * Gets Oracle's default port: 1521
798
     */
799
    public int getDefaultPort() {
800
        // oracle port
801
        return 1521;
802
    }
803

    
804
    /**
805
     * Gets the feature iterator for a given rectangle (the view's bounding box)
806
     * and a SRS.
807
     */
808
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
809
        throws DriverException {
810
        if (isNotAvailableYet) {
811
            return null;
812
        }
813

    
814
        singleCachedFeatureRowNum = -1;
815

    
816
        STRUCT local_st = shapeToStruct(r, FShape.NULL, true, false, true);
817

    
818
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
819

    
820
        ResultSet localrs = (ResultSet) rs_st[0];
821
        Statement _st = (Statement) rs_st[1];
822

    
823
        return new OracleSpatialFeatureIterator(this, localrs, _st,
824
            oneBasedGeoColInd, use_geotools);
825
    }
826

    
827
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
828
        if (workingAreaInTablesCS == null) return r;
829
        return doIntersect(r, workingAreaInTablesCS);
830
    }
831

    
832
    /**
833
     * This method reverts to the one without the fields specification.
834
     * The fields have been selected from the start.
835
     */
836
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
837
        String[] alphaNumericFieldsNeeded) throws DriverException {
838
        if (isNotAvailableYet) {
839
            return null;
840
        }
841

    
842
        singleCachedFeatureRowNum = -1;
843

    
844
        return getFeatureIterator(r, strEPSG);
845
    }
846

    
847
    public String getGeometryField(String fieldName) {
848
        return fieldName;
849

    
850
        // return "ASBINARY(" + fieldName + ")";
851
    }
852

    
853
    public DriverAttributes getDriverAttributes() {
854
        return drvAtts;
855
    }
856

    
857
    /**
858
     * Gets the requested geometry. Always performs a new query in this case.
859
     * This should be a rare way to get the geometries. The standard way is by using
860
     * the iterators.
861
     */
862
    public IGeometry getShape(int _ind) throws IOException {
863
        if (isNotAvailableYet) {
864
            return nullGeom;
865
        }
866

    
867
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
868

    
869
        String _sql = "select " + geoColName + " from " + getTableName() +
870
            " where rowid = ?";
871

    
872
        try {
873
            java.sql.PreparedStatement ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(_sql);
874
            ps.setObject(1, r_id);
875

    
876
            // Statement stmnt = conn.createStatement();
877
            ps.execute();
878

    
879
            ResultSet _res = ps.getResultSet();
880

    
881
            if (_res.next()) {
882
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
883
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
884
                _res.close();
885
                ps.close();
886

    
887
                return theGeom;
888
            }
889
            else {
890
                logger.error("Unable to get shape: " + _ind +
891
                    " (probably due to edition)");
892

    
893
                return nullGeom;
894
            }
895
        }
896
        catch (SQLException se) {
897
            throw new IOException("SQLException: " + se.getMessage());
898
        }
899
    }
900

    
901
    public boolean isWritable() {
902
        return true;
903
    }
904

    
905
    public String getName() {
906
        return NAME;
907
    }
908

    
909
    public int[] getPrimaryKeys()
910
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
911
        return pkOneBasedIndexes;
912
    }
913

    
914
    public void write(DataWare dataWare)
915
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
916
    }
917

    
918
    private void setIdRowTable() {
919
        hashRelate = new Hashtable();
920

    
921
        java.sql.PreparedStatement ps = null;
922

    
923
        try {
924
            String _sql = getIdAndElemInfoFullResulltSetQuery();
925

    
926
            logger.debug("SQL para leer ids: " + _sql);
927
            Statement st = null;
928

    
929

    
930
            st = ((ConnectionJDBC)conn).getConnection().createStatement(
931
                            ResultSet.TYPE_FORWARD_ONLY,
932
                            ResultSet.CONCUR_READ_ONLY);
933
            
934
            
935

    
936
            // st = ((ConnectionJDBC)conn).getConnection().createStatement();
937

    
938
             st.setFetchSize(FETCH_SIZE);
939
             logger.info("FETCH_SIZE = " + FETCH_SIZE);
940

    
941
            ResultSet _r = null;
942
            _r = st.executeQuery(_sql);
943

    
944
            ROWID ri = null;
945

    
946
            int row = 0;
947
            String gid;
948
            Value aux = null;
949

    
950
            // ----------------------------------- types init
951
            ArrayList types = new ArrayList();
952
            int types_aux = 0;
953

    
954
            ARRAY info_aux;
955
            int[] info_aux_int;
956
            int size;
957

    
958
            // ----------------------------------- types init
959
            logger.debug("Beginning of result set:");
960

    
961
            while (_r.next()) {
962
                // ---------------------------------------
963
                ri = (ROWID) _r.getObject(1);
964
                gid = ri.stringValue();
965
                aux = ValueFactory.createValue(gid);
966

    
967
                Integer intobj = new Integer(row);
968
                hashRelate.put(aux, intobj);
969
                rowToId.put(intobj, ri);
970

    
971
                if ((row % 5000) == 0) {
972
                    // ------------------------------------------- cancel load
973
                    if (cancelIDLoad) {
974
                        hashRelate.clear();
975
                        rowToId.clear();
976

    
977
                        return;
978
                    }
979

    
980
                    // -------------------------------------------
981
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
982
                    logger.info("IDs read: " + fmt);
983
                }
984

    
985
                row++;
986

    
987
                // --------------------------------------- types
988
                info_aux = (ARRAY) _r.getObject(2);
989

    
990
                if (info_aux == null) {
991
                    // logger.debug("NULL info array found in record: " + row);
992
                }
993
                else {
994
                    info_aux_int = info_aux.getIntArray();
995
                    size = info_aux_int.length / 3;
996

    
997
                    for (int i = 0; i < size; i++) {
998
                        types_aux = info_aux_int[(3 * i) + 1];
999
                        types.add(new Integer(types_aux % 1000));
1000
                    }
1001
                }
1002

    
1003
                // --------------------------------------- types end
1004
            }
1005

    
1006
            _r.close();
1007
//            ps.close();
1008
            st.close();
1009
            numReg = row;
1010

    
1011
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
1012

    
1013
            if (needsCollectionLayer) {
1014
                shapeType = FShape.MULTI;
1015
            }
1016
        }
1017
        catch (SQLException e) {
1018
            System.err.println("While setting id-row hashmap: " +
1019
                e.getMessage());
1020
        }
1021
    }
1022

    
1023
    public int getFieldCount()
1024
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1025
        try {
1026
            return metaData.getColumnCount();
1027
        }
1028
        catch (SQLException e) {
1029
            System.err.println("While getting field count: " + e.getMessage());
1030
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e.getMessage());
1031
        }
1032
    }
1033

    
1034
    public String[] getFieldNames() {
1035
        return fieldNames;
1036
    }
1037

    
1038
    public String getTotalFields() {
1039
        String strAux = "";
1040

    
1041
        for (int i = 0; i < fieldNames.length; i++) {
1042
            if (i == 0) {
1043
                strAux = fieldNames[i];
1044
            }
1045
            else {
1046
                strAux = strAux + ", " + fieldNames[i];
1047
            }
1048
        }
1049

    
1050
        return strAux;
1051
    }
1052

    
1053
    public int getFieldType(int idField)
1054
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1055
        int i = 0;
1056

    
1057
        try {
1058
            i = idField + 1; // idField viene basado en 0
1059

    
1060
            int __type = metaData.getColumnType(i);
1061

    
1062
            // we must add this entry because we did not remove the 'geometry' column
1063
            if (__type == Types.STRUCT) {
1064
                return Types.VARCHAR; // .STRUCT;
1065
                                      // ----------------------------------------------------------------------
1066
            }
1067

    
1068
            if (__type == Types.VARCHAR) {
1069
                return Types.VARCHAR;
1070
            }
1071

    
1072
            if (__type == Types.FLOAT) {
1073
                return Types.FLOAT;
1074
            }
1075

    
1076
            if (__type == Types.DOUBLE) {
1077
                return Types.DOUBLE;
1078
            }
1079

    
1080
            if (__type == Types.INTEGER) {
1081
                return Types.INTEGER;
1082
            }
1083

    
1084
            if (__type == Types.SMALLINT) {
1085
                return Types.SMALLINT;
1086
            }
1087

    
1088
            if (__type == Types.TINYINT) {
1089
                return Types.TINYINT;
1090
            }
1091

    
1092
            if (__type == Types.BIGINT) {
1093
                return Types.BIGINT;
1094
            }
1095

    
1096
            if (__type == Types.BIT) {
1097
                return Types.BIT;
1098
            }
1099

    
1100
            if (__type == Types.DATE) {
1101
                return Types.DATE;
1102
            }
1103

    
1104
            if (__type == Types.DECIMAL) {
1105
                return Types.DOUBLE;
1106
            }
1107

    
1108
            if (__type == Types.NUMERIC) {
1109
                return Types.DOUBLE;
1110
            }
1111

    
1112
            if (__type == Types.DATE) {
1113
                return Types.DATE;
1114
            }
1115

    
1116
            if (__type == Types.TIME) {
1117
                return Types.TIME;
1118
            }
1119

    
1120
            if (__type == Types.TIMESTAMP) {
1121
                return Types.TIMESTAMP;
1122
            }
1123
        }
1124
        catch (SQLException e) {
1125
            System.err.println("i = " + i);
1126
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e);
1127
        }
1128

    
1129
        return -1;
1130
    }
1131

    
1132
    public Value[] getAttributes(ResultSet rs) {
1133
        Value[] res = null;
1134
        
1135
        int fcount = 0;
1136

    
1137
        try {
1138
            fcount = rs.getMetaData().getColumnCount();
1139
            res = new Value[fcount];
1140

    
1141
            for (int i = 0; i < fcount; i++) {
1142
                Object obj = rs.getObject(i + 1);
1143
                String objToString = null;
1144

    
1145
                if (obj instanceof String) {
1146
                    objToString = (String) obj;
1147
                    res[i] = ValueFactory.createValue(objToString);
1148
                } else {
1149
                    if (obj instanceof ROWID) {
1150
                        objToString = ((ROWID) obj).stringValue();
1151
                        res[i] = ValueFactory.createValue(objToString);
1152
                    } else {
1153
                        if (obj instanceof STRUCT) {
1154
                            objToString = "STRUCT";
1155
                            res[i] = ValueFactory.createValue(objToString);
1156
                        } else {
1157
                            if (obj instanceof TIMESTAMP) {
1158
                                    TIMESTAMP aux = (TIMESTAMP) obj;
1159
                                objToString = aux.stringValue();
1160
                                Timestamp ts = flexibleTimeStamp(objToString);
1161
                                res[i] = ValueFactory.createValue(ts);
1162
                                
1163
                            } else {
1164
                                    
1165
                                    objToString = obj.toString();
1166
                                    int _type = getFieldType(i);
1167
                                    
1168
                                if (obj instanceof DATE) {
1169
                                        objToString = objToString.replace('-', '/');
1170
                                }
1171
                                res[i] = ValueFactory.createValueByType(
1172
                                                objToString, _type);
1173
                            }
1174
                        }
1175
                    }
1176
                }
1177
            }
1178
            
1179
        } catch (Exception se) {
1180
                
1181
                logger.error("While getting resultset attribute values: " + se.getMessage());
1182
                res = new Value[fcount];
1183
                for (int i=0; i<fcount; i++) res[i] = ValueFactory.createNullValue();
1184
        }
1185
        
1186
        return res;
1187
    }
1188

    
1189
    public Value[] getAttributesUsingMainMetadata(ResultSet rs) {
1190
        Value[] res = null;
1191

    
1192
        try {
1193
            int fcount = metaData.getColumnCount();
1194
            res = new Value[fcount];
1195

    
1196
            for (int i = 0; i < fcount; i++) {
1197
                Object obj = rs.getObject(i + 1);
1198
                String objToString = null;
1199
                int _type = -1;
1200

    
1201
                if (obj instanceof String) {
1202
                    objToString = (String) obj;
1203
                    _type = Types.VARCHAR;
1204
                }
1205
                else {
1206
                    if (obj instanceof ROWID) {
1207
                        objToString = ((ROWID) obj).stringValue();
1208
                        _type = Types.VARCHAR;
1209
                    }
1210
                    else {
1211
                        if (obj instanceof STRUCT) {
1212
                            objToString = "STRUCT";
1213
                            _type = Types.VARCHAR;
1214
                        }
1215
                        else {
1216
                            objToString = (obj == null) ? "NULL" : obj.toString();
1217
                            _type = getFieldType(i);
1218
                        }
1219
                    }
1220
                }
1221

    
1222
                // /*
1223
                if (_type == -1) {
1224
                    obj = null;
1225
                }
1226

    
1227
                // */
1228
                if (obj == null) {
1229
                    res[i] = ValueFactory.createNullValue();
1230
                }
1231
                else {
1232
                    if (_type == Types.DATE) {
1233
                        objToString = objToString.replace('-', '/');
1234
                    }
1235

    
1236
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1237
                }
1238
            }
1239
        }
1240
        catch (SQLException se) {
1241
            System.err.println("Error while getting attributes: " +
1242
                se.getMessage());
1243

    
1244
            return null;
1245
        }
1246
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1247
            System.err.println("Error while getting attributes: " +
1248
                e.getMessage());
1249

    
1250
            return null;
1251
        }
1252
        catch (ParseException e) {
1253
            System.err.println("Error while getting attributes: " +
1254
                e.getMessage());
1255

    
1256
            return null;
1257
        }
1258

    
1259
        return res;
1260
    }
1261

    
1262

    
1263
    public String getFieldName(int fieldId)
1264
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1265
        return fieldNames[fieldId];
1266
    }
1267

    
1268
    public int getFieldWidth(int fieldId) {
1269
        int i = -1;
1270

    
1271
        try {
1272
            int aux = fieldId + 1; // fieldId viene basado en 0
1273
            i = metaData.getColumnDisplaySize(aux);
1274
        }
1275
        catch (SQLException e) {
1276
            System.err.println("While getting field width: " + e.getMessage());
1277
        }
1278

    
1279
        if (i < 0) {
1280
            i = 255;
1281
        }
1282

    
1283
        return i;
1284
    }
1285

    
1286
    public Value getFieldValue(long rowIndex, int field_Id)
1287
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1288
        if (isNotAvailableYet) {
1289
            return nullVal;
1290
        }
1291

    
1292
        if ((singleCachedFeature != null) &&
1293
                (rowIndex == singleCachedFeatureRowNum)) {
1294
            return singleCachedFeature.getAttributes()[field_Id];
1295
        }
1296

    
1297
        // return ValueFactory.createNullValue();
1298
        ResultSet _r = null;
1299
        java.sql.PreparedStatement ps = null;
1300

    
1301
        try {
1302
            String rnq = getSearchId();
1303
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1304

    
1305
            ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(rnq);
1306
            ps.setObject(1, _id);
1307

    
1308
            ps.execute();
1309
            _r = ps.getResultSet();
1310
            _r.next();
1311
        }
1312
        catch (SQLException se) {
1313
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(se.getMessage());
1314
        }
1315

    
1316
        IFeature ife = null;
1317
        Value[] atts = null;
1318

    
1319
        try {
1320
            ROWID ri = (ROWID) _r.getObject(1);
1321
            atts = getAttributesUsingMainMetadata(_r);
1322

    
1323
            String gid = ri.stringValue();
1324
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1325
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1326
            ife = new DefaultFeature(theGeom, atts, gid);
1327
            _r.close();
1328
            ps.close();
1329
        }
1330
        catch (SQLException se) {
1331
            logger.error("Error while doing next(): " + se.getMessage(), se);
1332
        }
1333

    
1334
        // -------------------------------
1335
        singleCachedFeature = ife;
1336
        singleCachedFeatureRowNum = rowIndex;
1337

    
1338
        // -------------------------------
1339
        if (atts == null) {
1340
            return ValueFactory.createNullValue();
1341
        }
1342
        else {
1343
            return atts[field_Id];
1344
        }
1345
    }
1346

    
1347
    public static void showMemory() {
1348
        Runtime r = Runtime.getRuntime();
1349
        long mem = r.totalMemory() - r.freeMemory();
1350
        System.err.println("Memoria total: " + mem);
1351
    }
1352

    
1353
    public Rectangle2D getFullExtent() {
1354
            return full_Extent;
1355
    }
1356

    
1357
    /**
1358
     * Utility method to get a geometry from a struct.
1359
     *
1360
     * @param theStruct the struct to be converted
1361
     * @param use_gtools switch to use geotools classes or not
1362
     * @return the geometry
1363
     * @throws SQLException
1364
     */
1365
    public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
1366
        throws SQLException {
1367
        IGeometry _igeom = null;
1368

    
1369
        if (theStruct == null) {
1370
            return nullGeom;
1371
        }
1372

    
1373
        if (use_gtools) { // geotools
1374
//            _igeom = getGeotoolsIGeometry(theStruct);
1375
        }
1376
        else { // jgeometry
1377
            _igeom = getFMapGeometry(theStruct, false);
1378
        }
1379

    
1380
        return _igeom;
1381
    }
1382

    
1383
    /*
1384
    private IGeometry getFMapGeometry(JGeometry jg, boolean force_not_collection) {
1385
        int jgtype = jg.getType();
1386
        int dim = jg.getDimensions();
1387
        IGeometry ig = null;
1388

1389
        if ((jgtype != JGeometry.GTYPE_COLLECTION) &&
1390
                (isActuallyACollection(jg))) {
1391
            jgtype = JGeometry.GTYPE_COLLECTION;
1392
        }
1393

1394
        switch (jgtype) {
1395
        case JGeometry.GTYPE_COLLECTION:
1396

1397
            int srid = jg.getSRID();
1398
            ig = getFMapGeometryCollection(jg, dim, srid);
1399

1400
            break;
1401

1402
        case JGeometry.GTYPE_POINT:
1403
        case JGeometry.GTYPE_MULTIPOINT:
1404
            ig = getFMapGeometryPoint(jg, dim);
1405

1406
            break;
1407

1408
        case JGeometry.GTYPE_CURVE:
1409
        case JGeometry.GTYPE_MULTICURVE:
1410
            ig = getFMapGeometryMultiLineString(jg, dim);
1411

1412
            break;
1413

1414
        case JGeometry.GTYPE_POLYGON:
1415
        case JGeometry.GTYPE_MULTIPOLYGON:
1416
            ig = getFMapGeometryMultipolygon(jg, dim);
1417

1418
            break;
1419
        }
1420

1421
        return ig;
1422
    }
1423
    */
1424

    
1425
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim) {
1426
        // int __srid) {
1427

    
1428
            NUMBER _srid = new NUMBER(0);
1429
        NUMBER main_type = new NUMBER((dim * 1000) +
1430
                OracleSpatialUtils.getStructType(the_data));
1431

    
1432

    
1433
        Datum[] all_info_array = null;
1434
        Object[] elems_info_aray = null;
1435
        Datum[] all_ords = null;
1436

    
1437
        Object[] ords_of_groups = null;
1438
        Object[] _elems_info_aray = null;
1439
        try {
1440
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1441
            elems_info_aray = groupByElement(all_info_array);
1442
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1443

    
1444
            ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1445
            _elems_info_aray = new Object[elems_info_aray.length];
1446
        }
1447
        catch (SQLException e) {
1448
            logger.error("Unexpected error: " + e.getMessage());
1449
        }
1450

    
1451

    
1452
        for (int i = 0; i < elems_info_aray.length; i++) {
1453
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1454
        }
1455

    
1456
        // _elems_info_aray, ords_of_groups
1457
        int no_of_elems = ords_of_groups.length;
1458
        IGeometry[] geoms = new IGeometry[no_of_elems];
1459

    
1460
        for (int i = 0; i < no_of_elems; i++) {
1461
            Datum[] item_info_array = null;
1462
            Datum[] item_ords = null;
1463
            NUMBER gtype = null;
1464

    
1465
            try {
1466
                item_info_array = (Datum[]) _elems_info_aray[i];
1467
                item_ords = (Datum[]) ords_of_groups[i];
1468

    
1469
                gtype = new NUMBER((dim * 1000) +
1470
                        (item_info_array[1].intValue() % 1000));
1471

    
1472
                if (tableHasSrid) {
1473
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1474
                }
1475
            }
1476
            catch (SQLException se) {
1477
                logger.error("Unexpected error: " + se.getMessage());
1478
            }
1479

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

    
1483
            STRUCT itemst = null;
1484

    
1485
            if (tableHasSrid) {
1486

    
1487
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1488
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1489
            }
1490
            else {
1491
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1492
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1493
            }
1494

    
1495
            geoms[i] = getFMapGeometry(itemst, true);
1496
        }
1497

    
1498
        return new FGeometryCollection(geoms);
1499
    }
1500

    
1501
    /**
1502
     * Utility method to transform a struct into a IGeometry.
1503
     *
1504
     * @param st the struct to be converted
1505
     * @param force_not_collection t5his parameter is currently ignored
1506
     * @return the IGeometry
1507
     */
1508
    public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1509

    
1510
            if (st == null) {
1511
                    return new FNullGeometry();
1512
            }
1513

    
1514
        Datum[] the_data = null;
1515

    
1516
        try {
1517
            the_data = st.getOracleAttributes();
1518

    
1519
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1520
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1521

    
1522
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1523

    
1524
            if (dim < 2) {
1525
                dim = 2;
1526
            }
1527

    
1528
            IGeometry ig = null;
1529

    
1530
            if (isActuallyACollection(the_data)) {
1531
                    logger.debug("isActuallyACollection(the_data) = TRUE");
1532
                jgtype = FShape.MULTI;
1533
            }
1534

    
1535
            switch (jgtype) {
1536
            case FShape.MULTI:
1537

    
1538
                // int srid = ((NUMBER) the_data[1]).intValue();
1539
                ig = getFMapGeometryCollection(the_data, dim);
1540

    
1541
                break;
1542

    
1543
            case FShape.POINT:
1544
                ig = getFMapGeometryPoint(the_data, dim);
1545

    
1546
                break;
1547

    
1548
            case FShape.LINE:
1549
                ig = getFMapGeometryMultiLineString(the_data, dim);
1550

    
1551
                break;
1552

    
1553
            case FShape.POLYGON:
1554
                ig = getFMapGeometryMultipolygon(the_data, dim);
1555

    
1556
                break;
1557
            }
1558

    
1559
            return ig;
1560
        }
1561
        catch (SQLException e) {
1562
            logger.error(e);
1563
        }
1564

    
1565
        return null;
1566
    }
1567

    
1568
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1569
        int size = input.length / n;
1570
        double[] resp = new double[size];
1571

    
1572
        for (int i = 0; i < size; i++) {
1573
            resp[i] = input[(i * n) + ind];
1574
        }
1575

    
1576
        return resp;
1577
    }
1578

    
1579
    private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1580
        int size = input.length / n;
1581
        double[] resp = new double[size];
1582

    
1583
        for (int i = 0; i < size; i++) {
1584
            resp[i] = input[(i * n) + ind];
1585
        }
1586

    
1587
        return resp;
1588
    }
1589

    
1590
    /*
1591
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1592
        IGeometry ig = null;
1593

1594
        if (jg.isCircle()) {
1595
            ig = getCircleFromJGeometry(jg);
1596
        }
1597
        else {
1598
            Shape shape = jg.createShape();
1599
            GeneralPathX gpx = new GeneralPathX(shape);
1600

1601
            if (dim == 2) {
1602
                ig = ShapeFactory.createPolygon2D(gpx);
1603
            }
1604
            else {
1605
                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1606
                ig = ShapeFactory.createPolygon3D(gpx, z);
1607
            }
1608
        }
1609

1610
        return ig;
1611
    }
1612
    */
1613

    
1614
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1615
        IGeometry ig = null;
1616

    
1617
        if (OracleSpatialUtils.isCircle(the_data)) {
1618
            ig = getCircleFromStruct(the_data);
1619
        }
1620
        else {
1621
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1622

    
1623
            if (dim == 2) {
1624
                ig = ShapeFactory.createPolygon2D(gpx);
1625
            }
1626
            else {
1627
                double[] ords = null;
1628

    
1629
                try {
1630
                    ords = ((ARRAY) the_data[4]).getDoubleArray();
1631
                }
1632
                catch (SQLException se) {
1633
                    logger.error("While getting ordinates: " + se.getMessage(),
1634
                        se);
1635
                }
1636

    
1637
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1638
                ig = ShapeFactory.createPolygon3D(gpx, z);
1639
            }
1640
        }
1641

    
1642
        return ig;
1643
    }
1644

    
1645
    /*
1646
    private IGeometry getCircleFromJGeometry(JGeometry jg) {
1647
        double[] threep = jg.getOrdinatesArray();
1648
        Point2D[] three = new Point2D.Double[3];
1649
        three[0] = new Point2D.Double(threep[0], threep[1]);
1650
        three[1] = new Point2D.Double(threep[2], threep[3]);
1651
        three[2] = new Point2D.Double(threep[4], threep[5]);
1652

1653
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1654

1655
        Point2D cent = (Point2D) cent_rad[0];
1656
        double radius = ((Double) cent_rad[1]).doubleValue();
1657

1658
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1659

1660
        return circ;
1661
    }
1662
    */
1663

    
1664
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1665
        double[] threep = null;
1666

    
1667
        try {
1668
            threep = ((ARRAY) the_data[4]).getDoubleArray();
1669
        }
1670
        catch (SQLException se) {
1671
            logger.error("While getting ords from struct: " + se.getMessage(),
1672
                se);
1673

    
1674
            return new FNullGeometry();
1675
        }
1676

    
1677
        Point2D[] three = new Point2D.Double[3];
1678
        three[0] = new Point2D.Double(threep[0], threep[1]);
1679
        three[1] = new Point2D.Double(threep[2], threep[3]);
1680
        three[2] = new Point2D.Double(threep[4], threep[5]);
1681

    
1682
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1683

    
1684
        Point2D cent = (Point2D) cent_rad[0];
1685
        double radius = ((Double) cent_rad[1]).doubleValue();
1686

    
1687
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1688

    
1689
        return circ;
1690
    }
1691

    
1692
    /*
1693
    private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1694
        Shape shape = jg.createShape();
1695
        GeneralPathX gpx = new GeneralPathX(shape);
1696
        IGeometry ig = null;
1697

1698
        if (dim == 2) {
1699
            ig = ShapeFactory.createPolyline2D(gpx);
1700
        }
1701
        else {
1702
            double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1703
            ig = ShapeFactory.createPolyline3D(gpx, z);
1704
        }
1705

1706
        return ig;
1707
    }
1708
    */
1709

    
1710
    private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1711
        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1712
        IGeometry ig = null;
1713
        double[] ords = null;
1714

    
1715
        if (dim == 2) {
1716
            ig = ShapeFactory.createPolyline2D(gpx);
1717
        }
1718
        else {
1719
            ords = OracleSpatialUtils.getOrds(the_data);
1720

    
1721
            double[] z = getIndBigDecimalModule(ords, 2, dim);
1722
            ig = ShapeFactory.createPolyline3D(gpx, z);
1723
        }
1724

    
1725
        return ig;
1726
    }
1727

    
1728
    /*
1729
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1730
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1731

1732
            return getFMapGeometrySdoPoint(jg_point, dim);
1733
        }
1734

1735
        IGeometry ig = null;
1736
        int total_size = jg_point.getOrdinatesArray().length;
1737
        int no_po = total_size / dim;
1738
        double[] x = new double[no_po];
1739
        double[] y = new double[no_po];
1740
        double[] z = new double[no_po];
1741

1742
        for (int i = 0; i < no_po; i++) {
1743
            x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1744
            y[i] = jg_point.getOrdinatesArray()[(i * dim) + 1];
1745

1746
            if (dim >= 3) {
1747
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1748
            }
1749
        }
1750

1751
        if (dim == 2) {
1752
            if (no_po == 1) {
1753
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1754
            }
1755
            else {
1756
                ig = ShapeFactory.createMultipoint2D(x, y);
1757
            }
1758
        }
1759
        else {
1760
            if (no_po == 1) {
1761
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1762
            }
1763
            else {
1764
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1765
            }
1766
        }
1767

1768
        return ig;
1769
    }
1770
    */
1771

    
1772
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1773
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1774

    
1775
        if (ords == null) { // sdo_point
1776

    
1777
            return getFMapGeometrySdoPoint(the_data, dim);
1778
        }
1779

    
1780
        IGeometry ig = null;
1781
        int total_size = ords.length;
1782
        int no_po = total_size / dim;
1783
        double[] x = new double[no_po];
1784
        double[] y = new double[no_po];
1785
        double[] z = new double[no_po];
1786

    
1787
        for (int i = 0; i < no_po; i++) {
1788
            x[i] = ords[i * dim]; // pp[i].getX();
1789
            y[i] = ords[(i * dim) + 1];
1790

    
1791
            if (dim >= 3) {
1792
                z[i] = ords[(i * dim) + 2];
1793
            }
1794
        }
1795

    
1796
        if (dim == 2) {
1797
            if (no_po == 1) {
1798
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1799
            }
1800
            else {
1801
                ig = ShapeFactory.createMultipoint2D(x, y);
1802
            }
1803
        }
1804
        else {
1805
            if (no_po == 1) {
1806
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1807
            }
1808
            else {
1809
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1810
            }
1811
        }
1812

    
1813
        return ig;
1814
    }
1815

    
1816
    /*
1817
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1818
        double[] p = jgp.getPoint();
1819
        IGeometry ig = null;
1820

1821
        if (d == 2) {
1822
            ig = ShapeFactory.createPoint2D(p[0], p[1]);
1823
        }
1824
        else {
1825
            ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1826
        }
1827

1828
        return ig;
1829
    }
1830
    */
1831

    
1832
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1833
        double x = 0;
1834
        double y = 0;
1835
        double z = 0;
1836

    
1837
        try {
1838
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1839
            x = ((NUMBER) aux[0]).doubleValue();
1840
            y = ((NUMBER) aux[1]).doubleValue();
1841

    
1842
            if (d > 2) {
1843
                z = ((NUMBER) aux[2]).doubleValue();
1844
            }
1845
        }
1846
        catch (SQLException se) {
1847
            logger.error("While getting sdo point ordinates: " +
1848
                se.getMessage(), se);
1849
        }
1850

    
1851
        IGeometry ig = null;
1852

    
1853
        if (d == 2) {
1854
            ig = ShapeFactory.createPoint2D(x, y);
1855
        }
1856
        else {
1857
            ig = ShapeFactory.createPoint3D(x, y, z);
1858
        }
1859

    
1860
        return ig;
1861
    }
1862

    
1863
    /*
1864
    private boolean isActuallyACollection(JGeometry jg) {
1865
        int[] info = jg.getElemInfo();
1866

1867
        if (info == null) {
1868
            return false; // sdo_point
1869
        }
1870

1871
        int size = info.length / 3;
1872

1873
        if (size == 1) {
1874
            return false;
1875
        }
1876

1877
        if (size == 2) {
1878
            return ((info[1] % 1000) != (info[4] % 1000));
1879
        }
1880

1881
        int second = info[4] % 1000;
1882

1883
        for (int i = 2; i < size; i++) {
1884
            if ((info[(i * 3) + 1] % 1000) != second) {
1885
                return true;
1886
            }
1887
        }
1888

1889
        return false;
1890
    }
1891
    */
1892

    
1893
    private boolean isActuallyACollection(Datum[] the_data) {
1894
        int[] info = null;
1895

    
1896
        try {
1897
            ARRAY aux = (ARRAY) the_data[3];
1898

    
1899
            if (aux == null) {
1900
                return false;
1901
            }
1902

    
1903
            info = aux.getIntArray();
1904
        }
1905
        catch (SQLException se) {
1906
            logger.error("While checking collection: " + se.getMessage());
1907
            return false;
1908
        }
1909

    
1910
        if (info == null) {
1911
            return false; // sdo_point
1912
        }
1913

    
1914
        int size = info.length / 3;
1915

    
1916
        if (size == 1) {
1917
            return false;
1918
        }
1919

    
1920
        if (size == 2) {
1921
            return ((info[1] % 1000) != (info[4] % 1000)) &&
1922
            ( ! ((info[1] == 1005) && (info[4] == 2)) );
1923
        }
1924

    
1925
        int second = info[4] % 1000;
1926
        int item = 0;
1927

    
1928
        for (int i = 2; i < size; i++) {
1929
                item = info[(i * 3) + 1] % 1000;
1930
            if ((item != second) &&
1931
                            ( ! ((item == 5) && (second == 2)) )
1932
                            ) {
1933
                return true;
1934
            }
1935
        }
1936

    
1937
        return false;
1938
    }
1939

    
1940
    /*
1941
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1942
        int main_type = jg.getType();
1943

1944
        int[] all_info_array = jg.getElemInfo();
1945
        Object[] elems_info_aray = groupByElement(all_info_array);
1946
        double[] all_ords = jg.getOrdinatesArray();
1947
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1948
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1949

1950
        for (int i = 0; i < elems_info_aray.length; i++) {
1951
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1952
        }
1953

1954
        // _elems_info_aray, ords_of_groups
1955
        int no_of_elems = ords_of_groups.length;
1956
        IGeometry[] geoms = new IGeometry[no_of_elems];
1957

1958
        for (int i = 0; i < no_of_elems; i++) {
1959
            int[] item_info_array = (int[]) _elems_info_aray[i];
1960
            double[] item_ords = (double[]) ords_of_groups[i];
1961
            int gtype = (dim * 1000) + (item_info_array[1] % 1000);
1962

1963
            // if it's the first geometry, the type is the collection's main type (no?)
1964
            if (i == 0) {
1965
                gtype = main_type;
1966
            }
1967

1968
            JGeometry itemjg = null;
1969

1970
            if (tableHasSrid) {
1971
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1972
            }
1973
            else {
1974
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1975
            }
1976

1977
            geoms[i] = getFMapGeometry(itemjg, true);
1978
        }
1979

1980
        return new FGeometryCollection(geoms);
1981
    }
1982
    */
1983

    
1984
    private Datum[] updateIndexes(Datum[] info) {
1985
        int size = info.length / 3;
1986
        NUMBER[] resp = new NUMBER[3 * size];
1987

    
1988
        try {
1989
            int rest = info[0].intValue() - 1;
1990

    
1991
            for (int i = 0; i < size; i++) {
1992
                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1993
                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
1994
                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
1995
            }
1996
        }
1997
        catch (SQLException se) {
1998
            logger.error("Unexpected error: " + se.getMessage());
1999
        }
2000

    
2001
        return resp;
2002
    }
2003

    
2004
    private int[] updateIndexes(int[] info) {
2005
        int size = info.length / 3;
2006
        int[] resp = new int[3 * size];
2007
        int rest = info[0] - 1;
2008

    
2009
        for (int i = 0; i < size; i++) {
2010
            resp[3 * i] = info[3 * i] - rest;
2011
            resp[(3 * i) + 1] = info[(3 * i) + 1];
2012
            resp[(3 * i) + 2] = info[(3 * i) + 2];
2013
        }
2014

    
2015
        return resp;
2016
    }
2017

    
2018
    private int[] appendIntArrays(int[] head, int[] tail) {
2019
        int[] resp = new int[head.length + tail.length];
2020
        int hsize = head.length;
2021

    
2022
        for (int i = 0; i < hsize; i++) {
2023
            resp[i] = head[i];
2024
        }
2025

    
2026
        for (int i = 0; i < tail.length; i++) {
2027
            resp[hsize + i] = tail[i];
2028
        }
2029

    
2030
        return resp;
2031
    }
2032

    
2033
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
2034
        Datum[] resp = new Datum[head.length + tail.length];
2035
        int hsize = head.length;
2036

    
2037
        for (int i = 0; i < hsize; i++) {
2038
            resp[i] = head[i];
2039
        }
2040

    
2041
        for (int i = 0; i < tail.length; i++) {
2042
            resp[hsize + i] = tail[i];
2043
        }
2044

    
2045
        return resp;
2046
    }
2047

    
2048
    private int[] getNthGroupOfThree(int[] list, int n) {
2049
        int[] resp = new int[3];
2050
        resp[0] = list[3 * n];
2051
        resp[1] = list[(3 * n) + 1];
2052
        resp[2] = list[(3 * n) + 2];
2053

    
2054
        return resp;
2055
    }
2056

    
2057
    private Datum[] getNthGroupOfThree(Datum[] list, int n) {
2058
        Datum[] resp = new Datum[3];
2059
        resp[0] = list[3 * n];
2060
        resp[1] = list[(3 * n) + 1];
2061
        resp[2] = list[(3 * n) + 2];
2062

    
2063
        return resp;
2064
    }
2065

    
2066
    private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
2067
        Datum[] resp = new Datum[last_inc - first_inc + 1];
2068

    
2069
        for (int i = first_inc; i <= last_inc; i++) {
2070
            resp[i - first_inc] = all[i];
2071
        }
2072

    
2073
        return resp;
2074
    }
2075

    
2076
    private double[] getSubSet(double[] all, int first_inc, int last_inc) {
2077
        double[] resp = new double[last_inc - first_inc + 1];
2078

    
2079
        for (int i = first_inc; i <= last_inc; i++) {
2080
            resp[i - first_inc] = all[i];
2081
        }
2082

    
2083
        return resp;
2084
    }
2085

    
2086
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) throws SQLException {
2087
        Object[] resp = new Object[groups.length];
2088

    
2089
        if (resp.length == 1) {
2090
            resp[0] = all;
2091

    
2092
            return resp;
2093
        }
2094

    
2095
        int ind = 0;
2096
        Datum[] aux = (Datum[]) groups[1];
2097
        int _end = aux[0].intValue() - 2;
2098
        Datum[] ord_aux = getSubSet(all, 0, _end);
2099

    
2100
        int _start = _end + 1;
2101
        resp[ind] = ord_aux;
2102
        ind++;
2103

    
2104
        for (int i = 2; i < groups.length; i++) {
2105
            aux = (Datum[]) groups[i];
2106
            _end = aux[0].intValue() - 2;
2107
            ord_aux = getSubSet(all, _start, _end);
2108
            resp[ind] = ord_aux;
2109
            ind++;
2110
            _start = _end + 1;
2111
        }
2112

    
2113
        // last
2114
        _end = all.length - 1;
2115
        ord_aux = getSubSet(all, _start, _end);
2116
        resp[groups.length - 1] = ord_aux;
2117

    
2118
        return resp;
2119
    }
2120

    
2121
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2122
        Object[] resp = new Object[groups.length];
2123

    
2124
        if (resp.length == 1) {
2125
            resp[0] = all;
2126

    
2127
            return resp;
2128
        }
2129

    
2130
        int ind = 0;
2131
        int[] aux = (int[]) groups[1];
2132
        int _end = aux[0] - 2;
2133
        double[] ord_aux = getSubSet(all, 0, _end);
2134

    
2135
        int _start = _end + 1;
2136
        resp[ind] = ord_aux;
2137
        ind++;
2138

    
2139
        for (int i = 2; i < groups.length; i++) {
2140
            aux = (int[]) groups[i];
2141
            _end = aux[0] - 2;
2142
            ord_aux = getSubSet(all, _start, _end);
2143
            resp[ind] = ord_aux;
2144
            ind++;
2145
            _start = _end + 1;
2146
        }
2147

    
2148
        // last
2149
        _end = all.length - 1;
2150
        ord_aux = getSubSet(all, _start, _end);
2151
        resp[groups.length - 1] = ord_aux;
2152

    
2153
        return resp;
2154
    }
2155

    
2156
    private Object[] groupByElement(int[] all_elem) {
2157
        ArrayList resp = new ArrayList();
2158

    
2159
        int size = all_elem.length / 3;
2160

    
2161
        int[] aux = getNthGroupOfThree(all_elem, 0);
2162

    
2163
        int[] newaux;
2164
        int i = 1;
2165

    
2166
        while (i < size) {
2167
            newaux = getNthGroupOfThree(all_elem, i);
2168

    
2169
            if (newaux[0] == aux[0]) {
2170
                // aux[2] says how many components
2171
                for (int j = 0; j < aux[2]; j++) {
2172
                    aux = appendIntArrays(aux,
2173
                            getNthGroupOfThree(all_elem, j + i));
2174
                }
2175

    
2176
                resp.add(aux);
2177
                i = i + aux[2];
2178
                aux = getNthGroupOfThree(all_elem, i);
2179
            }
2180
            else {
2181
                if (newaux[1] == 2003) {
2182
                    aux = appendIntArrays(aux, newaux);
2183
                }
2184
                else {
2185
                    resp.add(aux);
2186
                    aux = getNthGroupOfThree(all_elem, i);
2187
                }
2188
            }
2189

    
2190
            i++;
2191
        }
2192

    
2193
        resp.add(aux);
2194

    
2195
        return resp.toArray();
2196
    }
2197

    
2198
    private Object[] groupByElement(Datum[] all_elem) {
2199
        ArrayList resp = new ArrayList();
2200

    
2201
        int size = all_elem.length / 3;
2202

    
2203
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2204

    
2205
        Datum[] newaux;
2206
        int i = 1;
2207

    
2208
        try {
2209
            while (i < size) {
2210
                newaux = getNthGroupOfThree(all_elem, i);
2211

    
2212
                if (newaux[0] == aux[0]) {
2213
                    // aux[2] says how many components
2214
                    for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
2215
                        aux = appendDatArrays(aux,
2216
                                getNthGroupOfThree(all_elem, j + i));
2217
                    }
2218

    
2219
                    resp.add(aux);
2220
                    i = i + ((NUMBER) aux[2]).intValue();
2221
                    aux = getNthGroupOfThree(all_elem, i);
2222
                }
2223
                else {
2224
                    if (((NUMBER) newaux[1]).intValue() == 2003) {
2225
                        aux = appendDatArrays(aux, newaux);
2226
                    }
2227
                    else {
2228
                        resp.add(aux);
2229
                        aux = getNthGroupOfThree(all_elem, i);
2230
                    }
2231
                }
2232

    
2233
                i++;
2234
            }
2235
        }
2236
        catch (SQLException se) {
2237
            logger.error("Unexpected error: " + se.getMessage());
2238
        }
2239

    
2240
        resp.add(aux);
2241

    
2242
        return resp.toArray();
2243
    }
2244

    
2245
    /*
2246
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2247
        Point2D p = _jgeom.getJavaPoint();
2248
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2249

2250
        return ig;
2251
    }
2252

2253
    private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2254
        Point2D[] pp = _jgeom.getJavaPoints();
2255
        int l = pp.length;
2256
        double[] x = new double[l];
2257
        double[] y = new double[l];
2258

2259
        for (int i = 0; i < l; i++) {
2260
            x[i] = pp[i].getX();
2261
            y[i] = pp[i].getY();
2262
        }
2263

2264
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2265

2266
        return ig;
2267
    }
2268

2269
    private IGeometry getJGeometryOther(JGeometry _jgeom) {
2270
        int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2271
        Shape shape = _jgeom.createShape();
2272
        GeneralPathX gpx = new GeneralPathX(shape);
2273
        IGeometry ig = null;
2274

2275
        switch (type) {
2276
        case FShape.LINE:
2277

2278
            FPolyline2D fpl = new FPolyline2D(gpx);
2279
            ig = ShapeFactory.createPolyline2D(gpx);
2280

2281
            break;
2282

2283
        case FShape.POLYGON:
2284

2285
            FPolygon2D fpg = new FPolygon2D(gpx);
2286
            ig = ShapeFactory.createPolygon2D(gpx);
2287

2288
            break;
2289
        }
2290

2291
        return ig;
2292
    }
2293
    */
2294

    
2295
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
2296
        /*
2297
         * Tipos en Oracle Spatial usando JGeometry
2298
         *
2299
         * GTYPE_COLLECTION collection geometry type
2300
         * GTYPE_CURVE curve geoemtry type
2301
         * GTYPE_MULTICURVE multi-curve geometry type
2302
         * GTYPE_MULTIPOINT multi-point geometry type
2303
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
2304
         * GTYPE_POINT point geometry type
2305
         * GTYPE_POLYGON  polygon geometry type
2306
         *
2307
         * Tipos gvSIG FShape
2308
         *
2309
         * NULL = 0;
2310
         * POINT = 1;
2311
         * LINE = 2;
2312
         * POLYGON = 4;
2313
         * TEXT = 8;
2314
         * MULTI = 16;
2315
         * MULTIPOINT = 32;
2316
         * CIRCLE = 64;
2317
         * ARC = 128;
2318
         * ELLIPSE=256;
2319
         * Z=512
2320
         */
2321
        switch (type) {
2322
        case JGeometry_GTYPE_POLYGON:
2323
        case JGeometry_GTYPE_MULTIPOLYGON:
2324
            return FShape.POLYGON;
2325

    
2326
        case JGeometry_GTYPE_CURVE:
2327
        case JGeometry_GTYPE_MULTICURVE:
2328
            return FShape.LINE;
2329
        }
2330

    
2331
        System.err.println("Unhandled Oracle Spatial geometry type: " + type +
2332
            " (conversion returned FShape.NULL)");
2333

    
2334
        return FShape.NULL;
2335
    }
2336

    
2337
    private void cleanWhereClause() {
2338
        emptyWhereClause = false;
2339

    
2340
        String aux = getWhereClauseWithoutWhere();
2341

    
2342
        for (int i = 0; i < aux.length(); i++)
2343
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
2344
                return;
2345
            }
2346

    
2347
        getLyrDef().setWhereClause("");
2348
        emptyWhereClause = true;
2349
    }
2350

    
2351
    private String getValidViewConstructor(
2352
                    STRUCT _st,
2353
                    String ora_srid,
2354
                    boolean _hassrid,
2355
                    boolean _isgeocs) {
2356

    
2357
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
2358
            String resp = "";
2359
            if ((_hassrid) && (_isgeocs)) {
2360
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
2361
            } else {
2362
                    resp = sdo;
2363
            }
2364

    
2365
            return resp;
2366
    }
2367

    
2368
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2369
        String resp = "";
2370

    
2371
        if (isGeogCS) {
2372
            String vport = "sdo_filter(" + geoColName +
2373
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
2374
                "), 'querytype=window') = 'TRUE'";
2375

    
2376
                resp = "select " + getStandardSelectExpression() + ", c." +
2377
                    geoColName + " from " + getTableName() + " c where ";
2378
                if (idsLoadWhere.length() > 0) {
2379
                        resp = resp + " (" + idsLoadWhere + ") AND ";
2380
                }
2381
                resp = resp + "(" + vport + ")";
2382
        }
2383
        else {
2384
                resp = "select " + getStandardSelectExpression() + ", c." +
2385
                    geoColName + " from " + getTableName() + " c where ";
2386
                if (idsLoadWhere.length() > 0) {
2387
                        resp = resp + " (" + idsLoadWhere + ") AND ";
2388
                }
2389
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
2390
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
2391
        }
2392

    
2393
//        return "select " + getStandardSelectExpression() + ", c." +
2394
//        geoColName + " from " + getTableName() + " c";
2395
        return resp;
2396
    }
2397

    
2398
    public void setWorkingArea(Rectangle2D rect) {
2399
    }
2400

    
2401
    private void setWAStructt() {
2402
    }
2403

    
2404
    private Geometry shapeToGeometry(Shape shp) {
2405
        if (shp == null) {
2406
            return null;
2407
        }
2408

    
2409
        int type = FShape.POLYGON;
2410

    
2411
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2412
            type = FShape.LINE;
2413
        }
2414

    
2415
        if (shp instanceof FPoint2D) {
2416
            type = FShape.POINT;
2417
        }
2418

    
2419
        if (shp instanceof FMultiPoint2D) {
2420
            type = FShape.MULTIPOINT;
2421
        }
2422

    
2423
        GeneralPathX wagp = new GeneralPathX(shp);
2424
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2425

    
2426
        return FConverter.java2d_to_jts(fwagp);
2427
    }
2428

    
2429
    /*
2430
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2431
        Shape shape = _jg.createShape();
2432

2433
        return shape.getBounds2D();
2434
    }
2435
    */
2436

    
2437
    private void printStruct(STRUCT st) {
2438
        System.out.println("----------------------------------------------");
2439

    
2440
        try {
2441
            Object[] att = st.getAttributes();
2442
            int l = att.length;
2443

    
2444
            for (int i = 0; i < l; i++) {
2445
                System.out.println("ATT " + i + ": " + att[i].toString());
2446
            }
2447
        }
2448
        catch (Exception ex) {
2449
            System.out.println(
2450
                "- Error ---------------------------------------");
2451
        }
2452

    
2453
        System.out.println("----------------------------------------------");
2454
    }
2455

    
2456
    private static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
2457
        boolean isView, boolean _isGeogCS, String _oracleSRID, IConnection __conn) {
2458
        Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2459
        Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2460

    
2461
        if ((_isGeogCS) && (isView)) {
2462
            c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2463
            c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2464
        }
2465

    
2466
        STRUCT resp = null;
2467

    
2468
        try {
2469
            // System.out.println("ABIERTA: " + (!conn.isClosed()));
2470
            // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2471
            // Object[] old_obj = resp.getAttributes();
2472
            int size = 5;
2473
            Object[] new_obj = new Object[size];
2474

    
2475
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2476
            new_obj[0] = new NUMBER(2003);
2477

    
2478
            if (hasSrid) {
2479
                new_obj[1] = new NUMBER(_oracleSRID);
2480
            }
2481
            else {
2482
                new_obj[1] = null;
2483
            }
2484

    
2485
            new_obj[2] = null;
2486

    
2487
            NUMBER[] elem_info = new NUMBER[3];
2488
            elem_info[0] = new NUMBER(1);
2489
            elem_info[1] = new NUMBER(1003);
2490
            elem_info[2] = new NUMBER(3);
2491
            new_obj[3] = elem_info;
2492

    
2493
            NUMBER[] ords = null;
2494
            ords = new NUMBER[4];
2495
            ords[0] = new NUMBER(c1.getX());
2496
            ords[1] = new NUMBER(c1.getY());
2497
            ords[2] = new NUMBER(c2.getX());
2498
            ords[3] = new NUMBER(c2.getY());
2499
            new_obj[4] = ords;
2500

    
2501
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2502
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2503
                            ((ConnectionJDBC)__conn).getConnection());
2504

    
2505
            resp = new STRUCT(dsc,((ConnectionJDBC)__conn).getConnection(), new_obj);
2506
        }
2507
        catch (Exception ex) {
2508
            logger.error("Error while creating rect struct: " +
2509
                ex.getMessage(), ex);
2510
        }
2511

    
2512
        return resp;
2513
    }
2514

    
2515
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2516
        boolean hasSrid) throws DriverException {
2517
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
2518
        String main_sel = "";
2519

    
2520
        if (fixsql == null) {
2521
            // main_sel = getMainSelect3(var_name);
2522
                String idswhere = getIdsQueryWhereClause(false);
2523
            main_sel = getMainSelect(sdo_intersect, idswhere);
2524
        }
2525
        else {
2526
            main_sel = fixsql;
2527
        }
2528

    
2529
        logger.debug("MAIN SEL = " + main_sel);
2530

    
2531
        ResultSet _rs = null;
2532
        Statement _stmnt = null;
2533
        Object[] _resp = new Object[2];
2534

    
2535
        try {
2536
            _stmnt = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
2537
                    ResultSet.CONCUR_READ_ONLY);
2538
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2539
            _stmnt.setFetchSize(FETCH_SIZE);
2540

    
2541
            _rs = _stmnt.executeQuery(main_sel);
2542

    
2543
            // stmnt.close();
2544
        }
2545
        catch (SQLException se) {
2546
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
2547
                se);
2548
            throw new DriverException(se);
2549
        }
2550

    
2551
        // this method returns the statement too, so that it can be closed afterwards
2552
        _resp[0] = _rs;
2553
        _resp[1] = _stmnt;
2554

    
2555
        return _resp;
2556
    }
2557

    
2558
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2559
        String resp = "";
2560

    
2561
        try {
2562
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2563
            String mdsys_sdo_ordinate_array = "";
2564
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2565

    
2566
            for (int i = 0; i < vertices.length; i++) {
2567
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2568
                    vertices[i].doubleValue() + ", ";
2569
            }
2570

    
2571
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2572
                    mdsys_sdo_ordinate_array.length() - 2);
2573
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2574
                mdsys_sdo_ordinate_array + ")";
2575

    
2576
            String aux = "";
2577

    
2578
            if (hasSrid) {
2579
                aux = oracleSRID;
2580

    
2581
                if (_isGeogCS) {
2582
                    aux = "0";
2583
                }
2584
            }
2585
            else {
2586
                aux = "null";
2587
            }
2588

    
2589
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
2590
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
2591
                ")";
2592
        }
2593
        catch (Exception ex) {
2594
            System.err.println("Error while getting sdo contructor: " +
2595
                ex.getMessage());
2596
        }
2597

    
2598
        return resp;
2599
    }
2600

    
2601
    private String getIdsQueryWhereClause(boolean with_where) {
2602
                String resp = "";
2603

    
2604
                String _where = "";
2605
                if (with_where) _where = " where ";
2606

    
2607
                if (workingAreaInTablesCSStruct == null) {
2608
                        if (emptyWhereClause) {
2609
                                // return "select rowid from " + getTableName();
2610
                        } else {
2611
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
2612
                                                + ")";
2613
                        }
2614
                } else {
2615
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
2616
                                        oracleSRID, tableHasSrid, isGeogCS);
2617

    
2618
                        if (emptyWhereClause) {
2619
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
2620
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2621
                        } else {
2622
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
2623
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
2624
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2625
                        }
2626
                }
2627

    
2628
                // resp = resp + " order by rowid";
2629
                return resp;
2630
        }
2631

    
2632
    public String getIdAndElemInfoFullResulltSetQuery() {
2633
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
2634
            getTableName() + " c";
2635

    
2636
        resp = resp + getIdsQueryWhereClause(true);
2637
        return resp;
2638
    }
2639

    
2640
    private String getSearchId() {
2641
        if (emptyWhereClause) {
2642
            return "select " + getStandardSelectExpression() + ", c." +
2643
            geoColName + " from " + getTableName() + " c where rowid = ?";
2644
        }
2645
        else {
2646
            return "select " + getStandardSelectExpression() + ", c." +
2647
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
2648
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
2649
        }
2650
    }
2651

    
2652
    public int getShapeType() {
2653
        return shapeType;
2654
    }
2655

    
2656
    private String getWhereClauseWithoutWhere() {
2657
        String resp = "";
2658
        String old = getLyrDef().getWhereClause();
2659
        resp = old;
2660

    
2661
        if (old.length() <= 6) {
2662
            return old;
2663
        }
2664

    
2665
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2666
            resp = resp.substring(6, resp.length());
2667
        }
2668

    
2669
        return resp;
2670
    }
2671

    
2672
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2673
        if (r1.getMaxX() <= r2.getMinX()) {
2674
            return null;
2675
        }
2676

    
2677
        if (r2.getMaxX() <= r1.getMinX()) {
2678
            return null;
2679
        }
2680

    
2681
        if (r1.getMaxY() <= r2.getMinY()) {
2682
            return null;
2683
        }
2684

    
2685
        if (r2.getMaxY() <= r1.getMinY()) {
2686
            return null;
2687
        }
2688

    
2689
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2690
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2691
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2692
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2693

    
2694
        double w = maxx - minx;
2695
        double h = maxy - miny;
2696

    
2697
        return new Rectangle2D.Double(minx, miny, w, h);
2698
    }
2699

    
2700
    private static int maxSizeForFieldType(int _type) {
2701
        switch (_type) {
2702
        case Types.VARCHAR:
2703
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2704

    
2705
        case Types.LONGVARCHAR:
2706
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2707
        }
2708

    
2709
        return -1;
2710
    }
2711

    
2712
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2713
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2714

    
2715
        switch (fieldDesc.getFieldType()) {
2716
        case Types.SMALLINT:
2717
            aux = "NUMBER(5, 0)";
2718

    
2719
            break;
2720

    
2721
        case Types.INTEGER:
2722
            aux = "NUMBER(10, 0)";
2723

    
2724
            break;
2725

    
2726
        case Types.BIGINT:
2727
            aux = "NUMBER(38, 0)";
2728

    
2729
            break;
2730

    
2731
        case Types.BOOLEAN:
2732
            aux = "NUMBER(1, 0)";
2733

    
2734
            break;
2735

    
2736
        case Types.DECIMAL:
2737
            aux = "NUMBER";
2738

    
2739
            break;
2740

    
2741
        case Types.NUMERIC:
2742
            aux = "NUMBER";
2743

    
2744
            break;
2745

    
2746
        case Types.DOUBLE:
2747
            aux = "FLOAT";
2748

    
2749
            break;
2750

    
2751
        case Types.FLOAT:
2752
            aux = "FLOAT";
2753

    
2754
            break;
2755

    
2756
        case Types.CHAR:
2757
            aux = "CHAR(1 BYTE)";
2758

    
2759
            break;
2760

    
2761
        case Types.VARCHAR:
2762
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2763

    
2764
            break;
2765

    
2766
        case Types.LONGVARCHAR:
2767
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2768

    
2769
            break;
2770
        }
2771

    
2772
        return aux;
2773
    }
2774

    
2775
    // -----------------------------------------------------------
2776
    // -----------------------------------------------------------
2777
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2778
        return "DROP TABLE " + dbLayerDef.getTableName() +
2779
        " CASCADE CONSTRAINTS";
2780
    }
2781

    
2782
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2783
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2784

    
2785
        String type = "";
2786
        String name = "";
2787

    
2788
        String resp = "CREATE TABLE " + dbLayerDef.getTableName() + " ( ";
2789

    
2790
        for (int i = 0; i < flds.length; i++) {
2791
            name = flds[i].getFieldName();
2792

    
2793
            // -------------- FORBIDDEN FIELD NAMES -----------------
2794
            if (!isOracleAllowedFieldname(name)) {
2795
                continue;
2796
            }
2797

    
2798
            // ------------------------------------------------------
2799
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
2800
            }
2801
            else {
2802
                name = getValidOracleID(name, i);
2803
                resp = resp + "\"" + name + "\" ";
2804
                type = fieldTypeToSqlStringType(flds[i]);
2805
                resp = resp + type + ", ";
2806
            }
2807
        }
2808

    
2809
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2810
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2811
        resp = resp + ", ";
2812

    
2813
        String pk = "CONSTRAINT " + getDerivedNAme(dbLayerDef.getTableName(), "PK") +
2814
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD +
2815
            "\") ENABLE";
2816

    
2817
        resp = resp + pk + " )";
2818

    
2819
        return resp;
2820
    }
2821

    
2822
    private static String getDerivedNAme(String tname, String suffix) {
2823

    
2824
            int ind = tname.lastIndexOf(".");
2825
            if (ind == -1) {
2826

    
2827
                    int l = Math.min(28, tname.length());
2828
                    return tname.substring(0, l) + "_" + suffix;
2829

    
2830
            } else {
2831

    
2832
                    String pre = tname.substring(0, ind);
2833
                    String post = tname.substring(ind + 1, tname.length());
2834
                    int lpost = Math.min(24, post.length());
2835
                    int lpre = Math.min(3, pre.length());
2836
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
2837
            }
2838

    
2839
    }
2840

    
2841
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2842
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
2843
            " ON " + dbLayerDef.getTableName() + " (\"" +
2844
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
2845
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2846

    
2847
        return resp;
2848
    }
2849

    
2850
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2851

    
2852
            String tname = dbLayerDef.getTableName();
2853
            int ind = tname.lastIndexOf(".");
2854
            if (ind != -1) {
2855
                    String schema = tname.substring(0, ind);
2856
                    tname = tname.substring(ind + 1, tname.length());
2857
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2858
            " WHERE TABLE_NAME = '" + tname + "' AND OWNER = '" + schema + "'";
2859

    
2860
            } else{
2861
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2862
            " WHERE TABLE_NAME = '" + tname + "'";
2863
            }
2864
    }
2865

    
2866
    /**
2867
     * UTility method to get the SQL sentence needed to update the geographic metadata table
2868
     * with a new bounding box and SRS
2869
     *
2870
     * @param tName table name
2871
     * @param ora_srid new SRS
2872
     * @param bbox new bounding box
2873
     * @param dim geometries dimension
2874
     * @param withsrid False if the SRS is set to NULL. True otherwise.
2875
     * @return the SQL sentence to perform the update
2876
     */
2877
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
2878
        Rectangle2D bbox, int dim, boolean withsrid) {
2879
        String[] dim_name = new String[dim];
2880
        double tolerance = 0.5;
2881

    
2882
        if (ora_srid.compareTo(GEODETIC_SRID) == 0) {
2883
            dim_name[0] = "LONGITUDE";
2884
            dim_name[1] = "LATITUDE";
2885
        }
2886
        else {
2887
            dim_name[0] = "X";
2888
            dim_name[1] = "Y";
2889

    
2890
            if (dim > 2) {
2891
                dim_name[2] = "Z";
2892

    
2893
                if (dim > 3) {
2894
                    dim_name[3] = "T";
2895
                }
2896
            }
2897
        }
2898

    
2899
        String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " " +
2900
            " ( OWNER, TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
2901
            + "'" + schema + "', "
2902
            + "'" + tName + "', "
2903
            + "'" + DEFAULT_GEO_FIELD + "', " +
2904
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2905
            bbox.getMinX() + ", " + bbox.getMaxX() + ", " + tolerance + " ), " +
2906
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + bbox.getMinY() + ", " +
2907
            bbox.getMaxY() + ", " + tolerance + " ))";
2908

    
2909
        if (dim > 2) {
2910
            resp = resp.substring(0, resp.length() - 1) + ",";
2911
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
2912
                "', 0.0, 100.0, " + tolerance + " ))";
2913

    
2914
            if (dim > 3) {
2915
                resp = resp.substring(0, resp.length() - 1) + ",";
2916
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
2917
                    "', 0.0, 100.0, " + tolerance + " ))";
2918
            }
2919
        }
2920

    
2921
        if (withsrid) {
2922
            resp = resp + ", " + ora_srid + " )";
2923
        }
2924
        else {
2925
            resp = resp + ", NULL )";
2926
        }
2927

    
2928
        return resp;
2929
    }
2930

    
2931
    /**
2932
     * Gets the SQL sentence to perform an insertion.
2933
     *
2934
     * @param feat feature to be added
2935
     * @param dbLayerDef layer definition
2936
     * @param rowInd row index
2937
     * @param _geoColName geometry field name
2938
     * @return the SQL sentence to perform the insertion
2939
     */
2940
    public static String getRowInsertSql(IFeature feat,
2941
        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2942
        String name = "";
2943
        int ftype = -1;
2944
        String aux_orig = "";
2945
        String aux_limited = "";
2946
        String aux_quotes_ok = "";
2947

    
2948
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2949

    
2950
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
2951

    
2952
        for (int i = 0; i < fieldsDescr.length; i++) {
2953
            name = fieldsDescr[i].getFieldName();
2954
            ftype = fieldsDescr[i].getFieldType();
2955

    
2956
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2957
            if (!isOracleAllowedFieldname(name)) continue;
2958
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2959
            // ------------------------------------------------------
2960
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2961
            }
2962
            else {
2963
                name = getValidOracleID(name, i);
2964
                resp = resp + "\"" + name + "\"" + " , ";
2965
            }
2966
        }
2967

    
2968
        resp = resp + _geoColName + " ) VALUES ( ";
2969

    
2970
        for (int i = 0; i < fieldsDescr.length; i++) {
2971
            name = fieldsDescr[i].getFieldName();
2972
            ftype = fieldsDescr[i].getFieldType();
2973

    
2974
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2975
            if (!isOracleAllowedFieldname(name)) continue;
2976
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2977
            // ------------------------------------------------------
2978
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2979

    
2980
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2981
            }
2982
            else {
2983
                if (name.compareToIgnoreCase(
2984
                            OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2985
                    resp = resp + rowInd + " , ";
2986
                }
2987
                else {
2988
                    Value attValue = feat.getAttribute(i);
2989

    
2990
                    if (attValue.toString() == null) {
2991
                        resp = resp + "NULL , ";
2992
                    }
2993
                    else {
2994
                        if (sur.length() > 0) {
2995
                            aux_orig = attValue.toString();
2996
                            aux_limited = cropStringValue(aux_orig, i,
2997
                                    fieldsDescr);
2998
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2999

    
3000
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
3001
                        }
3002
                        else {
3003
                            String _aux = attValue.toString();
3004

    
3005
                            if (_aux.length() == 0) {
3006
                                _aux = "NULL";
3007
                            }
3008

    
3009
                            resp = resp + _aux + " , ";
3010
                        }
3011
                    }
3012
                }
3013
            }
3014
        }
3015

    
3016
        resp = resp + " ? )";
3017
        /*
3018
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
3019
                        + "2002, NULL, NULL,"
3020
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
3021
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
3022
                        + "), ? )";
3023

3024
        resp = resp + " " + test + " )";
3025
        */
3026
        return resp;
3027
    }
3028

    
3029
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
3030

    
3031
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
3032
                    return true;
3033
            }
3034

    
3035
            if ((ftype == Types.BINARY)
3036
                || (ftype == Types.ARRAY)
3037
                || (ftype == Types.BLOB)
3038
                || (ftype == Types.CLOB)
3039
                || (ftype == Types.STRUCT)
3040
            ) {
3041
                    return false;
3042
            }
3043
                return true;
3044
        }
3045

    
3046
        /**
3047
     * Gets the SQL sentence to perform an update.
3048
     *
3049
     * @param feat feature to be updated
3050
     * @param dbLayerDef layer definition
3051
     * @param rowInd row index
3052
     * @param geoFieldName geometry field name
3053
     * @return the SQL sentence to perform the update
3054
     */
3055
    public static String getRowUpdateSql(IFeature feat,
3056
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
3057
        String name = "";
3058
        String aux_orig = "";
3059
        String aux_limited = "";
3060
        String aux_quotes_ok = "";
3061

    
3062
        Value[] atts = feat.getAttributes();
3063
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
3064

    
3065
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
3066

    
3067
        for (int i = 0; i < _fieldsDescr.length; i++) {
3068
            name = _fieldsDescr[i].getFieldName();
3069

    
3070
            // -------------- FORBIDDEN FIELD NAMES -----------------
3071
            if (!isOracleAllowedFieldname(name)) {
3072
                logger.info("Field: " + name + " will not be updated.");
3073
                continue;
3074
            }
3075

    
3076
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
3077
                        geoFieldName)) {
3078
                logger.info("Field: " + name + " will not be updated (it's a struct).");
3079
                continue;
3080
            }
3081

    
3082
            // ------------------------------------------------------
3083
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
3084
                // resp = resp + "\"" + name + "\"" + " = ?, ";
3085
            }
3086
            else {
3087
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
3088
                aux_orig = atts[i].toString();
3089
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
3090
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
3091
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
3092
                    sur + ", ";
3093
            }
3094
        }
3095

    
3096
        resp = resp + "\"" + geoFieldName + "\" = ?";
3097
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
3098

    
3099
        return resp;
3100
    }
3101

    
3102
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
3103
        String geoname) {
3104
        if (ftype == Types.STRUCT) {
3105
            if (fldname.compareToIgnoreCase(geoname) != 0) {
3106
                return true;
3107
            }
3108
        }
3109

    
3110
        return false;
3111
    }
3112

    
3113
    /**
3114
     * Gets the SQL sentence to perform a deletion.
3115
     *
3116
     * @param dbLayerDef layer definition
3117
     * @param id ROWID of the record to be deleted
3118
     * @return the SQL sentence to perform the deletion
3119
     */
3120
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
3121
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
3122
        resp = resp + " WHERE ROWID ='" + id + "'";
3123

    
3124
        return resp;
3125
    }
3126

    
3127
    private static String cropStringValue(String orig_val, int i,
3128
        FieldDescription[] _flds) {
3129
            
3130
        if (orig_val == null) {
3131
            return "NULL";
3132
        }
3133
        
3134
        if (NumberUtilities.isNumeric(_flds[i].getFieldType())
3135
                    && (orig_val.length() == 0)) {
3136
                    return "NULL";
3137
        }
3138

    
3139
        int tpe = _flds[i].getFieldType();
3140
        int max_size = maxSizeForFieldType(tpe);
3141

    
3142
        if (max_size == -1) {
3143
            return orig_val;
3144
        }
3145

    
3146
        int or_size = orig_val.length();
3147

    
3148
        if (or_size <= max_size) {
3149
            return orig_val;
3150
        }
3151

    
3152
        return orig_val.substring(0, max_size);
3153
    }
3154

    
3155
    private static String avoidQuoteProblem(String str) {
3156
        return str.replaceAll("'", "''");
3157
    }
3158

    
3159
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3160
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3161
            return "";
3162
        }
3163

    
3164
        return "'";
3165
    }
3166

    
3167
    /**
3168
     * Utility function to translate a SRS code from EPSG to Oracle.
3169
     * Uses a datasource based on a DBF file.
3170
     *
3171
     * @param epsg the EPSG code
3172
     * @return the Oracle code
3173
     */
3174
    public static String epsgSridToOracleSrid(String epsg) throws Exception {
3175
        String resp = "8307";
3176

    
3177
        // --------------------------------------------
3178
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3179
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3180
        DataSource ds = null;
3181

    
3182
        try {
3183
            ds = LayerFactory.getDataSourceFactory()
3184
                             .executeSQL(sql,
3185
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3186

    
3187
            if (ds.getRowCount() == 0) {
3188
                logger.error("EPSG code not found in table: " + epsg);
3189
                throw new Exception("Unknown EPSG: " + epsg);
3190
            }
3191

    
3192
            if (ds.getRowCount() > 1) {
3193
                logger.error("===============");
3194
                logger.error(
3195
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
3196
                    epsg);
3197

    
3198
                for (int i = 0; i < ds.getRowCount(); i++) {
3199
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3200

    
3201
                    if (i == 0) {
3202
                        resp = "" + aux;
3203
                    }
3204

    
3205
                    logger.error("" + aux);
3206
                }
3207

    
3208
                logger.error("===============");
3209

    
3210
                return resp;
3211
            }
3212

    
3213
            resp = "" +
3214
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3215
        }
3216
        catch (Exception pe) {
3217
            logger.error("Error with SQL statement. " + pe.getMessage());
3218
        }
3219

    
3220
        return resp;
3221
    }
3222

    
3223
    /**
3224
     * Utility function to translate a SRS code from Oracle to EPSG.
3225
     * Uses a datasource based on a DBF file.
3226
     *
3227
     * @param ora the Oracle code
3228
     * @return the EPSG code
3229
     */
3230
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3231
        String resp = "4326";
3232

    
3233
        // --------------------------------------------
3234
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3235
            " where ORACLE = " + ora + ";";
3236
        DataSource ds = null;
3237

    
3238
        try {
3239
            ds = LayerFactory.getDataSourceFactory()
3240
                             .executeSQL(sql,
3241
                    DataSourceFactory.AUTOMATIC_OPENING);
3242

    
3243
            if (ds.getRowCount() == 0) {
3244
                logger.error("Oracle Spatial code not found in table: " + ora);
3245
                throw new Exception("Unknown Oracle code: " + ora);
3246
            }
3247

    
3248
            if (ds.getRowCount() > 1) {
3249
                logger.error("===============");
3250
                logger.error(
3251
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3252
                    ora);
3253

    
3254
                for (int i = 0; i < ds.getRowCount(); i++) {
3255
                    String aux = "" +
3256
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3257

    
3258
                    if (i == 0) {
3259
                        resp = aux;
3260
                    }
3261

    
3262
                    logger.error("" + aux);
3263
                }
3264

    
3265
                logger.error("===============");
3266

    
3267
                return resp;
3268
            }
3269

    
3270
            resp = "" +
3271
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3272
        }
3273
        catch (Exception pe) {
3274
            logger.error("Error with SQL statement. " + pe.getMessage());
3275
        }
3276

    
3277
        return resp;
3278
    }
3279

    
3280
    /**
3281
     * This methos creates the datasource used to translate the SRS codes:
3282
     * EPSG <--> Oracle.
3283
     *
3284
     * It's called from several places, so checks that the datasource does not exist.
3285
     */
3286

    
3287

    
3288
    /**
3289
     * Utility method to get a valid Oracle identifier (in terms of length)
3290
     *
3291
     * @param str Proposed string
3292
     * @param ind field index of the given field name (used by the method to
3293
     * improve the renaming)
3294
     * @return an acceptable oracle identifier.
3295
     */
3296
    public static String getValidOracleID(String str, int ind) {
3297
        if (str.length() <= MAX_ID_LENGTH) {
3298
            return str;
3299
        }
3300

    
3301
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3302
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3303
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3304
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3305
        resp = resp + "_" + (ind % 1000);
3306

    
3307
        return resp;
3308
    }
3309

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

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

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

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

    
3328
                return resp;
3329
            }
3330

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

    
3334
                return ensureSensibleShell(cc);
3335
            }
3336

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

    
3342
            return cc;
3343
        }
3344
    }
3345

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

    
3353
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3354
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3355
                resp.add(newcoo);
3356

    
3357
                newcoo = new Coordinate((Coordinate) cc.get(0));
3358
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3359
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3360
                resp.add(newcoo);
3361

    
3362
                resp.add(cc.get(0));
3363

    
3364
                return resp;
3365
            }
3366

    
3367
            if (cc.size() == 3) {
3368
                cc.remove(1);
3369

    
3370
                return ensureSensibleHole(cc);
3371
            }
3372

    
3373
            return cc;
3374
        }
3375
        else {
3376
            cc.add(cc.get(0));
3377

    
3378
            return cc;
3379
        }
3380
    }
3381

    
3382
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
3383
        if (cc.size() == 2) {
3384
            if (sameCoordinate((Coordinate) cc.get(0),
3385
                        (Coordinate) cc.get(cc.size() - 1))) {
3386
                ArrayList resp = new ArrayList();
3387
                resp.add(cc.get(0));
3388

    
3389
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3390
                newc.x = newc.x + IRRELEVANT_DISTANCE;
3391
                resp.add(newc);
3392

    
3393
                return resp;
3394
            }
3395
        }
3396

    
3397
        return cc;
3398
    }
3399

    
3400
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3401
        if (c1.x != c2.x) {
3402
            return false;
3403
        }
3404

    
3405
        if (c1.y != c2.y) {
3406
            return false;
3407
        }
3408

    
3409
        return true;
3410
    }
3411

    
3412
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3413
        if (cc.size() == 2) {
3414
            return null;
3415
        }
3416

    
3417
        if (cc.size() == 3) {
3418
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3419
                return null;
3420
            }
3421

    
3422
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3423
                return null;
3424
            }
3425

    
3426
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3427
                return null;
3428
            }
3429

    
3430
            cc.add(cc.get(0));
3431

    
3432
            return cc;
3433
        }
3434

    
3435
        if (!sameCoordinate((Coordinate) cc.get(0),
3436
                    (Coordinate) cc.get(cc.size() - 1))) {
3437
            cc.add(cc.get(0));
3438
        }
3439

    
3440
        return cc;
3441
    }
3442

    
3443
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3444
        Coordinate[] p = new Coordinate[4];
3445
        p[0] = c;
3446

    
3447
        Coordinate nc = new Coordinate(c);
3448
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3449

    
3450
        Coordinate nc2 = new Coordinate(nc);
3451
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3452
        p[1] = nc;
3453
        p[2] = nc2;
3454
        p[3] = new Coordinate(c);
3455

    
3456
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3457
        LinearRing ls = new LinearRing(cs, geomFactory);
3458
        Polygon po = new Polygon(ls, null, geomFactory);
3459
        Polygon[] pos = new Polygon[1];
3460
        pos[0] = po;
3461

    
3462
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3463

    
3464
        return mpo;
3465
    }
3466

    
3467
    public String getSourceProjection() {
3468
        // TODO Auto-generated method stub
3469
        if (tableHasSrid) {
3470
            return epsgSRID;
3471
        }
3472

    
3473
        return destProj;
3474
    }
3475

    
3476
    public String getDestProjection() {
3477
        return destProj;
3478
    }
3479

    
3480
    public void setDestProjection(String toEPSG) {
3481
        destProj = toEPSG;
3482
        try {
3483
                        destProjOracle = epsgSridToOracleSrid(destProj);
3484
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3485

    
3486
                } catch (Exception e) {
3487
                        logger.error("Unknown EPSG code: " + destProj);
3488
                        destProjOracle = oracleSRID;
3489
                        isDestGeogCS = false;
3490
                }
3491

    
3492
    }
3493

    
3494
    public String getDestProjectionOracleCode() {
3495
            return destProjOracle;
3496
    }
3497

    
3498
    public boolean getIsDestProjectionGeog() {
3499
            return isDestGeogCS;
3500
    }
3501

    
3502
    public String getTableProjectionOracleCode() {
3503
            return oracleSRID;
3504
    }
3505

    
3506
    public boolean canReproject(String toEPSGdestinyProjection) {
3507
        return false;
3508
    }
3509

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

    
3523
        if (str.compareToIgnoreCase("rownum") == 0) {
3524
            return false;
3525
        }
3526

    
3527
        return true;
3528
    }
3529

    
3530
    public Hashtable getHashRelate() {
3531
        return hashRelate;
3532
    }
3533

    
3534
    public void setHashRelate(Hashtable m) {
3535
        hashRelate = m;
3536
    }
3537

    
3538
    public void setNumReg(int n) {
3539
        numReg = n;
3540
    }
3541

    
3542
    private int[] getRandomSample(int maxn_one_based, int n) {
3543
        int[] resp = new int[n];
3544

    
3545
        if (maxn_one_based <= n) {
3546
            resp = new int[maxn_one_based];
3547

    
3548
            for (int i = 0; i < maxn_one_based; i++) {
3549
                resp[i] = i;
3550
            }
3551
        }
3552
        else {
3553
            Random rnd = new Random();
3554

    
3555
            for (int i = 0; i < n; i++) {
3556
                resp[i] = rnd.nextInt(maxn_one_based);
3557
            }
3558
        }
3559

    
3560
        return resp;
3561
    }
3562

    
3563
    private String getRowIdRestrictionCondition(int nrecords) {
3564
        int[] zero_based_rows = getRandomSample(nrecords,
3565
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3566
        String resp = "(";
3567
        Object aux = "";
3568
        ROWID riaux = null;
3569

    
3570
        for (int i = 0; i < zero_based_rows.length; i++) {
3571
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3572
            riaux = (ROWID) aux;
3573
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3574
        }
3575

    
3576
        resp = resp.substring(0, resp.length() - 4);
3577
        resp = resp + ")";
3578

    
3579
        return resp;
3580
    }
3581

    
3582
    private Rectangle2D getBoundingFromSample(int n_max) {
3583
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3584
            " WHERE " + getRowIdRestrictionCondition(n_max);
3585
        STRUCT auxstr = null;
3586
        IGeometry theGeom = null;
3587
        Rectangle2D resp = null;
3588

    
3589
        try {
3590
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3591
            ResultSet rs = st.executeQuery(_qry);
3592

    
3593
            if (rs.next()) {
3594
                auxstr = (STRUCT) rs.getObject(1);
3595

    
3596
                if (auxstr != null) {
3597
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3598

    
3599
                    if (resp == null) {
3600
                        resp = theGeom.getBounds2D();
3601
                    }
3602
                    else {
3603
                        resp.add(theGeom.getBounds2D());
3604
                    }
3605
                }
3606

    
3607
                while (rs.next()) {
3608
                    auxstr = (STRUCT) rs.getObject(1);
3609

    
3610
                    if (auxstr != null) {
3611
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3612

    
3613
                        if (resp == null) {
3614
                            resp = theGeom.getBounds2D();
3615
                        }
3616
                        else {
3617
                            resp.add(theGeom.getBounds2D());
3618
                        }
3619
                    }
3620
                }
3621

    
3622
                rs.close();
3623
                st.close();
3624
            }
3625
            else {
3626
                throw new SQLException("Empty resultset from this query: " +
3627
                    _qry);
3628
            }
3629
        }
3630
        catch (SQLException se) {
3631
            System.err.println("Error while getting sample full extent: " +
3632
                se.getMessage());
3633
        }
3634

    
3635
        if (resp == null) {
3636
            logger.warn(
3637
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3638

    
3639
            return new Rectangle2D.Double(-180, -90, 360, 180);
3640
        }
3641

    
3642
        return resp;
3643
    }
3644

    
3645
    /**
3646
     * Does what it says, puts the LinearRing in counter clock wise
3647
     * order.
3648
     * @param ls The ring to set.
3649
     * @param gf a GeometryFactory object
3650
     * @return A new ring in CCW order.
3651
     *
3652
     */
3653
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3654
        Coordinate[] cc = ls.getCoordinates();
3655

    
3656
        if (CGAlgorithms.isCCW(cc)) {
3657
            return gf.createLinearRing(cc);
3658
        }
3659
        else {
3660
            if (ls instanceof LinearRing) {
3661
                return reverseRing((LinearRing) ls, gf);
3662
            }
3663
            else {
3664
                return reverseLineString(ls, gf);
3665
            }
3666
        }
3667
    }
3668

    
3669
    /**
3670
     * Does what it says, reverses the order of the Coordinates in the ring.
3671
     * @param lr The ring to reverse.
3672
     * @return A new ring with the reversed Coordinates.
3673
     *
3674
     */
3675
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3676
        int numPoints = lr.getNumPoints() - 1;
3677
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3678

    
3679
        for (int t = numPoints; t >= 0; t--) {
3680
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3681
        }
3682

    
3683
        return gf.createLinearRing(newCoords);
3684
    }
3685

    
3686
    /**
3687
     * Does what it says, reverses the order of the Coordinates in the linestring.
3688
     * @param ls The ls to reverse.
3689
     * @param gf a GeometryFactory object
3690
     * @return A new ls with the reversed Coordinates.
3691
     *
3692
     */
3693
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3694
        int numPoints = ls.getNumPoints() - 1;
3695
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3696

    
3697
        for (int t = numPoints; t >= 0; t--) {
3698
            newCoords[t] = ls.getCoordinateN(numPoints - t);
3699
        }
3700

    
3701
        return gf.createLinearRing(newCoords);
3702
    }
3703

    
3704
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3705
        if (ge instanceof MultiPolygon) {
3706
            MultiPolygon mp = (MultiPolygon) ge;
3707
            int size = ge.getNumGeometries();
3708
            Polygon[] pols = new Polygon[size];
3709

    
3710
            for (int i = 0; i < size; i++)
3711
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3712
                        gf);
3713

    
3714
            return new MultiPolygon(pols, gf);
3715
        }
3716
        else {
3717
            if (ge instanceof Polygon) {
3718
                Polygon p = (Polygon) ge;
3719
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3720
                int nholes = p.getNumInteriorRing();
3721

    
3722
                if (nholes > 0) {
3723
                    LinearRing[] holes = new LinearRing[nholes];
3724

    
3725
                    for (int i = 0; i < nholes; i++) {
3726
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3727
                    }
3728

    
3729
                    return gf.createPolygon(exterior, holes);
3730
                }
3731
                else {
3732
                    return gf.createPolygon(exterior, null);
3733
                }
3734
            }
3735
            else {
3736
                return ge;
3737
            }
3738
        }
3739
    }
3740

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

    
3759
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3760
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3761

    
3762
            // logger.error("Collections no soportadas por ahora.");
3763
            // return null;
3764
        }
3765
        else {
3766
            Shape shp = ig.getInternalShape();
3767

    
3768
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3769
                agu_bien, false, _isGeoCS);
3770
        }
3771
    }
3772

    
3773
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3774
        boolean agu_bien, boolean isView) {
3775

    
3776
            if (shp == null) return null;
3777
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3778
            agu_bien, isView, isGeogCS);
3779
    }
3780

    
3781
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3782
        IConnection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3783
        boolean isView, boolean _isGeoCS) {
3784
        int _srid = -1;
3785

    
3786
        if (o_srid.length() > 0) {
3787
            _srid = Integer.parseInt(o_srid);
3788
        }
3789

    
3790
        if (shp == null) {
3791
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3792

    
3793
            return null;
3794
        }
3795

    
3796
        if (shp instanceof Rectangle2D) {
3797
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3798
                _isGeoCS, o_srid, _conn);
3799
        }
3800

    
3801
        try {
3802
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3803
                    _srid, agu_bien, hasSrid);
3804

    
3805
            return the_struct;
3806
        }
3807
        catch (SQLException ex) {
3808
            logger.error("While creating STRUCT: " + ex.getMessage());
3809

    
3810
            return null;
3811
        }
3812
    }
3813

    
3814
    // -------------------------- not ready yet ----------------
3815
    public int getRowIndexByFID(IFeature _fid) {
3816
        if (isNotAvailableYet) {
3817
            return -1;
3818
        }
3819
        else {
3820
            return super.getRowIndexByFID(_fid);
3821
        }
3822
    }
3823

    
3824
    public int getShapeCount() throws IOException {
3825
        if (isNotAvailableYet) {
3826
            return 0;
3827
        }
3828
        else {
3829
            return numReg;
3830
        }
3831
    }
3832

    
3833
    public void setNotAvailableYet(boolean nav) {
3834
        isNotAvailableYet = nav;
3835
    }
3836

    
3837
    // -------------------------------------------------------
3838
    // -------------------------------------------------------
3839
    public String[] getTableNames(IConnection conn, String catalog)
3840
        throws DBException {
3841
        try{
3842
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
3843
        String[] types = { "TABLE", "VIEW" };
3844
        // String[] types = { "VIEW" };
3845

    
3846
        ResultSet rs = null;
3847
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3848
                    ORACLE_GEOMETADATA_VIEW, types), ((ConnectionJDBC)conn).getConnection());
3849
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3850
//                          ORACLE_GEOMETADATA_VIEW, types);
3851
        TreeMap ret = new TreeMap();
3852

    
3853
        while (rs.next()) {
3854
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
3855
            ret.put(nomCompleto, nomCompleto);
3856
        }
3857

    
3858
        return (String[]) ret.keySet().toArray(new String[0]);
3859
        }catch (SQLException e) {
3860
                        throw new DBException(e);
3861
                }
3862
    }
3863

    
3864
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3865
        throws SQLException {
3866
        String tablename = "";
3867

    
3868

    
3869

    
3870
        if (res.next()) {
3871
            tablename = res.getString("TABLE_NAME");
3872

    
3873
            // debug
3874
            writeMetaTableToLog(con, tablename);
3875

    
3876
            Statement __st = con.createStatement();
3877

    
3878
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3879
                "union (select VIEW_NAME from USER_VIEWS)) " +
3880
                "intersect (select TABLE_NAME from " + tablename + ")";
3881
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
3882
            ResultSet rs = __st.executeQuery(sql);
3883

    
3884
            return rs;
3885
        }
3886
        else {
3887
            logger.error("Error while getting geometry tables.");
3888

    
3889
            return null;
3890
        }
3891
    }
3892

    
3893
    private void writeMetaTableToLog(Connection con, String tname) {
3894

    
3895
            logger.debug("======================================================");
3896
            logger.debug("=     " + ORACLE_GEOMETADATA_VIEW + "     =====================");
3897
            logger.debug("======================================================");
3898

    
3899
            try {
3900
            Statement _stmt = con.createStatement();
3901
            String sql = "SELECT * FROM " + tname;
3902
            ResultSet res = _stmt.executeQuery(sql);
3903
            while (res.next()) {
3904
                    logger.debug("======================================================");
3905
                    logger.debug("OWNER: " + res.getString("OWNER"));
3906
                    logger.debug("TABLE_NAME: " + res.getString("TABLE_NAME"));
3907
                    logger.debug("COLUMN_NAME: " + res.getString("COLUMN_NAME"));
3908
                    logger.debug("SRID: " + res.getString("SRID"));
3909

    
3910
                    ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3911
                    String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3912
                    logger.debug("DIMINFO: " + dinfo);
3913
                    logger.debug("======================================================");
3914

    
3915
            }
3916
            } catch (Throwable th) {
3917

    
3918
            }
3919

    
3920

    
3921

    
3922

    
3923

    
3924
                // TODO Auto-generated method stub
3925

    
3926
        }
3927

    
3928
        /**
3929
     * Gets the field names that can act as row id (always ROWID)
3930
     */
3931
    public String[] getIdFieldsCandidates(IConnection conn, String table_name)
3932
        throws DBException {
3933
            try{
3934
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
3935
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3936
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3937
            _rs.close();
3938
            _st.close();
3939

    
3940
            String[] resp = { "ROWID" };
3941
        return resp;
3942
            }catch (SQLException e) {
3943
                        throw new DBException(e);
3944
                }
3945
    }
3946

    
3947
    /**
3948
     * Gets the field names that can act as geometry fields
3949
     * (queries the user's geographic metadata).
3950
     */
3951
    public String[] getGeometryFieldsCandidates(IConnection conn,
3952
        String table_name) throws DBException {
3953
            try{
3954
        Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3955
        String[] tokens = table_name.split("\\u002E", 2);
3956
        String qry;
3957
        if (tokens.length > 1)
3958
        {
3959
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3960
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
3961
            tokens[1] + "'";
3962
        }
3963
        else
3964
        {
3965
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3966
            " where TABLE_NAME = " + "'" + table_name + "'";
3967

    
3968
        }
3969
        ResultSet _rs = _st.executeQuery(qry);
3970

    
3971
        ArrayList aux = new ArrayList();
3972

    
3973
        while (_rs.next()) {
3974
            String _geo = _rs.getString("COLUMN_NAME");
3975
            aux.add(_geo);
3976
        }
3977

    
3978
        _rs.close();
3979
        _st.close();
3980

    
3981
        String[] resp = (String[]) aux.toArray(new String[0]);
3982

    
3983
        return checkIndexes(conn, resp, table_name);
3984
            }catch (SQLException e) {
3985
                        throw new DBException(e);
3986
                }
3987
    }
3988

    
3989
    private String[] checkIndexes(IConnection c, String[] all, String long_table_name) throws DBException {
3990

    
3991
            ArrayList good_ones = new ArrayList();
3992
            try{
3993
            String t = long_table_name;
3994
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
3995

    
3996
            for (int i=0; i<all.length; i++) {
3997

    
3998
                String qry = "SELECT SRID, DIMINFO FROM " + ORACLE_GEOMETADATA_VIEW +
3999
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
4000
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
4001

    
4002
                Statement _st = ((ConnectionJDBC)c).getConnection().createStatement();
4003
                ResultSet _rs = _st.executeQuery(qry);
4004
                if (_rs.next()) {
4005
                        String _srid = toString((BigDecimal) _rs.getObject(1));
4006
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
4007
                        int len = diminfo.getOracleArray().length;
4008
                        if (allowsGeoQueries(((ConnectionJDBC)c).getConnection(), long_table_name, all[i], _srid, len)) {
4009
                                good_ones.add(all[i]);
4010
                        }
4011
                }
4012
                _rs.close();
4013
                _st.close();
4014
            }
4015

    
4016
            if (good_ones.size() == 0) {
4017
                    throw new SQLException("no_indexes_on_declared_geo_fields");
4018
            }
4019
            }catch (SQLException e) {
4020
                        throw new DBException(e);
4021
                }
4022
            return (String[]) good_ones.toArray(new String[0]);
4023
    }
4024

    
4025
    private String toString(BigDecimal number) {
4026

    
4027
            if (number == null) return "NULL";
4028
            return "" + number.intValue();
4029
        }
4030

    
4031
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
4032
            String p = getPointConstructor(dims, _srid);
4033
            String qry = "SELECT * FROM " + _t.toUpperCase() + " WHERE (ROWNUM = 1)";
4034
            qry = "SELECT * FROM (" + qry + ") WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'";
4035

    
4036
            try {
4037
                        Statement _st = c.createStatement();
4038
                        ResultSet _rs = _st.executeQuery(qry);
4039
                        _rs.close();
4040
                        _st.close();
4041
                } catch (Exception ex) {
4042
                        return false;
4043
                }
4044
                return true;
4045
        }
4046

    
4047
        private String getPointConstructor(int dims, String _srid) {
4048

    
4049
                String coord = "";
4050
                for (int i=0; i<dims; i++) coord = coord + "0, ";
4051
                coord = coord.substring(0, coord.length() - 2);
4052

    
4053
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
4054
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
4055
        }
4056

    
4057
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
4058

    
4059
            if (l == null) return false;
4060
            if (str == null) return false;
4061

    
4062
            String item = "";
4063
            for (int i=0; i<l.size(); i++) {
4064
                    if (l.get(i) instanceof String) {
4065
                            item = (String) l.get(i);
4066
                            if (item.compareToIgnoreCase(str) == 0) return true;
4067
                    }
4068
            }
4069
            return false;
4070
    }
4071

    
4072
        /**
4073
     * Utility method to check if a given table is empty.
4074
     */
4075
    public boolean isEmptyTable(Connection conn, String tableName) {
4076
        boolean res = true;
4077

    
4078
        try {
4079
            Statement st = conn.createStatement();
4080
            ResultSet rs = null;
4081
            rs = st.executeQuery("select * from " + tableName +
4082
                    " where rownum = 1");
4083
            res = !rs.next();
4084
            rs.close();
4085
            st.close();
4086
        }
4087
        catch (Exception ex) {
4088
            res = true;
4089
        }
4090

    
4091
        return res;
4092
    }
4093

    
4094
    /**
4095
     * Gets all the fields from a table name.
4096
     */
4097
    public String[] getAllFields(IConnection conn, String table_name)
4098
        throws DBException {
4099
            try{
4100
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
4101
        ResultSet rs = st.executeQuery("select * from " + table_name +
4102
                " where rownum = 1");
4103
        ResultSetMetaData rsmd = rs.getMetaData();
4104
        String[] ret = new String[rsmd.getColumnCount()];
4105

    
4106
        for (int i = 0; i < ret.length; i++) {
4107
            ret[i] = rsmd.getColumnName(i + 1);
4108
        }
4109

    
4110
        rs.close();
4111
        st.close();
4112

    
4113
        return ret;
4114
            }catch (SQLException e) {
4115
                        throw new DBException(e);
4116
                }
4117
    }
4118

    
4119
    /**
4120
     * Gets all field type names from a table.
4121
     */
4122
    public String[] getAllFieldTypeNames(IConnection conn, String table_name)
4123
        throws DBException {
4124
            try{
4125
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
4126
        ResultSet rs = st.executeQuery("select * from " + table_name +
4127
                " where rownum = 1");
4128
        ResultSetMetaData rsmd = rs.getMetaData();
4129
        String[] ret = new String[rsmd.getColumnCount()];
4130

    
4131
        for (int i = 0; i < ret.length; i++) {
4132
            ret[i] = rsmd.getColumnTypeName(i + 1);
4133
        }
4134

    
4135
        rs.close();
4136
        st.close();
4137

    
4138
        close();
4139

    
4140
        return ret;
4141
            }catch (SQLException e) {
4142
                        throw new DBException(e);
4143
                }
4144
    }
4145

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

    
4153
        if (_pw == null) {
4154
            _pw = "null";
4155
        }
4156

    
4157
        String fullstr = CONN_STR_BEGIN;
4158
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
4159
        fullstr = fullstr + "@" + host.toLowerCase();
4160
        fullstr = fullstr + ":" + port;
4161
        fullstr = fullstr + ":" + dbname.toLowerCase();
4162

    
4163
        return fullstr;
4164
    }
4165

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

    
4173
            writer = new OracleSpatialWriter(getRowCount());
4174
            writer.setDriver(this);
4175
            writer.setLyrShapeType(getShapeType());
4176
            writer.setGeoCS(isGeogCS());
4177
            writer.setGeoColName(geoColName);
4178
            writer.setSRID(oracleSRID);
4179

    
4180
            try {
4181
                writer.initialize(getLyrDef());
4182
            }
4183
            catch (EditionException e) {
4184
                logger.error("While initializing OS Writer: " + e.getMessage(),
4185
                    e);
4186
            }
4187

    
4188
            writer.setStoreWithSrid(tableHasSrid);
4189
        }
4190

    
4191
        return writer;
4192
    }
4193

    
4194
    /**
4195
     * Tells whether the SRS is geodetic or not
4196
     * @return whether the SRS is geodetic or not
4197
     */
4198
    public boolean isGeogCS() {
4199
        return isGeogCS;
4200
    }
4201

    
4202
    /**
4203
     * Adds a row id to the inner set od IDs.
4204
     * @param id
4205
     */
4206
    public void addRow(String id) {
4207
        Value aux = ValueFactory.createValue(id);
4208
        Integer intobj = new Integer(numReg);
4209
        hashRelate.put(aux, intobj);
4210
        rowToId.put(intobj, id);
4211

    
4212
        numReg++;
4213
    }
4214

    
4215
    /**
4216
     * Removes a row id to the inner set od IDs.
4217
     * @param id
4218
     */
4219
    public void deleteRow(String id) {
4220
        Value aux = ValueFactory.createValue(id);
4221
        Integer intobj = (Integer) hashRelate.get(aux);
4222
        hashRelate.remove(aux);
4223
        rowToId.remove(intobj);
4224

    
4225
        numReg--;
4226
    }
4227

    
4228
    private String getStandardSelectExpression() {
4229
        if (standardSelectExpressionFalse == null) {
4230
            standardSelectExpressionFalse = "";
4231

    
4232
            String[] flds = getLyrDef().getFieldNames();
4233
            int size = flds.length;
4234

    
4235
            for (int i = 0; i < size; i++) {
4236
                if (i > 0) {
4237
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4238
                        "c.\"" + flds[i] + "\", ";
4239
                }
4240
                else {
4241
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4242
                        flds[i] + ", ";
4243
                }
4244
            }
4245

    
4246
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4247
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4248
                    standardSelectExpressionFalse.length() - 2);
4249
        }
4250

    
4251
        return standardSelectExpressionFalse;
4252
    }
4253

    
4254
    /**
4255
     * Allows the method to decide what to do with the geometry field name
4256
     * (remove/add it from the user selected fields).
4257
     *
4258
     * @param flds
4259
     * @param geof
4260
     * @return the possibly modified field names
4261
     */
4262
    public String[] manageGeometryField(String[] flds, String geof) {
4263
        return addEndIfNotContained(flds, geof);
4264
    }
4265

    
4266
    /**
4267
     * Allows the method to decide what to do with the ID field name
4268
     * (remove/add it from the user selected fields).
4269
     *
4270
     * @param flds
4271
     * @param idf
4272
     * @return the possibly modified field names
4273
     */
4274
    public String[] manageIdField(String[] flds, String idf) {
4275
        return addStartIfNotContained(flds, idf);
4276
    }
4277

    
4278
    private String[] addEndIfNotContained(String[] arr, String item) {
4279
        if (contains(arr, item)) {
4280
            return arr;
4281
        }
4282
        else {
4283
            int size = arr.length;
4284
            String[] resp = new String[size + 1];
4285

    
4286
            for (int i = 0; i < size; i++) {
4287
                resp[i] = arr[i];
4288
            }
4289

    
4290
            resp[size] = item;
4291

    
4292
            return resp;
4293
        }
4294
    }
4295

    
4296
    private String[] addStartIfNotContained(String[] arr, String item) {
4297
        if (contains(arr, item)) {
4298
            return arr;
4299
        }
4300
        else {
4301
            int size = arr.length;
4302
            String[] resp = new String[size + 1];
4303

    
4304
            for (int i = 1; i <= size; i++) {
4305
                resp[i] = arr[i];
4306
            }
4307

    
4308
            resp[0] = item;
4309

    
4310
            return resp;
4311
        }
4312
    }
4313

    
4314
    private boolean contains(String[] arr, String item) {
4315
        for (int i = 0; i < arr.length; i++) {
4316
            if (arr[i].compareTo(item) == 0) {
4317
                return true;
4318
            }
4319
        }
4320

    
4321
        return false;
4322
    }
4323

    
4324
    /**
4325
     * This method is called when the user removes the layer from the view.
4326
     * If the IDs were being loaded, the driver will check this field and will
4327
     * let the thread 'die' quietly.
4328
     *
4329
     */
4330
    public void remove() {
4331
        cancelIDLoad = true;
4332
    }
4333

    
4334
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4335
            // if (!isgeodetic) return true;
4336
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true;
4337
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true;
4338
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true;
4339
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true;
4340
            return false;
4341
    }
4342

    
4343
    private Rectangle2D getFastEstimatedGeodeticExtent(
4344
                    String tname, String gfield, IConnection c, int sample_size, double enlargement) {
4345

    
4346
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4347
            Rectangle2D resp_aux = null;
4348
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4349
            ResultSet _rs = null;
4350

    
4351
            try {
4352
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
4353
                        _rs = _st.executeQuery();
4354
                        while (_rs.next()) {
4355
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4356
                                IGeometry ig = getGeometryUsing(aux, false);
4357

    
4358
                                if (ig == null) continue;
4359

    
4360
                                if (resp_aux == null) {
4361
                                        resp_aux = ig.getBounds2D();
4362
                                } else {
4363
                                        resp_aux.add(ig.getBounds2D());
4364
                                }
4365

    
4366
                        }
4367
                } catch (Exception ex) {
4368
                        logger.error("While getting random sample: " + ex.getMessage());
4369
                        return world;
4370
                }
4371

    
4372
                if (resp_aux == null) return world;
4373
                double w = resp_aux.getWidth();
4374
                double h = resp_aux.getHeight();
4375
                double x = resp_aux.getMinX();
4376
                double y = resp_aux.getMinY();
4377

    
4378
                // enlarge 10 times:
4379
                double newx = x - (0.5 * (enlargement - 1)) * w;
4380
                double newy = y - (0.5 * (enlargement - 1)) * w;
4381
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4382
                                enlargement * w,
4383
                                enlargement * h);
4384

    
4385

    
4386
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4387

    
4388
                logger.debug("FAST BB:");
4389
                logger.debug(" min x:" + resp_aux.getMinX());
4390
                logger.debug(" min y:" + resp_aux.getMinY());
4391
                logger.debug("     w:" + resp_aux.getWidth());
4392
                logger.debug("     h:" + resp_aux.getHeight());
4393
                return resp_aux;
4394
    }
4395

    
4396
    private Rectangle2D getEstimatedGeodeticExtent(
4397
                    String tname, String gfield, IConnection c, int sample_size, double enlargement) {
4398

    
4399
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4400

    
4401
            ArrayList ids = new ArrayList();
4402
            int _rnd_index = 0;
4403
            ROWID _id = null;
4404
            Random rnd = new Random(System.currentTimeMillis());
4405

    
4406
            for (int i=0; i<sample_size; i++) {
4407
                    _rnd_index = rnd.nextInt(numReg);
4408
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
4409
                    ids.add(_id.stringValue());
4410
            }
4411

    
4412
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
4413
            for (int i=0; i<ids.size(); i++) {
4414
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR ";
4415
            }
4416
            qry = qry.substring(0, qry.length() - 4) + ")";
4417

    
4418
            Rectangle2D resp_aux = null;
4419
            ResultSet _rs = null;
4420

    
4421
            try {
4422
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
4423
                        _rs = _st.executeQuery();
4424
                        while (_rs.next()) {
4425
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4426
                                IGeometry ig = getGeometryUsing(aux, false);
4427

    
4428
                                if (ig == null) continue;
4429

    
4430
                                if (resp_aux == null) {
4431
                                        resp_aux = ig.getBounds2D();
4432
                                } else {
4433
                                        resp_aux.add(ig.getBounds2D());
4434
                                }
4435

    
4436
                        }
4437
                } catch (Exception ex) {
4438
                        logger.error("While getting random sample: " + ex.getMessage());
4439
                        return world;
4440
                }
4441

    
4442
                if (resp_aux == null) return world;
4443
                double w = resp_aux.getWidth();
4444
                double h = resp_aux.getHeight();
4445
                double x = resp_aux.getMinX();
4446
                double y = resp_aux.getMinY();
4447

    
4448
                // enlarge 10 times:
4449
                double newx = x - (0.5 * (enlargement - 1)) * w;
4450
                double newy = y - (0.5 * (enlargement - 1)) * w;
4451
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4452
                                enlargement * w,
4453
                                enlargement * h);
4454

    
4455

    
4456
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4457
                return resp_aux;
4458
    }
4459

    
4460
    public void setUserName(String u) {
4461
            userName = u;
4462
    }
4463

    
4464
    public String getUserName() {
4465
            return userName;
4466
    }
4467

    
4468
    public static final int JGeometry_GTYPE_COLLECTION = 4;
4469
    public static final int JGeometry_GTYPE_CURVE = 2;
4470
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
4471
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
4472
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
4473
    public static final int JGeometry_GTYPE_POINT = 1;
4474
    public static final int JGeometry_GTYPE_POLYGON = 3;
4475

    
4476
    // ------------------------------
4477
    
4478
    public void setXMLEntity(XMLEntity xml) throws XMLException {
4479
            
4480
            super.setXMLEntity(xml);
4481
            workingAreaInTablesCS = workingArea;
4482
            
4483
            try {
4484
                    int[] ftypes = xml.getIntArrayProperty("fieldTypes");
4485
                    setLyrDefFieldTypes(ftypes);
4486
            } catch (Exception ex) {
4487
                    logger.warn("Apparently, an old GVP file has been opened," +
4488
                                    " field type values are not accurate after this point.");
4489
            }
4490
            
4491
    }
4492
    
4493
    public XMLEntity getXMLEntity() {
4494
                // ---------------------
4495

    
4496
                XMLEntity xml = new XMLEntity();
4497
                xml.putProperty("className", getClass().getName());
4498

    
4499
                xml.putProperty("catalog", getLyrDef().getCatalogName());
4500

    
4501
                int aux = userName.indexOf("@");
4502
                if (aux != -1)
4503
                        userName = userName.substring(0, aux);
4504
                xml.putProperty("username", userName);
4505

    
4506
                xml.putProperty("driverclass", ORACLE_JAR_FILE_NAME);
4507

    
4508
                xml.putProperty("tablename", getTableName());
4509
                xml.putProperty("fields", lyrDef.getFieldNames());
4510
                xml.putProperty("fieldTypes", getLyrDefFieldTypes());
4511
                xml.putProperty("FID", lyrDef.getFieldID());
4512
                xml.putProperty("THE_GEOM", lyrDef.getFieldGeometry());
4513
                xml.putProperty("whereclause", getWhereClause());
4514
                xml.putProperty("SRID", lyrDef.getSRID_EPSG());
4515

    
4516
                xml.putProperty("host", host);
4517
                xml.putProperty("port", port);
4518
                xml.putProperty("dbName", dbName);
4519
                xml.putProperty("connName", connName);
4520

    
4521
                if (workingAreaInTablesCS != null) {
4522
                        xml.putProperty("minXworkArea", workingAreaInTablesCS.getMinX());
4523
                        xml.putProperty("minYworkArea", workingAreaInTablesCS.getMinY());
4524
                        xml.putProperty("HworkArea", workingAreaInTablesCS.getHeight());
4525
                        xml.putProperty("WworkArea", workingAreaInTablesCS.getWidth());
4526
                }
4527

    
4528
                return xml;
4529
        }
4530
    
4531
    private int[] getLyrDefFieldTypes() {
4532
            FieldDescription[] fd = lyrDef.getFieldsDesc();
4533
            int sz = fd.length;
4534
            int[] resp = new int[sz];
4535
            for (int i=0; i<sz; i++) resp[i] = fd[i].getFieldType();
4536
                return resp;
4537
        }
4538
    
4539
    private void setLyrDefFieldTypes(int[] tt) {
4540
            FieldDescription[] fd = lyrDef.getFieldsDesc();
4541
            
4542
            int sz_fd = fd.length;
4543
            int sz_tt = tt.length;
4544
            int sz = sz_tt;
4545
            
4546
            if (sz_tt != sz_fd) {
4547
                    logger.error("Field count does not match. lyrDef has " + sz_fd + " fields," +
4548
                                    " but this method was called with " + sz_tt + " items (?)");
4549
                    sz = Math.min(sz_fd, sz_tt);
4550
            }
4551
            
4552
            for (int i=0; i<sz; i++) lyrDef.getFieldsDesc()[i].setFieldType(tt[i]);
4553
    }
4554

    
4555
        public String[] getTableFields(IConnection conex, String table) throws DBException {
4556
                try{
4557
                Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
4558
        // ResultSet rs = dbmd.getTables(catalog, null, dbLayerDefinition.getTable(), null);
4559
                ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
4560
                ResultSetMetaData rsmd = rs.getMetaData();
4561

    
4562
                String[] ret = new String[rsmd.getColumnCount()];
4563

    
4564
                for (int i = 0; i < ret.length; i++) {
4565
                        ret[i] = rsmd.getColumnName(i+1);
4566
                }
4567

    
4568
                return ret;
4569
                }catch (SQLException e) {
4570
                        throw new DBException(e);
4571
                }
4572
        }
4573

    
4574
    // Overwritten to keep old behavior: returns "schema.table_name" if
4575
    // schema is not current user
4576
        public String getTableName() {
4577
            return fullTableName; 
4578
        }
4579
        
4580
    private Timestamp flexibleTimeStamp(String s) {
4581
            
4582
            String aux = s.replace('-', ' ');
4583
            aux = aux.replace(':', ' ');
4584
            aux = aux.replace('.', ' ');
4585
            // sample: 2007 12 31 23 59 59 9999
4586
            String[] parts = aux.trim().split(" ");
4587
            
4588
            int year;
4589
            int month;
4590
            int day;
4591
            int hour;
4592
            int minute;
4593
            int second;
4594
            int a_nanos;
4595

    
4596
            if (parts.length == 7) {
4597

    
4598
                    try {
4599

    
4600
                            year = Integer.parseInt(parts[0]) - 1900;
4601
                            month = Integer.parseInt(parts[1]) - 1;
4602
                            day = Integer.parseInt(parts[2]);
4603
                            hour = Integer.parseInt(parts[3]);
4604
                            minute = Integer.parseInt(parts[4]);
4605
                            second = Integer.parseInt(parts[5]);
4606
                            a_nanos = Integer.parseInt(parts[6]);
4607
                            
4608
                    } catch (Exception ex) {
4609
                        logger.debug("Bad time stamp: " + ex.getMessage());
4610
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4611
                    }
4612

    
4613
            } else {
4614
                    
4615
                if (parts.length == 6) {
4616
                        
4617
                        try {
4618
                            year = Integer.parseInt(parts[0]) - 1900;
4619
                            month = Integer.parseInt(parts[1]) - 1;
4620
                            day = Integer.parseInt(parts[2]);
4621
                            hour = Integer.parseInt(parts[3]);
4622
                            minute = Integer.parseInt(parts[4]);
4623
                            second = Integer.parseInt(parts[5]);
4624
                            a_nanos = 0;
4625
                            
4626
                        } catch (Exception ex) {
4627
                                
4628
                            logger.debug("Bad time stamp: " + ex.getMessage());
4629
                            return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4630
                        }
4631

    
4632
                } else {
4633
                        
4634
                        logger.debug("Bad time stamp: " + s);
4635
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4636
                        
4637
                }
4638
            }
4639
            
4640
            return new Timestamp(year, month, day, hour, minute, second, a_nanos);
4641
    }        
4642
    
4643

    
4644
}