Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialDriver.java @ 16325

History | View | Annotate | Download (138 KB)

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

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

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

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

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

    
130

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

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

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

    
180
        public static final String ORACLE_JAR_FILE_NAME = "oracle.jdbc.driver.OracleDriver";
181

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

    
191
    private OracleSpatialWriter writer = null;
192

    
193
    // utility object to convert geometries.
194
//    private GeometryConverter geotools_conv;
195

    
196
    // switch variable
197
    private boolean use_geotools = false;
198
    private boolean tableHasSrid = true;
199

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

    
210
    private Rectangle2D workingAreaInViewsCS = null;
211
    private Rectangle2D workingAreaInTablesCS = null;
212
    private STRUCT workingAreaInTablesCSStruct = null;
213

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

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

    
224
    // ----------------------------------------------
225
    private boolean cancelIDLoad = false;
226

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

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

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

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

    
253

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

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

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

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

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

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

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

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

    
311
                setUpperCase(lyrDef);
312
        lyrDef.setConnection(conn);
313

    
314
        setLyrDef(lyrDef);
315

    
316
        geoColName = lyrDef.getFieldGeometry();
317
        
318
        String tn = lyrDef.getTableName();
319
        
320
        if (tn.indexOf(".") == -1) {
321
                
322
                if (lyrDef.getSchema() == null) {
323
                        fullTableName = _cwp.getUser().toUpperCase() + "." + tn;
324
                } else {
325
                        fullTableName = lyrDef.getSchema() + "." + tn;
326
                }
327
                
328
                
329
        } else {
330
                fullTableName = tn;
331
        }
332
        
333
        not_restricted_sql = "select " + getStandardSelectExpression() +
334
            " from " + getTableName() + " c ";
335

    
336
        // various metadata settings
337
        // getMetaDataInThisThread();
338
        cleanWhereClause();
339
        loadSdoMetadata();
340
        oneRowMetadata();
341

    
342
        setDestProjection(lyrDef.getSRID_EPSG());
343
        workingAreaInViewsCS = lyrDef.getWorkingArea();
344
        
345
        if ((workingAreaInViewsCS != null) && (epsgSRID != null)) {
346
            IProjection viewProj = CRSFactory.getCRS("EPSG:" + destProj);
347
            IProjection tableProj = CRSFactory.getCRS("EPSG:" + epsgSRID);
348
            ICoordTrans reprojecter = viewProj.getCT(tableProj);
349
                workingAreaInTablesCS = reprojecter.convert(workingAreaInViewsCS);
350
            workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
351
                    FShape.NULL, tableHasSrid, false, true);
352
        }
353

    
354
        cancelIDLoad = false;
355
        idLoader = new IdLoaderThread(this);
356
        idLoader.start();
357
    }
358

    
359
        private void setUpperCase(DBLayerDefinition def) {
360
                
361
                String aux = def.getCatalogName();
362
                if (aux != null) def.setCatalogName(aux.toUpperCase());
363

    
364
                aux = def.getSchema();
365
                if (aux != null) def.setSchema(aux.toUpperCase());
366
                
367
                aux = def.getFieldID();
368
                if (aux != null) def.setFieldID(aux.toUpperCase());
369
                
370
                aux = def.getFieldGeometry();
371
                if (aux != null) def.setFieldGeometry(aux.toUpperCase());
372
                
373
                String flds[] = def.getFieldNames();
374
                if (flds != null) {
375
                        for (int i=0; i<flds.length; i++) flds[i] = flds[i].toUpperCase();
376
                        def.setFieldNames(flds);
377
                }
378
        }
379

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

    
389
    private void getMetadata() {
390

    
391
            long id_load_start = System.currentTimeMillis();
392
        setIdRowTable();
393
        long id_load_end = System.currentTimeMillis();
394

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

    
405
        if (!hasRealiableExtent) {
406
                full_Extent = getEstimatedExtent(
407
                                getTableName(), geoColName, conn, 20, 1.5, isGeogCS);
408
        }
409

    
410
        if (cancelIDLoad) {
411
            return;
412
        }
413
    }
414

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

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

    
426
            ArrayList types = new ArrayList();
427
            int aux = 0;
428

    
429
            ARRAY info_aux;
430
            int[] info_aux_int;
431
            int size;
432

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

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

    
443
                types.add(new Integer(aux % 1000));
444
            }
445

    
446
            _rs.close();
447
            _st.close();
448

    
449
            boolean resp = hasSeveralGeometryTypes(types, false);
450

    
451
            return resp;
452
        }
453
        catch (Exception se) {
454
                logger.error("While getting SDO metadata: " + se.getMessage());
455
        }
456

    
457
        return false;
458
    }
459

    
460
    private boolean hasSeveralGeometryTypes(ArrayList tt, boolean are_dims) {
461
        if (tt.size() == 0) {
462
            return false;
463
        }
464

    
465
        HashMap m = new HashMap();
466

    
467
        for (int i = 0; i < tt.size(); i++) {
468
            Integer integ = (Integer) tt.get(i);
469
            int val = integ.intValue();
470

    
471
            if ((val == 4) && (!are_dims)) {
472
                return true;
473
            }
474

    
475
            m.put("" + (val % 4), "a type");
476
        }
477

    
478
        Iterator iter = m.keySet().iterator();
479
        iter.next();
480

    
481
        return iter.hasNext();
482
    }
483

    
484
    private String getOracleSridFromCurrentRecord(ResultSet _rs)
485
        throws SQLException {
486
        Object obj = _rs.getObject("SRID");
487

    
488
        if (obj == null) {
489
            logger.warn("No SRID found for this table.");
490
            tableHasSrid = false;
491

    
492
            return null;
493
        }
494

    
495
        return obj.toString();
496
    }
497

    
498
    private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
499
        throws SQLException {
500
        ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
501

    
502
        if (dim_info_array == null) {
503
            // no full extent found:
504
            return null;
505
        }
506
        else {
507
            Datum[] da = dim_info_array.getOracleArray();
508

    
509
            STRUCT sx = (STRUCT) da[0];
510
            STRUCT sy = (STRUCT) da[1];
511

    
512
            try {
513
                double minx = Double.parseDouble(sx.getAttributes()[1].toString());
514
                double maxx = Double.parseDouble(sx.getAttributes()[2].toString());
515
                double miny = Double.parseDouble(sy.getAttributes()[1].toString());
516
                double maxy = Double.parseDouble(sy.getAttributes()[2].toString());
517

    
518
                if (minx > maxx) {
519
                    double aux = minx;
520
                    minx = maxx;
521
                    maxx = aux;
522
                }
523

    
524
                if (miny > maxy) {
525
                    double aux = miny;
526
                    miny = maxy;
527
                    maxy = aux;
528
                }
529

    
530
                return getRectangle(minx, maxx, miny, maxy);
531

    
532
                // fullExtentJTS = shapeToGeometry(fullExtent);
533
            }
534
            catch (Exception ex) {
535
                    logger.error("While getting full extent from metadata table.");
536
                return null;
537
            }
538
        }
539
    }
540

    
541
    private void loadSdoMetadata() {
542
        try {
543
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
544
            String[] tokens = getTableName().split("\\u002E", 2);
545
            String qry;
546
            if (tokens.length > 1)
547
            {
548
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
549
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
550
                tokens[1] + "'";
551
            }
552
            else
553
            {
554
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
555
                " where TABLE_NAME = " + "'" + getTableName() + "'";
556

    
557
            }
558

    
559
            ResultSet _rs = _st.executeQuery(qry);
560

    
561
            if (_rs.next()) {
562
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
563

    
564
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
565

    
566
                try {
567
                                        epsgSRID = oracleSridToEpsgSrid(oracleSRID);
568
                                } catch (Exception e) {
569
                                        logger.error("Unknown oracle SRID: " + oracleSRID);
570
                                        tableHasSrid = false;
571
                                }
572
                full_Extent = getFullExtentFromCurrentRecord(_rs);
573

    
574
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS);
575

    
576
                if (!hasRealiableExtent) {
577
                        full_Extent = getFastEstimatedExtent(
578
                                            getTableName(), geoColName, conn, 20, 10, isGeogCS);
579
                }
580

    
581
                _rs.close();
582
                _st.close();
583
            }
584
            else {
585
                throw new SQLException("Empty resultset from this query: " +
586
                    qry);
587
            }
588
        }
589
        catch (SQLException se) {
590
                logger.error("While getting SDO metadata: " + se.getMessage());
591
        }
592
    }
593

    
594
    /**
595
     * Utility method to find out if a coordinate system is geodetic or not.
596
     *
597
     * @param oracleSRID2 the coordinate system's oracle code
598
     * @param thas whether the table has a coordinate system set.
599
     * if not, the method returns false.
600
     * @return whether the coordinate system is geodetic or not.
601
     */
602
    public static boolean getIsGCS(String oracleSRID2, boolean thas) {
603

    
604
        if (!thas) return false;
605
        if (oracleSRID2 == null) return false;
606
        
607
        int ora_cs = 0;
608

    
609
        try {
610
            ora_cs = Integer.parseInt(oracleSRID2);
611
        }
612
        catch (Exception ex) {
613
            return false;
614
        }
615

    
616
        if (((ora_cs >= 8000) && (ora_cs <= 8999)) || (ora_cs == 524288)) {
617
            return true;
618
        } else {
619
                return false;
620
        }
621
    }
622

    
623
    private Rectangle2D getRectangle(double minx, double maxx, double miny,
624
        double maxy) {
625
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
626
                maxy - miny);
627

    
628
        return resp;
629
    }
630

    
631
    private void oneRowMetadata() {
632
        try {
633
            String _sql = "select " + getStandardSelectExpression() + ", c." +
634
                geoColName + " from " + getTableName() + " c ";
635

    
636
            st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
637
                    ResultSet.CONCUR_READ_ONLY);
638

    
639
            ResultSet _rs = st.executeQuery(_sql + " where (rownum = 1)");
640

    
641
            if (_rs.next()) {
642
                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
643
                shapeType = getShapeTypeOfStruct(sample_geo);
644
            }
645
            else {
646
                shapeType = FShape.MULTI;
647
            }
648

    
649
            // -----------------------
650
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
651
            metaData = _rs.getMetaData();
652

    
653
            userName = ((ConnectionJDBC)conn).getConnection().getMetaData().getUserName();
654

    
655
            // geoColInd = _rs.findColumn(geoColName);
656
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
657

    
658
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
659
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
660

    
661
            int cnt = metaData.getColumnCount();
662
            fieldNames = new String[cnt];
663

    
664
            for (int i = 0; i < cnt; i++) {
665
                fieldNames[i] = metaData.getColumnName(i + 1);
666
            }
667

    
668
            getIdFieldNames();
669

    
670
            adjustLyrDef();
671

    
672
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan
673
        }
674
        catch (SQLException se) {
675
            logger.error("While getting metadata. " + se.getMessage());
676
        }
677
    }
678

    
679
    private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
680

    
681
        int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue();
682
        
683
        int type_part = code % 10;
684
        int dim_part = code / 1000;
685

    
686
        int z_added = 0;
687
        if ((dim_part == 3) || (dim_part == 4)) {
688
                z_added = 512;
689
        }
690

    
691
        switch (type_part) {
692
        case 1:
693
            return z_added + FShape.POINT;
694

    
695
        case 2:
696
            return z_added + FShape.LINE;
697

    
698
        case 3:
699
            return z_added + FShape.POLYGON;
700

    
701
        case 4:
702
            return z_added + FShape.MULTI;
703

    
704
        case 5:
705
            return z_added + FShape.MULTIPOINT;
706

    
707
        case 6:
708
            return z_added + FShape.LINE;
709

    
710
        case 7:
711
            return z_added + FShape.POLYGON;
712
        }
713

    
714
        logger.error("Unknown geometry type: " + code);
715

    
716
        return FShape.NULL;
717
    }
718

    
719
    private String getIdFieldNames() {
720
        try {
721
            idFieldNames = "";
722

    
723
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
724
                idFieldNames = idFieldNames +
725
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
726
            }
727
        }
728
        catch (SQLException se) {
729
        }
730

    
731
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
732

    
733
        return idFieldNames;
734
    }
735

    
736
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
737
        int[] _res = new int[1];
738
        _res[0] = 1;
739

    
740
        return _res;
741
    }
742

    
743
    public String getSqlTotal() {
744
        // TODO Auto-generated method stub
745
        return "";
746
    }
747

    
748
    public String getCompleteWhere() {
749
        // TODO Auto-generated method stub
750
        return "";
751
    }
752

    
753
    /**
754
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
755
     * and uses directly that sentence to query the table).
756
     */
757
    public IFeatureIterator getFeatureIterator(String sql)
758
        throws ReadDriverException {
759
        if (isNotAvailableYet) {
760
                return new AnEmptyFeatureIterator();
761
            // return null;
762
        }
763

    
764
        singleCachedFeatureRowNum = -1;
765

    
766
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
767

    
768
        ResultSet localrs = (ResultSet) rs_st[0];
769
        Statement _st = (Statement) rs_st[1];
770

    
771
        return new OracleSpatialFeatureIterator(this, localrs, _st,
772
            oneBasedGeoColInd, use_geotools);
773
    }
774

    
775
    /**
776
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
777
     */
778
    public String getConnectionStringBeginning() {
779
        // oracle
780
        return CONN_STR_BEGIN;
781
    }
782

    
783
    public void open() { // throws DriverException {
784
    }
785

    
786
    /**
787
     * Gets Oracle's default port: 1521
788
     */
789
    public int getDefaultPort() {
790
        // oracle port
791
        return 1521;
792
    }
793

    
794
    /**
795
     * Gets the feature iterator for a given rectangle (the view's bounding box)
796
     * and a SRS.
797
     */
798
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
799
        throws ReadDriverException {
800
        if (isNotAvailableYet) {
801
                return new AnEmptyFeatureIterator();
802
            // return null;
803
        }
804

    
805
        singleCachedFeatureRowNum = -1;
806

    
807
        STRUCT local_st = shapeToStruct(r, FShape.NULL, tableHasSrid, false, true);
808

    
809
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
810

    
811
        ResultSet localrs = (ResultSet) rs_st[0];
812
        Statement _st = (Statement) rs_st[1];
813

    
814
        return new OracleSpatialFeatureIterator(this, localrs, _st,
815
            oneBasedGeoColInd, use_geotools);
816
    }
817

    
818
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
819
        if (workingAreaInTablesCS == null) return r;
820
        return doIntersect(r, workingAreaInTablesCS);
821
    }
822

    
823
    /**
824
     * This method reverts to the one without the fields specification.
825
     * The fields have been selected from the start.
826
     */
827
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
828
        String[] alphaNumericFieldsNeeded) throws ReadDriverException {
829
            
830
        if (isNotAvailableYet) {
831
                return new AnEmptyFeatureIterator();
832
            // return null;
833
        }
834

    
835
        singleCachedFeatureRowNum = -1;
836

    
837
        return getFeatureIterator(r, strEPSG);
838
    }
839

    
840
    public String getGeometryField(String fieldName) {
841
        return fieldName;
842

    
843
        // return "ASBINARY(" + fieldName + ")";
844
    }
845

    
846
    public DriverAttributes getDriverAttributes() {
847
        return drvAtts;
848
    }
849

    
850
    /**
851
     * Gets the requested geometry. Always performs a new query in this case.
852
     * This should be a rare way to get the geometries. The standard way is by using
853
     * the iterators.
854
     */
855
    public IGeometry getShape(int _ind) throws ReadDriverException {
856
        if (isNotAvailableYet) {
857
            return nullGeom;
858
        }
859

    
860
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
861

    
862
        String _sql = "select " + geoColName + " from " + getTableName() +
863
            " where rowid = ?";
864

    
865
        try {
866
            java.sql.PreparedStatement ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(_sql);
867
            ps.setObject(1, r_id);
868

    
869
            // Statement stmnt = conn.createStatement();
870
            ps.execute();
871

    
872
            ResultSet _res = ps.getResultSet();
873

    
874
            if (_res.next()) {
875
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
876
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
877
                _res.close();
878
                ps.close();
879

    
880
                return theGeom;
881
            }
882
            else {
883
                logger.error("Unable to get shape: " + _ind +
884
                    " (probably due to edition)");
885
                
886

    
887
                return nullGeom;
888
            }
889
        }
890
        catch (SQLException se) {
891
            throw new ReadDriverException(getName(), se);
892
        }
893
    }
894

    
895
    public boolean isWritable() {
896
        return true;
897
    }
898

    
899
    public String getName() {
900
        return NAME;
901
    }
902

    
903
    public int[] getPrimaryKeys() throws ReadDriverException {
904
        return pkOneBasedIndexes;
905
    }
906

    
907
    /*
908
    public void write(DataWare dataWare) throws ReadDriverException {
909
    }
910
    */
911

    
912
    private void setIdRowTable() {
913
        hashRelate = new Hashtable();
914

    
915
        java.sql.PreparedStatement ps = null;
916

    
917
        try {
918
            String _sql = getIdAndElemInfoFullResulltSetQuery();
919

    
920
            logger.debug("SQL para leer ids: " + _sql);
921
            Statement st = null;
922

    
923

    
924
            st = ((ConnectionJDBC)conn).getConnection().createStatement(
925
                            ResultSet.TYPE_FORWARD_ONLY,
926
                            ResultSet.CONCUR_READ_ONLY);
927
            
928
            
929

    
930
            // st = ((ConnectionJDBC)conn).getConnection().createStatement();
931

    
932
             st.setFetchSize(FETCH_SIZE);
933
             logger.info("FETCH_SIZE = " + FETCH_SIZE);
934

    
935
            ResultSet _r = null;
936
            _r = st.executeQuery(_sql);
937

    
938
            ROWID ri = null;
939

    
940
            int row = 0;
941
            String gid;
942
            Value aux = null;
943

    
944
            // ----------------------------------- types init
945
            ArrayList types = new ArrayList();
946
            int types_aux = 0;
947

    
948
            ARRAY info_aux;
949
            int[] info_aux_int;
950
            int size;
951

    
952
            // ----------------------------------- types init
953
            logger.debug("Beginning of result set:");
954

    
955
            while (_r.next()) {
956
                // ---------------------------------------
957
                ri = (ROWID) _r.getObject(1);
958
                gid = ri.stringValue();
959
                aux = ValueFactory.createValue(gid);
960

    
961
                Integer intobj = new Integer(row);
962
                hashRelate.put(aux, intobj);
963
                rowToId.put(intobj, ri);
964

    
965
                if ((row % 5000) == 0) {
966
                    // ------------------------------------------- cancel load
967
                    if (cancelIDLoad) {
968
                        hashRelate.clear();
969
                        rowToId.clear();
970

    
971
                        return;
972
                    }
973

    
974
                    // -------------------------------------------
975
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
976
                    logger.info("IDs read: " + fmt);
977
                }
978

    
979
                row++;
980

    
981
                // --------------------------------------- types
982
                info_aux = (ARRAY) _r.getObject(2);
983

    
984
                if (info_aux == null) {
985
                    // logger.debug("NULL info array found in record: " + row);
986
                }
987
                else {
988
                    info_aux_int = info_aux.getIntArray();
989
                    size = info_aux_int.length / 3;
990

    
991
                    for (int i = 0; i < size; i++) {
992
                        types_aux = info_aux_int[(3 * i) + 1];
993
                        types.add(new Integer(types_aux % 1000));
994
                    }
995
                }
996

    
997
                // --------------------------------------- types end
998
            }
999

    
1000
            _r.close();
1001
//            ps.close();
1002
            st.close();
1003
            numReg = row;
1004

    
1005
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
1006

    
1007
            if (needsCollectionLayer) {
1008
                shapeType = FShape.MULTI;
1009
            }
1010
        }
1011
        catch (SQLException e) {
1012
                logger.error("While setting id-row hashmap: " +
1013
                e.getMessage());
1014
        }
1015
    }
1016

    
1017
    public int getFieldCount() throws ReadDriverException {
1018
        try {
1019
            return metaData.getColumnCount();
1020
        }
1021
        catch (SQLException e) {
1022
                logger.error("While getting field count: " + e.getMessage());
1023
            throw new ReadDriverException(getName(), e);
1024
        }
1025
    }
1026

    
1027
    public String[] getFieldNames() {
1028
        return fieldNames;
1029
    }
1030

    
1031
    public String getTotalFields() {
1032
        String strAux = "";
1033

    
1034
        for (int i = 0; i < fieldNames.length; i++) {
1035
            if (i == 0) {
1036
                strAux = fieldNames[i];
1037
            }
1038
            else {
1039
                strAux = strAux + ", " + fieldNames[i];
1040
            }
1041
        }
1042

    
1043
        return strAux;
1044
    }
1045

    
1046
    public int getFieldType(int idField) throws ReadDriverException {
1047
        int i = 0;
1048

    
1049
        try {
1050
            i = idField + 1; // idField viene basado en 0
1051

    
1052
            int __type = metaData.getColumnType(i);
1053

    
1054
            // we must add this entry because we did not remove the 'geometry' column
1055
            if (__type == Types.STRUCT) {
1056
                return Types.VARCHAR; // .STRUCT;
1057
                                      // ----------------------------------------------------------------------
1058
            }
1059

    
1060
            if (__type == Types.VARCHAR) {
1061
                return Types.VARCHAR;
1062
            }
1063

    
1064
            if (__type == Types.FLOAT) {
1065
                return Types.FLOAT;
1066
            }
1067

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

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

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

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

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

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

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

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

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

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

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

    
1112
            if (__type == Types.TIMESTAMP) {
1113
                return Types.TIMESTAMP;
1114
            }
1115
        }
1116
        catch (SQLException e) {
1117
            logger.error("Unknown field type of : " + i);
1118
            throw new ReadDriverException(getName(), e);
1119
        }
1120

    
1121
        return -1;
1122
    }
1123

    
1124
    public Value[] getAttributes(ResultSet rs) {
1125
        Value[] res = null;
1126
        
1127
        int fcount = 0;
1128

    
1129
        try {
1130
            fcount = rs.getMetaData().getColumnCount();
1131
            res = new Value[fcount];
1132

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

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

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

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

    
1200
                if (obj instanceof String) {
1201
                    objToString = (String) obj;
1202
                    _type = Types.VARCHAR;
1203
                }
1204
                else {
1205
                    if (obj instanceof ROWID) {
1206
                        objToString = ((ROWID) obj).stringValue();
1207
                        _type = Types.VARCHAR;
1208
                    }
1209
                    else {
1210
                        if (obj instanceof STRUCT) {
1211
                            objToString = "STRUCT";
1212
                            _type = Types.VARCHAR;
1213
                        }
1214
                        else {
1215
                            objToString = (obj == null) ? "NULL" : obj.toString();
1216
                            try {
1217
                                                                _type = getFieldType(i);
1218
                                                        } catch (ReadDriverException e) {
1219
                                                                logger.error("TYPE = -1 due to exception");
1220
                                                        }
1221
                        }
1222
                    }
1223
                }
1224

    
1225
                // /*
1226
                if (_type == -1) {
1227
                    obj = null;
1228
                }
1229

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

    
1239
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1240
                }
1241
            }
1242
        } catch (Exception se) {
1243
                logger.error("While getting attributes: " + se.getMessage());
1244
            return null;
1245
        }
1246

    
1247
        return res;
1248
    }
1249

    
1250

    
1251
    public String getFieldName(int fieldId) throws ReadDriverException {
1252
        return fieldNames[fieldId];
1253
    }
1254

    
1255
    public int getFieldWidth(int fieldId) {
1256
        int i = -1;
1257

    
1258
        try {
1259
            int aux = fieldId + 1; // fieldId viene basado en 0
1260
            i = metaData.getColumnDisplaySize(aux);
1261
        }
1262
        catch (SQLException e) {
1263
            logger.error("While getting field width: " + e.getMessage());
1264
        }
1265

    
1266
        if (i < 0) {
1267
            i = 255;
1268
        }
1269

    
1270
        return i;
1271
    }
1272

    
1273
    public Value getFieldValue(long rowIndex, int field_Id) throws ReadDriverException {
1274
        if (isNotAvailableYet) {
1275
            return nullVal;
1276
        }
1277

    
1278
        if ((singleCachedFeature != null) &&
1279
                (rowIndex == singleCachedFeatureRowNum)) {
1280
            return singleCachedFeature.getAttributes()[field_Id];
1281
        }
1282

    
1283
        // return ValueFactory.createNullValue();
1284
        ResultSet _r = null;
1285
        java.sql.PreparedStatement ps = null;
1286

    
1287
        try {
1288
            String rnq = getSearchId();
1289
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1290

    
1291
            ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(rnq);
1292
            ps.setObject(1, _id);
1293

    
1294
            ps.execute();
1295
            _r = ps.getResultSet();
1296
            
1297
            if (!_r.next()) {
1298
                _r.close();
1299
                ps.close();
1300
                    throw new SQLException("No row for ROWID: " + _id.toString() + ". Possibly deleted from another app.");
1301
            }
1302
            
1303
        } catch (SQLException se) {
1304
                logger.error("While getting row " + rowIndex + " : " + se.getMessage());
1305
                return ValueFactory.createNullValue();
1306
        }
1307

    
1308
        IFeature ife = null;
1309
        Value[] atts = null;
1310

    
1311
        try {
1312
            ROWID ri = (ROWID) _r.getObject(1);
1313
            atts = getAttributesUsingMainMetadata(_r);
1314

    
1315
            String gid = ri.stringValue();
1316
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1317
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1318
            ife = new DefaultFeature(theGeom, atts, gid);
1319
            _r.close();
1320
            ps.close();
1321
        } catch (SQLException se) {
1322
            logger.error("Error while doing next(): " + se.getMessage(), se);
1323
            return ValueFactory.createNullValue();
1324
        }
1325

    
1326
        // -------------------------------
1327
        singleCachedFeature = ife;
1328
        singleCachedFeatureRowNum = rowIndex;
1329

    
1330
        // -------------------------------
1331
        if (atts == null) {
1332
            return ValueFactory.createNullValue();
1333
        } else {
1334
            return atts[field_Id];
1335
        }
1336
    }
1337

    
1338
    public static void showMemory() {
1339
        Runtime r = Runtime.getRuntime();
1340
        long mem = r.totalMemory() - r.freeMemory();
1341
        logger.info("Total memory : " + mem);
1342
    }
1343

    
1344
    public Rectangle2D getFullExtent() {
1345
            return full_Extent;
1346
    }
1347

    
1348
    /**
1349
     * Utility method to get a geometry from a struct.
1350
     *
1351
     * @param theStruct the struct to be converted
1352
     * @param use_gtools switch to use geotools classes or not
1353
     * @return the geometry
1354
     * @throws SQLException
1355
     */
1356
    public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
1357
        throws SQLException {
1358
        IGeometry _igeom = null;
1359

    
1360
        if (theStruct == null) {
1361
            return nullGeom;
1362
        }
1363

    
1364
        if (use_gtools) { // geotools
1365
//            _igeom = getGeotoolsIGeometry(theStruct);
1366
        }
1367
        else { // jgeometry
1368
            _igeom = getFMapGeometry(theStruct, false);
1369
        }
1370

    
1371
        return _igeom;
1372
    }
1373

    
1374
    /*
1375
    private IGeometry getFMapGeometry(JGeometry jg, boolean force_not_collection) {
1376
        int jgtype = jg.getType();
1377
        int dim = jg.getDimensions();
1378
        IGeometry ig = null;
1379

1380
        if ((jgtype != JGeometry.GTYPE_COLLECTION) &&
1381
                (isActuallyACollection(jg))) {
1382
            jgtype = JGeometry.GTYPE_COLLECTION;
1383
        }
1384

1385
        switch (jgtype) {
1386
        case JGeometry.GTYPE_COLLECTION:
1387

1388
            int srid = jg.getSRID();
1389
            ig = getFMapGeometryCollection(jg, dim, srid);
1390

1391
            break;
1392

1393
        case JGeometry.GTYPE_POINT:
1394
        case JGeometry.GTYPE_MULTIPOINT:
1395
            ig = getFMapGeometryPoint(jg, dim);
1396

1397
            break;
1398

1399
        case JGeometry.GTYPE_CURVE:
1400
        case JGeometry.GTYPE_MULTICURVE:
1401
            ig = getFMapGeometryMultiLineString(jg, dim);
1402

1403
            break;
1404

1405
        case JGeometry.GTYPE_POLYGON:
1406
        case JGeometry.GTYPE_MULTIPOLYGON:
1407
            ig = getFMapGeometryMultipolygon(jg, dim);
1408

1409
            break;
1410
        }
1411

1412
        return ig;
1413
    }
1414
    */
1415

    
1416
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim) {
1417
        // int __srid) {
1418

    
1419
            NUMBER _srid = new NUMBER(0);
1420
        NUMBER main_type = new NUMBER((dim * 1000) +
1421
                OracleSpatialUtils.getStructType(the_data));
1422

    
1423

    
1424
        Datum[] all_info_array = null;
1425
        Object[] elems_info_aray = null;
1426
        Datum[] all_ords = null;
1427

    
1428
        Object[] ords_of_groups = null;
1429
        Object[] _elems_info_aray = null;
1430
        try {
1431
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1432
            elems_info_aray = groupByElement(all_info_array);
1433
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1434

    
1435
            ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1436
            _elems_info_aray = new Object[elems_info_aray.length];
1437
        }
1438
        catch (SQLException e) {
1439
            logger.error("Unexpected error: " + e.getMessage());
1440
        }
1441

    
1442

    
1443
        for (int i = 0; i < elems_info_aray.length; i++) {
1444
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1445
        }
1446

    
1447
        // _elems_info_aray, ords_of_groups
1448
        int no_of_elems = ords_of_groups.length;
1449
        IGeometry[] geoms = new IGeometry[no_of_elems];
1450

    
1451
        for (int i = 0; i < no_of_elems; i++) {
1452
            Datum[] item_info_array = null;
1453
            Datum[] item_ords = null;
1454
            NUMBER gtype = null;
1455

    
1456
            try {
1457
                item_info_array = (Datum[]) _elems_info_aray[i];
1458
                item_ords = (Datum[]) ords_of_groups[i];
1459

    
1460
                gtype = new NUMBER((dim * 1000) +
1461
                        (item_info_array[1].intValue() % 1000));
1462

    
1463
                if (tableHasSrid) {
1464
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1465
                }
1466
            }
1467
            catch (SQLException se) {
1468
                logger.error("Unexpected error: " + se.getMessage());
1469
            }
1470

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

    
1474
            STRUCT itemst = null;
1475

    
1476
            if (tableHasSrid) {
1477

    
1478
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1479
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1480
            }
1481
            else {
1482
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1483
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1484
            }
1485

    
1486
            geoms[i] = getFMapGeometry(itemst, true);
1487
        }
1488

    
1489
        return new FGeometryCollection(geoms);
1490
    }
1491

    
1492
    /**
1493
     * Utility method to transform a struct into a IGeometry.
1494
     *
1495
     * @param st the struct to be converted
1496
     * @param force_not_collection t5his parameter is currently ignored
1497
     * @return the IGeometry
1498
     */
1499
    public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1500

    
1501
            if (st == null) {
1502
                    return new FNullGeometry();
1503
            }
1504

    
1505
        Datum[] the_data = null;
1506

    
1507
        try {
1508
            the_data = st.getOracleAttributes();
1509

    
1510
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1511
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1512

    
1513
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1514

    
1515
            if (dim < 2) {
1516
                dim = 2;
1517
            }
1518

    
1519
            IGeometry ig = null;
1520

    
1521
            if (isActuallyACollection(the_data)) {
1522
                    logger.debug("isActuallyACollection(the_data) = TRUE");
1523
                jgtype = FShape.MULTI;
1524
            }
1525

    
1526
            switch (jgtype) {
1527
            case FShape.MULTI:
1528

    
1529
                // int srid = ((NUMBER) the_data[1]).intValue();
1530
                ig = getFMapGeometryCollection(the_data, dim);
1531

    
1532
                break;
1533

    
1534
            case FShape.POINT:
1535
                ig = getFMapGeometryPoint(the_data, dim);
1536

    
1537
                break;
1538

    
1539
            case FShape.LINE:
1540
                ig = getFMapGeometryMultiLineString(the_data, dim);
1541

    
1542
                break;
1543

    
1544
            case FShape.POLYGON:
1545
                ig = getFMapGeometryMultipolygon(the_data, dim);
1546

    
1547
                break;
1548
            }
1549

    
1550
            return ig;
1551
        }
1552
        catch (SQLException e) {
1553
            logger.error(e);
1554
        }
1555

    
1556
        return null;
1557
    }
1558

    
1559
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1560
        int size = input.length / n;
1561
        double[] resp = new double[size];
1562

    
1563
        for (int i = 0; i < size; i++) {
1564
            resp[i] = input[(i * n) + ind];
1565
        }
1566

    
1567
        return resp;
1568
    }
1569

    
1570
    private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1571
        int size = input.length / n;
1572
        double[] resp = new double[size];
1573

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

    
1578
        return resp;
1579
    }
1580

    
1581
    /*
1582
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1583
        IGeometry ig = null;
1584

1585
        if (jg.isCircle()) {
1586
            ig = getCircleFromJGeometry(jg);
1587
        }
1588
        else {
1589
            Shape shape = jg.createShape();
1590
            GeneralPathX gpx = new GeneralPathX(shape);
1591

1592
            if (dim == 2) {
1593
                ig = ShapeFactory.createPolygon2D(gpx);
1594
            }
1595
            else {
1596
                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1597
                ig = ShapeFactory.createPolygon3D(gpx, z);
1598
            }
1599
        }
1600

1601
        return ig;
1602
    }
1603
    */
1604

    
1605
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1606
        IGeometry ig = null;
1607

    
1608
        if (OracleSpatialUtils.isCircle(the_data)) {
1609
            ig = getCircleFromStruct(the_data);
1610
        }
1611
        else {
1612
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1613

    
1614
            if (dim == 2) {
1615
                ig = ShapeFactory.createPolygon2D(gpx);
1616
            }
1617
            else {
1618
                double[] ords = null;
1619

    
1620
                try {
1621
                    ords = ((ARRAY) the_data[4]).getDoubleArray();
1622
                }
1623
                catch (SQLException se) {
1624
                    logger.error("While getting ordinates: " + se.getMessage(),
1625
                        se);
1626
                }
1627

    
1628
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1629
                ig = ShapeFactory.createPolygon3D(gpx, z);
1630
            }
1631
        }
1632

    
1633
        return ig;
1634
    }
1635

    
1636
    /*
1637
    private IGeometry getCircleFromJGeometry(JGeometry jg) {
1638
        double[] threep = jg.getOrdinatesArray();
1639
        Point2D[] three = new Point2D.Double[3];
1640
        three[0] = new Point2D.Double(threep[0], threep[1]);
1641
        three[1] = new Point2D.Double(threep[2], threep[3]);
1642
        three[2] = new Point2D.Double(threep[4], threep[5]);
1643

1644
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1645

1646
        Point2D cent = (Point2D) cent_rad[0];
1647
        double radius = ((Double) cent_rad[1]).doubleValue();
1648

1649
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1650

1651
        return circ;
1652
    }
1653
    */
1654

    
1655
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1656
        double[] threep = null;
1657

    
1658
        try {
1659
            threep = ((ARRAY) the_data[4]).getDoubleArray();
1660
        }
1661
        catch (SQLException se) {
1662
            logger.error("While getting ords from struct: " + se.getMessage(),
1663
                se);
1664

    
1665
            return new FNullGeometry();
1666
        }
1667

    
1668
        Point2D[] three = new Point2D.Double[3];
1669
        three[0] = new Point2D.Double(threep[0], threep[1]);
1670
        three[1] = new Point2D.Double(threep[2], threep[3]);
1671
        three[2] = new Point2D.Double(threep[4], threep[5]);
1672

    
1673
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1674

    
1675
        Point2D cent = (Point2D) cent_rad[0];
1676
        double radius = ((Double) cent_rad[1]).doubleValue();
1677

    
1678
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1679

    
1680
        return circ;
1681
    }
1682

    
1683
    /*
1684
    private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1685
        Shape shape = jg.createShape();
1686
        GeneralPathX gpx = new GeneralPathX(shape);
1687
        IGeometry ig = null;
1688

1689
        if (dim == 2) {
1690
            ig = ShapeFactory.createPolyline2D(gpx);
1691
        }
1692
        else {
1693
            double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1694
            ig = ShapeFactory.createPolyline3D(gpx, z);
1695
        }
1696

1697
        return ig;
1698
    }
1699
    */
1700

    
1701
    private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1702
        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1703
        IGeometry ig = null;
1704
        double[] ords = null;
1705

    
1706
        if (dim == 2) {
1707
            ig = ShapeFactory.createPolyline2D(gpx);
1708
        }
1709
        else {
1710
            ords = OracleSpatialUtils.getOrds(the_data);
1711

    
1712
            double[] z = getIndBigDecimalModule(ords, 2, dim);
1713
            ig = ShapeFactory.createPolyline3D(gpx, z);
1714
        }
1715

    
1716
        return ig;
1717
    }
1718

    
1719
    /*
1720
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1721
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1722

1723
            return getFMapGeometrySdoPoint(jg_point, dim);
1724
        }
1725

1726
        IGeometry ig = null;
1727
        int total_size = jg_point.getOrdinatesArray().length;
1728
        int no_po = total_size / dim;
1729
        double[] x = new double[no_po];
1730
        double[] y = new double[no_po];
1731
        double[] z = new double[no_po];
1732

1733
        for (int i = 0; i < no_po; i++) {
1734
            x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1735
            y[i] = jg_point.getOrdinatesArray()[(i * dim) + 1];
1736

1737
            if (dim >= 3) {
1738
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1739
            }
1740
        }
1741

1742
        if (dim == 2) {
1743
            if (no_po == 1) {
1744
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1745
            }
1746
            else {
1747
                ig = ShapeFactory.createMultipoint2D(x, y);
1748
            }
1749
        }
1750
        else {
1751
            if (no_po == 1) {
1752
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1753
            }
1754
            else {
1755
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1756
            }
1757
        }
1758

1759
        return ig;
1760
    }
1761
    */
1762

    
1763
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1764
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1765

    
1766
        if (ords == null) { // sdo_point
1767

    
1768
            return getFMapGeometrySdoPoint(the_data, dim);
1769
        }
1770

    
1771
        IGeometry ig = null;
1772
        int total_size = ords.length;
1773
        int no_po = total_size / dim;
1774
        double[] x = new double[no_po];
1775
        double[] y = new double[no_po];
1776
        double[] z = new double[no_po];
1777

    
1778
        for (int i = 0; i < no_po; i++) {
1779
            x[i] = ords[i * dim]; // pp[i].getX();
1780
            y[i] = ords[(i * dim) + 1];
1781

    
1782
            if (dim >= 3) {
1783
                z[i] = ords[(i * dim) + 2];
1784
            }
1785
        }
1786

    
1787
        if (dim == 2) {
1788
            if (no_po == 1) {
1789
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1790
            }
1791
            else {
1792
                ig = ShapeFactory.createMultipoint2D(x, y);
1793
            }
1794
        }
1795
        else {
1796
            if (no_po == 1) {
1797
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1798
            }
1799
            else {
1800
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1801
            }
1802
        }
1803

    
1804
        return ig;
1805
    }
1806

    
1807
    /*
1808
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1809
        double[] p = jgp.getPoint();
1810
        IGeometry ig = null;
1811

1812
        if (d == 2) {
1813
            ig = ShapeFactory.createPoint2D(p[0], p[1]);
1814
        }
1815
        else {
1816
            ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1817
        }
1818

1819
        return ig;
1820
    }
1821
    */
1822

    
1823
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1824
        double x = 0;
1825
        double y = 0;
1826
        double z = 0;
1827

    
1828
        try {
1829
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1830
            x = ((NUMBER) aux[0]).doubleValue();
1831
            y = ((NUMBER) aux[1]).doubleValue();
1832

    
1833
            if (d > 2) {
1834
                z = ((NUMBER) aux[2]).doubleValue();
1835
            }
1836
        }
1837
        catch (SQLException se) {
1838
            logger.error("While getting sdo point ordinates: " +
1839
                se.getMessage(), se);
1840
        }
1841

    
1842
        IGeometry ig = null;
1843

    
1844
        if (d == 2) {
1845
            ig = ShapeFactory.createPoint2D(x, y);
1846
        }
1847
        else {
1848
            ig = ShapeFactory.createPoint3D(x, y, z);
1849
        }
1850

    
1851
        return ig;
1852
    }
1853

    
1854
    /*
1855
    private boolean isActuallyACollection(JGeometry jg) {
1856
        int[] info = jg.getElemInfo();
1857

1858
        if (info == null) {
1859
            return false; // sdo_point
1860
        }
1861

1862
        int size = info.length / 3;
1863

1864
        if (size == 1) {
1865
            return false;
1866
        }
1867

1868
        if (size == 2) {
1869
            return ((info[1] % 1000) != (info[4] % 1000));
1870
        }
1871

1872
        int second = info[4] % 1000;
1873

1874
        for (int i = 2; i < size; i++) {
1875
            if ((info[(i * 3) + 1] % 1000) != second) {
1876
                return true;
1877
            }
1878
        }
1879

1880
        return false;
1881
    }
1882
    */
1883

    
1884
    private boolean isActuallyACollection(Datum[] the_data) {
1885
        int[] info = null;
1886

    
1887
        try {
1888
            ARRAY aux = (ARRAY) the_data[3];
1889

    
1890
            if (aux == null) {
1891
                return false;
1892
            }
1893

    
1894
            info = aux.getIntArray();
1895
        }
1896
        catch (SQLException se) {
1897
            logger.error("While checking collection: " + se.getMessage());
1898
            return false;
1899
        }
1900

    
1901
        if (info == null) {
1902
            return false; // sdo_point
1903
        }
1904

    
1905
        int size = info.length / 3;
1906

    
1907
        if (size == 1) {
1908
            return false;
1909
        }
1910

    
1911
        if (size == 2) {
1912
            return ((info[1] % 1000) != (info[4] % 1000)) &&
1913
            ( ! ((info[1] == 1005) && (info[4] == 2)) );
1914
        }
1915

    
1916
        int second = info[4] % 1000;
1917
        int item = 0;
1918

    
1919
        for (int i = 2; i < size; i++) {
1920
                item = info[(i * 3) + 1] % 1000;
1921
            if ((item != second) &&
1922
                            ( ! ((item == 5) && (second == 2)) )
1923
                            ) {
1924
                return true;
1925
            }
1926
        }
1927

    
1928
        return false;
1929
    }
1930

    
1931
    /*
1932
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1933
        int main_type = jg.getType();
1934

1935
        int[] all_info_array = jg.getElemInfo();
1936
        Object[] elems_info_aray = groupByElement(all_info_array);
1937
        double[] all_ords = jg.getOrdinatesArray();
1938
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1939
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1940

1941
        for (int i = 0; i < elems_info_aray.length; i++) {
1942
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1943
        }
1944

1945
        // _elems_info_aray, ords_of_groups
1946
        int no_of_elems = ords_of_groups.length;
1947
        IGeometry[] geoms = new IGeometry[no_of_elems];
1948

1949
        for (int i = 0; i < no_of_elems; i++) {
1950
            int[] item_info_array = (int[]) _elems_info_aray[i];
1951
            double[] item_ords = (double[]) ords_of_groups[i];
1952
            int gtype = (dim * 1000) + (item_info_array[1] % 1000);
1953

1954
            // if it's the first geometry, the type is the collection's main type (no?)
1955
            if (i == 0) {
1956
                gtype = main_type;
1957
            }
1958

1959
            JGeometry itemjg = null;
1960

1961
            if (tableHasSrid) {
1962
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1963
            }
1964
            else {
1965
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1966
            }
1967

1968
            geoms[i] = getFMapGeometry(itemjg, true);
1969
        }
1970

1971
        return new FGeometryCollection(geoms);
1972
    }
1973
    */
1974

    
1975
    private Datum[] updateIndexes(Datum[] info) {
1976
        int size = info.length / 3;
1977
        NUMBER[] resp = new NUMBER[3 * size];
1978

    
1979
        try {
1980
            int rest = info[0].intValue() - 1;
1981

    
1982
            for (int i = 0; i < size; i++) {
1983
                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1984
                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
1985
                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
1986
            }
1987
        }
1988
        catch (SQLException se) {
1989
            logger.error("Unexpected error: " + se.getMessage());
1990
        }
1991

    
1992
        return resp;
1993
    }
1994

    
1995
    private int[] updateIndexes(int[] info) {
1996
        int size = info.length / 3;
1997
        int[] resp = new int[3 * size];
1998
        int rest = info[0] - 1;
1999

    
2000
        for (int i = 0; i < size; i++) {
2001
            resp[3 * i] = info[3 * i] - rest;
2002
            resp[(3 * i) + 1] = info[(3 * i) + 1];
2003
            resp[(3 * i) + 2] = info[(3 * i) + 2];
2004
        }
2005

    
2006
        return resp;
2007
    }
2008

    
2009
    private int[] appendIntArrays(int[] head, int[] tail) {
2010
        int[] resp = new int[head.length + tail.length];
2011
        int hsize = head.length;
2012

    
2013
        for (int i = 0; i < hsize; i++) {
2014
            resp[i] = head[i];
2015
        }
2016

    
2017
        for (int i = 0; i < tail.length; i++) {
2018
            resp[hsize + i] = tail[i];
2019
        }
2020

    
2021
        return resp;
2022
    }
2023

    
2024
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
2025
        Datum[] resp = new Datum[head.length + tail.length];
2026
        int hsize = head.length;
2027

    
2028
        for (int i = 0; i < hsize; i++) {
2029
            resp[i] = head[i];
2030
        }
2031

    
2032
        for (int i = 0; i < tail.length; i++) {
2033
            resp[hsize + i] = tail[i];
2034
        }
2035

    
2036
        return resp;
2037
    }
2038

    
2039
    private int[] getNthGroupOfThree(int[] list, int n) {
2040
        int[] resp = new int[3];
2041
        resp[0] = list[3 * n];
2042
        resp[1] = list[(3 * n) + 1];
2043
        resp[2] = list[(3 * n) + 2];
2044

    
2045
        return resp;
2046
    }
2047

    
2048
    private Datum[] getNthGroupOfThree(Datum[] list, int n) {
2049
        Datum[] resp = new Datum[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[] getSubSet(Datum[] all, int first_inc, int last_inc) {
2058
        Datum[] resp = new Datum[last_inc - first_inc + 1];
2059

    
2060
        for (int i = first_inc; i <= last_inc; i++) {
2061
            resp[i - first_inc] = all[i];
2062
        }
2063

    
2064
        return resp;
2065
    }
2066

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

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

    
2074
        return resp;
2075
    }
2076

    
2077
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) throws SQLException {
2078
        Object[] resp = new Object[groups.length];
2079

    
2080
        if (resp.length == 1) {
2081
            resp[0] = all;
2082

    
2083
            return resp;
2084
        }
2085

    
2086
        int ind = 0;
2087
        Datum[] aux = (Datum[]) groups[1];
2088
        int _end = aux[0].intValue() - 2;
2089
        Datum[] ord_aux = getSubSet(all, 0, _end);
2090

    
2091
        int _start = _end + 1;
2092
        resp[ind] = ord_aux;
2093
        ind++;
2094

    
2095
        for (int i = 2; i < groups.length; i++) {
2096
            aux = (Datum[]) groups[i];
2097
            _end = aux[0].intValue() - 2;
2098
            ord_aux = getSubSet(all, _start, _end);
2099
            resp[ind] = ord_aux;
2100
            ind++;
2101
            _start = _end + 1;
2102
        }
2103

    
2104
        // last
2105
        _end = all.length - 1;
2106
        ord_aux = getSubSet(all, _start, _end);
2107
        resp[groups.length - 1] = ord_aux;
2108

    
2109
        return resp;
2110
    }
2111

    
2112
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2113
        Object[] resp = new Object[groups.length];
2114

    
2115
        if (resp.length == 1) {
2116
            resp[0] = all;
2117

    
2118
            return resp;
2119
        }
2120

    
2121
        int ind = 0;
2122
        int[] aux = (int[]) groups[1];
2123
        int _end = aux[0] - 2;
2124
        double[] ord_aux = getSubSet(all, 0, _end);
2125

    
2126
        int _start = _end + 1;
2127
        resp[ind] = ord_aux;
2128
        ind++;
2129

    
2130
        for (int i = 2; i < groups.length; i++) {
2131
            aux = (int[]) groups[i];
2132
            _end = aux[0] - 2;
2133
            ord_aux = getSubSet(all, _start, _end);
2134
            resp[ind] = ord_aux;
2135
            ind++;
2136
            _start = _end + 1;
2137
        }
2138

    
2139
        // last
2140
        _end = all.length - 1;
2141
        ord_aux = getSubSet(all, _start, _end);
2142
        resp[groups.length - 1] = ord_aux;
2143

    
2144
        return resp;
2145
    }
2146

    
2147
    private Object[] groupByElement(int[] all_elem) {
2148
        ArrayList resp = new ArrayList();
2149

    
2150
        int size = all_elem.length / 3;
2151

    
2152
        int[] aux = getNthGroupOfThree(all_elem, 0);
2153

    
2154
        int[] newaux;
2155
        int i = 1;
2156

    
2157
        while (i < size) {
2158
            newaux = getNthGroupOfThree(all_elem, i);
2159

    
2160
            if (newaux[0] == aux[0]) {
2161
                // aux[2] says how many components
2162
                for (int j = 0; j < aux[2]; j++) {
2163
                    aux = appendIntArrays(aux,
2164
                            getNthGroupOfThree(all_elem, j + i));
2165
                }
2166

    
2167
                resp.add(aux);
2168
                i = i + aux[2];
2169
                aux = getNthGroupOfThree(all_elem, i);
2170
            }
2171
            else {
2172
                if (newaux[1] == 2003) {
2173
                    aux = appendIntArrays(aux, newaux);
2174
                }
2175
                else {
2176
                    resp.add(aux);
2177
                    aux = getNthGroupOfThree(all_elem, i);
2178
                }
2179
            }
2180

    
2181
            i++;
2182
        }
2183

    
2184
        resp.add(aux);
2185

    
2186
        return resp.toArray();
2187
    }
2188

    
2189
    private Object[] groupByElement(Datum[] all_elem) {
2190
        ArrayList resp = new ArrayList();
2191

    
2192
        int size = all_elem.length / 3;
2193

    
2194
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2195

    
2196
        Datum[] newaux;
2197
        int i = 1;
2198

    
2199
        try {
2200
            while (i < size) {
2201
                newaux = getNthGroupOfThree(all_elem, i);
2202

    
2203
                if (newaux[0] == aux[0]) {
2204
                    // aux[2] says how many components
2205
                    for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
2206
                        aux = appendDatArrays(aux,
2207
                                getNthGroupOfThree(all_elem, j + i));
2208
                    }
2209

    
2210
                    resp.add(aux);
2211
                    i = i + ((NUMBER) aux[2]).intValue();
2212
                    aux = getNthGroupOfThree(all_elem, i);
2213
                }
2214
                else {
2215
                    if (((NUMBER) newaux[1]).intValue() == 2003) {
2216
                        aux = appendDatArrays(aux, newaux);
2217
                    }
2218
                    else {
2219
                        resp.add(aux);
2220
                        aux = getNthGroupOfThree(all_elem, i);
2221
                    }
2222
                }
2223

    
2224
                i++;
2225
            }
2226
        }
2227
        catch (SQLException se) {
2228
            logger.error("Unexpected error: " + se.getMessage());
2229
        }
2230

    
2231
        resp.add(aux);
2232

    
2233
        return resp.toArray();
2234
    }
2235

    
2236
    /*
2237
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2238
        Point2D p = _jgeom.getJavaPoint();
2239
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2240

2241
        return ig;
2242
    }
2243

2244
    private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2245
        Point2D[] pp = _jgeom.getJavaPoints();
2246
        int l = pp.length;
2247
        double[] x = new double[l];
2248
        double[] y = new double[l];
2249

2250
        for (int i = 0; i < l; i++) {
2251
            x[i] = pp[i].getX();
2252
            y[i] = pp[i].getY();
2253
        }
2254

2255
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2256

2257
        return ig;
2258
    }
2259

2260
    private IGeometry getJGeometryOther(JGeometry _jgeom) {
2261
        int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2262
        Shape shape = _jgeom.createShape();
2263
        GeneralPathX gpx = new GeneralPathX(shape);
2264
        IGeometry ig = null;
2265

2266
        switch (type) {
2267
        case FShape.LINE:
2268

2269
            FPolyline2D fpl = new FPolyline2D(gpx);
2270
            ig = ShapeFactory.createPolyline2D(gpx);
2271

2272
            break;
2273

2274
        case FShape.POLYGON:
2275

2276
            FPolygon2D fpg = new FPolygon2D(gpx);
2277
            ig = ShapeFactory.createPolygon2D(gpx);
2278

2279
            break;
2280
        }
2281

2282
        return ig;
2283
    }
2284
    */
2285

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

    
2317
        case JGeometry_GTYPE_CURVE:
2318
        case JGeometry_GTYPE_MULTICURVE:
2319
            return FShape.LINE;
2320
        }
2321

    
2322
        logger.error("Unhandled Oracle Spatial geometry type: " + type +
2323
            " (conversion returned FShape.NULL)");
2324

    
2325
        return FShape.NULL;
2326
    }
2327

    
2328
    private void cleanWhereClause() {
2329
        emptyWhereClause = false;
2330

    
2331
        String aux = getWhereClauseWithoutWhere();
2332

    
2333
        for (int i = 0; i < aux.length(); i++)
2334
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
2335
                return;
2336
            }
2337

    
2338
        getLyrDef().setWhereClause("");
2339
        emptyWhereClause = true;
2340
    }
2341

    
2342
    private String getValidViewConstructor(
2343
                    STRUCT _st,
2344
                    String ora_srid,
2345
                    boolean _hassrid,
2346
                    boolean _isgeocs) {
2347

    
2348
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
2349
            String resp = "";
2350
            if ((_hassrid) && (_isgeocs)) {
2351
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
2352
            } else {
2353
                    resp = sdo;
2354
            }
2355

    
2356
            return resp;
2357
    }
2358

    
2359
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2360
        String resp = "";
2361

    
2362
        if (isGeogCS) {
2363
            String vport = "sdo_filter(" + geoColName +
2364
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
2365
                "), 'querytype=window') = 'TRUE'";
2366

    
2367
                resp = "select " + getStandardSelectExpression() + ", c." +
2368
                    geoColName + " from " + getTableName() + " c where ";
2369
                if (idsLoadWhere.length() > 0) {
2370
                        resp = resp + " (" + idsLoadWhere + ") AND ";
2371
                }
2372
                resp = resp + "(" + vport + ")";
2373
        }
2374
        else {
2375
                resp = "select " + getStandardSelectExpression() + ", c." +
2376
                    geoColName + " from " + getTableName() + " c where ";
2377
                if (idsLoadWhere.length() > 0) {
2378
                        resp = resp + " (" + idsLoadWhere + ") AND ";
2379
                }
2380
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
2381
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
2382
        }
2383

    
2384
//        return "select " + getStandardSelectExpression() + ", c." +
2385
//        geoColName + " from " + getTableName() + " c";
2386
        return resp;
2387
    }
2388

    
2389
    public void setWorkingArea(Rectangle2D rect) {
2390
    }
2391

    
2392
    private void setWAStructt() {
2393
    }
2394

    
2395
    private Geometry shapeToGeometry(Shape shp) {
2396
        if (shp == null) {
2397
            return null;
2398
        }
2399

    
2400
        int type = FShape.POLYGON;
2401

    
2402
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2403
            type = FShape.LINE;
2404
        }
2405

    
2406
        if (shp instanceof FPoint2D) {
2407
            type = FShape.POINT;
2408
        }
2409

    
2410
        if (shp instanceof FMultiPoint2D) {
2411
            type = FShape.MULTIPOINT;
2412
        }
2413

    
2414
        GeneralPathX wagp = new GeneralPathX(shp);
2415
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2416

    
2417
        return FConverter.java2d_to_jts(fwagp);
2418
    }
2419

    
2420
    /*
2421
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2422
        Shape shape = _jg.createShape();
2423

2424
        return shape.getBounds2D();
2425
    }
2426
    */
2427

    
2428
    private void printStruct(STRUCT st) {
2429
        System.out.println("----------------------------------------------");
2430

    
2431
        try {
2432
            Object[] att = st.getAttributes();
2433
            int l = att.length;
2434

    
2435
            for (int i = 0; i < l; i++) {
2436
                System.out.println("ATT " + i + ": " + att[i].toString());
2437
            }
2438
        }
2439
        catch (Exception ex) {
2440
            System.out.println(
2441
                "- Error ---------------------------------------");
2442
        }
2443

    
2444
        System.out.println("----------------------------------------------");
2445
    }
2446

    
2447
    private static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
2448
        boolean isView, boolean _isGeogCS, String _oracleSRID, IConnection __conn) {
2449
        Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2450
        Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2451

    
2452
        if ((_isGeogCS) && (isView)) {
2453
            c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2454
            c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2455
        }
2456

    
2457
        STRUCT resp = null;
2458

    
2459
        try {
2460
            // System.out.println("ABIERTA: " + (!conn.isClosed()));
2461
            // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2462
            // Object[] old_obj = resp.getAttributes();
2463
            int size = 5;
2464
            Object[] new_obj = new Object[size];
2465

    
2466
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2467
            new_obj[0] = new NUMBER(2003);
2468

    
2469
            if (hasSrid) {
2470
                new_obj[1] = new NUMBER(_oracleSRID);
2471
            }
2472
            else {
2473
                new_obj[1] = null;
2474
            }
2475

    
2476
            new_obj[2] = null;
2477

    
2478
            NUMBER[] elem_info = new NUMBER[3];
2479
            elem_info[0] = new NUMBER(1);
2480
            elem_info[1] = new NUMBER(1003);
2481
            elem_info[2] = new NUMBER(3);
2482
            new_obj[3] = elem_info;
2483

    
2484
            NUMBER[] ords = null;
2485
            ords = new NUMBER[4];
2486
            ords[0] = new NUMBER(c1.getX());
2487
            ords[1] = new NUMBER(c1.getY());
2488
            ords[2] = new NUMBER(c2.getX());
2489
            ords[3] = new NUMBER(c2.getY());
2490
            new_obj[4] = ords;
2491

    
2492
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2493
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2494
                            ((ConnectionJDBC)__conn).getConnection());
2495

    
2496
            resp = new STRUCT(dsc,((ConnectionJDBC)__conn).getConnection(), new_obj);
2497
        }
2498
        catch (Exception ex) {
2499
            logger.error("Error while creating rect struct: " +
2500
                ex.getMessage(), ex);
2501
        }
2502

    
2503
        return resp;
2504
    }
2505

    
2506
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2507
        boolean hasSrid) throws ReadDriverException {
2508
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
2509
        String main_sel = "";
2510

    
2511
        if (fixsql == null) {
2512
            // main_sel = getMainSelect3(var_name);
2513
                String idswhere = getIdsQueryWhereClause(false);
2514
            main_sel = getMainSelect(sdo_intersect, idswhere);
2515
        }
2516
        else {
2517
            main_sel = fixsql;
2518
        }
2519

    
2520
        logger.debug("MAIN SEL = " + main_sel);
2521

    
2522
        ResultSet _rs = null;
2523
        Statement _stmnt = null;
2524
        Object[] _resp = new Object[2];
2525

    
2526
        try {
2527
            _stmnt = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
2528
                    ResultSet.CONCUR_READ_ONLY);
2529
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2530
            _stmnt.setFetchSize(FETCH_SIZE);
2531

    
2532
            _rs = _stmnt.executeQuery(main_sel);
2533

    
2534
            // stmnt.close();
2535
        }
2536
        catch (SQLException se) {
2537
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
2538
                se);
2539
            throw new ReadDriverException(getName(), se);
2540
        }
2541

    
2542
        // this method returns the statement too, so that it can be closed afterwards
2543
        _resp[0] = _rs;
2544
        _resp[1] = _stmnt;
2545

    
2546
        return _resp;
2547
    }
2548

    
2549
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2550
        String resp = "";
2551

    
2552
        try {
2553
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2554
            String mdsys_sdo_ordinate_array = "";
2555
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2556

    
2557
            for (int i = 0; i < vertices.length; i++) {
2558
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2559
                    vertices[i].doubleValue() + ", ";
2560
            }
2561

    
2562
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2563
                    mdsys_sdo_ordinate_array.length() - 2);
2564
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2565
                mdsys_sdo_ordinate_array + ")";
2566

    
2567
            String aux = "";
2568

    
2569
            if (hasSrid) {
2570
                aux = oracleSRID;
2571

    
2572
                if (_isGeogCS) {
2573
                    aux = "0";
2574
                }
2575
            }
2576
            else {
2577
                aux = "null";
2578
            }
2579

    
2580
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
2581
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
2582
                ")";
2583
        }
2584
        catch (Exception ex) {
2585
                logger.error("While getting sdo contructor: " +
2586
                ex.getMessage());
2587
        }
2588

    
2589
        return resp;
2590
    }
2591

    
2592
    private String getIdsQueryWhereClause(boolean with_where) {
2593
                String resp = "";
2594

    
2595
                String _where = "";
2596
                if (with_where) _where = " where ";
2597

    
2598
                if (workingAreaInTablesCSStruct == null) {
2599
                        if (emptyWhereClause) {
2600
                                // return "select rowid from " + getTableName();
2601
                        } else {
2602
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
2603
                                                + ")";
2604
                        }
2605
                } else {
2606
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
2607
                                        oracleSRID, tableHasSrid, isGeogCS);
2608

    
2609
                        if (emptyWhereClause) {
2610
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
2611
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2612
                        } else {
2613
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
2614
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
2615
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2616
                        }
2617
                }
2618

    
2619
                // resp = resp + " order by rowid";
2620
                return resp;
2621
        }
2622

    
2623
    public String getIdAndElemInfoFullResulltSetQuery() {
2624
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
2625
            getTableName() + " c";
2626

    
2627
        resp = resp + getIdsQueryWhereClause(true);
2628
        return resp;
2629
    }
2630

    
2631
    private String getSearchId() {
2632
        if (emptyWhereClause) {
2633
            return "select " + getStandardSelectExpression() + ", c." +
2634
            geoColName + " from " + getTableName() + " c where rowid = ?";
2635
        }
2636
        else {
2637
            return "select " + getStandardSelectExpression() + ", c." +
2638
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
2639
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
2640
        }
2641
    }
2642

    
2643
    public int getShapeType() {
2644
        return shapeType;
2645
    }
2646
    
2647
    public void setShapeType(int t) {
2648
        shapeType = t;
2649
    }
2650
    
2651

    
2652
    private String getWhereClauseWithoutWhere() {
2653
        String resp = "";
2654
        String old = getLyrDef().getWhereClause();
2655
        resp = old;
2656

    
2657
        if (old.length() <= 6) {
2658
            return old;
2659
        }
2660

    
2661
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2662
            resp = resp.substring(6, resp.length());
2663
        }
2664

    
2665
        return resp;
2666
    }
2667

    
2668
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2669
        if (r1.getMaxX() <= r2.getMinX()) {
2670
            return null;
2671
        }
2672

    
2673
        if (r2.getMaxX() <= r1.getMinX()) {
2674
            return null;
2675
        }
2676

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

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

    
2685
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2686
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2687
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2688
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2689

    
2690
        double w = maxx - minx;
2691
        double h = maxy - miny;
2692

    
2693
        return new Rectangle2D.Double(minx, miny, w, h);
2694
    }
2695

    
2696
    private static int maxSizeForFieldType(int _type) {
2697
        switch (_type) {
2698
        case Types.VARCHAR:
2699
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2700

    
2701
        case Types.LONGVARCHAR:
2702
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2703
        }
2704

    
2705
        return -1;
2706
    }
2707

    
2708
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2709
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2710

    
2711
        switch (fieldDesc.getFieldType()) {
2712
        case Types.SMALLINT:
2713
            aux = "NUMBER(5, 0)";
2714

    
2715
            break;
2716

    
2717
        case Types.INTEGER:
2718
            aux = "NUMBER(10, 0)";
2719

    
2720
            break;
2721

    
2722
        case Types.BIGINT:
2723
            aux = "NUMBER(38, 0)";
2724

    
2725
            break;
2726

    
2727
        case Types.BOOLEAN:
2728
            aux = "NUMBER(1, 0)";
2729

    
2730
            break;
2731

    
2732
        case Types.DECIMAL:
2733
            aux = "NUMBER";
2734

    
2735
            break;
2736

    
2737
        case Types.NUMERIC:
2738
            aux = "NUMBER";
2739

    
2740
            break;
2741

    
2742
        case Types.DOUBLE:
2743
            aux = "FLOAT";
2744

    
2745
            break;
2746

    
2747
        case Types.FLOAT:
2748
            aux = "FLOAT";
2749

    
2750
            break;
2751

    
2752
        case Types.CHAR:
2753
            aux = "CHAR(1 BYTE)";
2754

    
2755
            break;
2756

    
2757
        case Types.VARCHAR:
2758
            aux = "NVARCHAR2(" + nvarchar2Limited(fieldDesc.getFieldLength()) + ")";
2759

    
2760
            break;
2761

    
2762
        case Types.LONGVARCHAR:
2763
            aux = "NVARCHAR2(" + nvarchar2Limited(fieldDesc.getFieldLength()) + ")";
2764

    
2765
            break;
2766
        }
2767

    
2768
        return aux;
2769
    }
2770

    
2771
    // -----------------------------------------------------------
2772
    // -----------------------------------------------------------
2773
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2774
        return "DROP TABLE " + dbLayerDef.getTableName() +
2775
        " CASCADE CONSTRAINTS";
2776
    }
2777

    
2778
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2779
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2780

    
2781
        String type = "";
2782
        String name = "";
2783
        String table_name = dbLayerDef.getTableName().toUpperCase();
2784

    
2785
        String resp = "CREATE TABLE " + table_name + " ( ";
2786

    
2787
        for (int i = 0; i < flds.length; i++) {
2788
            name = flds[i].getFieldName();
2789

    
2790
            // -------------- FORBIDDEN FIELD NAMES -----------------
2791
            if (!isOracleAllowedFieldname(name)) {
2792
                continue;
2793
            }
2794

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

    
2806
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2807
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2808
        resp = resp + ", ";
2809

    
2810
        String pk = "CONSTRAINT " + getDerivedNAme(table_name, "PK") +
2811
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD +
2812
            "\") ENABLE";
2813

    
2814
        resp = resp + pk + " )";
2815

    
2816
        return resp;
2817
    }
2818

    
2819
    private static String getDerivedNAme(String tname, String suffix) {
2820

    
2821
            int ind = tname.lastIndexOf(".");
2822
            if (ind == -1) {
2823

    
2824
                    int l = Math.min(28, tname.length());
2825
                    return tname.substring(0, l) + "_" + suffix;
2826

    
2827
            } else {
2828

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

    
2836
    }
2837

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

    
2844
        return resp;
2845
    }
2846

    
2847
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2848

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

    
2857
            } else{
2858
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2859
            " WHERE TABLE_NAME = '" + tname + "'";
2860
            }
2861
    }
2862

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

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

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

    
2894
                if (dim > 3) {
2895
                    dim_name[3] = "T";
2896
                }
2897
            }
2898
        }
2899
        
2900
        double minx = bbox.getMinX();
2901
        double miny = bbox.getMinY();
2902
        double maxx = bbox.getMaxX();
2903
        double maxy = bbox.getMaxY();
2904
        
2905
        /*
2906
        minx = -180;
2907
        maxx = 180;
2908
        miny = -90;
2909
        maxy = 90;
2910
        */
2911
        
2912
        String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " " +
2913
            " ( OWNER, TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
2914
            + "'" + schema + "', "
2915
            + "'" + tName + "', "
2916
            + "'" + DEFAULT_GEO_FIELD + "', " +
2917
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2918
            minx + ", " + maxx + ", " + tolerance + " ), " +
2919
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + miny + ", " +
2920
            maxy + ", " + tolerance + " ))";
2921

    
2922
        if (dim > 2) {
2923
            resp = resp.substring(0, resp.length() - 1) + ",";
2924
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
2925
                "', 0.0, 100.0, " + tolerance + " ))";
2926

    
2927
            if (dim > 3) {
2928
                resp = resp.substring(0, resp.length() - 1) + ",";
2929
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
2930
                    "', 0.0, 100.0, " + tolerance + " ))";
2931
            }
2932
        }
2933

    
2934
        if (withsrid) {
2935
            resp = resp + ", " + _ora_srid + " )";
2936
        }
2937
        else {
2938
            resp = resp + ", NULL )";
2939
        }
2940

    
2941
        return resp;
2942
    }
2943

    
2944
    /**
2945
     * Gets the SQL sentence to perform an insertion.
2946
     *
2947
     * @param feat feature to be added
2948
     * @param dbLayerDef layer definition
2949
     * @param rowInd row index
2950
     * @param _geoColName geometry field name
2951
     * @return the SQL sentence to perform the insertion
2952
     */
2953
    public static String getRowInsertSql(IFeature feat,
2954
        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2955
        String name = "";
2956
        int ftype = -1;
2957
        String aux_orig = "";
2958
        String aux_limited = "";
2959
        String aux_quotes_ok = "";
2960

    
2961
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2962

    
2963
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
2964

    
2965
        for (int i = 0; i < fieldsDescr.length; i++) {
2966
            name = fieldsDescr[i].getFieldName();
2967
            ftype = fieldsDescr[i].getFieldType();
2968

    
2969
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2970
            if (!isOracleAllowedFieldname(name)) continue;
2971
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2972
            // ------------------------------------------------------
2973
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2974
            }
2975
            else {
2976
                name = getValidOracleID(name, i);
2977
                resp = resp + "\"" + name + "\"" + " , ";
2978
            }
2979
        }
2980

    
2981
        resp = resp + _geoColName + " ) VALUES ( ";
2982

    
2983
        for (int i = 0; i < fieldsDescr.length; i++) {
2984
            name = fieldsDescr[i].getFieldName();
2985
            ftype = fieldsDescr[i].getFieldType();
2986

    
2987
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2988
            if (!isOracleAllowedFieldname(name)) continue;
2989
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2990
            // ------------------------------------------------------
2991
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2992

    
2993
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2994
            }
2995
            else {
2996
                if (name.compareToIgnoreCase(
2997
                            OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2998
                    resp = resp + rowInd + " , ";
2999
                }
3000
                else {
3001
                    Value attValue = feat.getAttribute(i);
3002

    
3003
                    if (attValue.toString() == null) {
3004
                        resp = resp + "NULL , ";
3005
                    }
3006
                    else {
3007
                        if (sur.length() > 0) {
3008
                            aux_orig = attValue.toString();
3009
                            aux_limited = cropStringValue(aux_orig, i,
3010
                                    fieldsDescr);
3011
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
3012

    
3013
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
3014
                        }
3015
                        else {
3016
                            String _aux = attValue.toString();
3017

    
3018
                            if (_aux.length() == 0) {
3019
                                _aux = "NULL";
3020
                            }
3021

    
3022
                            resp = resp + _aux + " , ";
3023
                        }
3024
                    }
3025
                }
3026
            }
3027
        }
3028

    
3029
        resp = resp + " ? )";
3030
        /*
3031
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
3032
                        + "2002, NULL, NULL,"
3033
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
3034
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
3035
                        + "), ? )";
3036

3037
        resp = resp + " " + test + " )";
3038
        */
3039
        return resp;
3040
    }
3041

    
3042
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
3043

    
3044
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
3045
                    return true;
3046
            }
3047

    
3048
            if ((ftype == Types.BINARY)
3049
                || (ftype == Types.ARRAY)
3050
                || (ftype == Types.BLOB)
3051
                || (ftype == Types.CLOB)
3052
                || (ftype == Types.STRUCT)
3053
            ) {
3054
                    return false;
3055
            }
3056
                return true;
3057
        }
3058

    
3059
        /**
3060
     * Gets the SQL sentence to perform an update.
3061
     *
3062
     * @param feat feature to be updated
3063
     * @param dbLayerDef layer definition
3064
     * @param rowInd row index
3065
     * @param geoFieldName geometry field name
3066
     * @return the SQL sentence to perform the update
3067
     */
3068
    public static String getRowUpdateSql(IFeature feat,
3069
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
3070
        String name = "";
3071
        String aux_orig = "";
3072
        String aux_limited = "";
3073
        String aux_quotes_ok = "";
3074

    
3075
        Value[] atts = feat.getAttributes();
3076
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
3077

    
3078
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
3079

    
3080
        for (int i = 0; i < _fieldsDescr.length; i++) {
3081
            name = _fieldsDescr[i].getFieldName();
3082

    
3083
            // -------------- FORBIDDEN FIELD NAMES -----------------
3084
            if (!isOracleAllowedFieldname(name)) {
3085
                logger.info("Field: " + name + " will not be updated.");
3086
                continue;
3087
            }
3088

    
3089
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
3090
                        geoFieldName)) {
3091
                logger.info("Field: " + name + " will not be updated (it's a struct).");
3092
                continue;
3093
            }
3094

    
3095
            // ------------------------------------------------------
3096
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
3097
                // resp = resp + "\"" + name + "\"" + " = ?, ";
3098
            }
3099
            else {
3100
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
3101
                aux_orig = atts[i].toString();
3102
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
3103
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
3104
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
3105
                    sur + ", ";
3106
            }
3107
        }
3108

    
3109
        resp = resp + "\"" + geoFieldName + "\" = ?";
3110
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
3111

    
3112
        return resp;
3113
    }
3114

    
3115
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
3116
        String geoname) {
3117
        if (ftype == Types.STRUCT) {
3118
            if (fldname.compareToIgnoreCase(geoname) != 0) {
3119
                return true;
3120
            }
3121
        }
3122

    
3123
        return false;
3124
    }
3125

    
3126
    /**
3127
     * Gets the SQL sentence to perform a deletion.
3128
     *
3129
     * @param dbLayerDef layer definition
3130
     * @param id ROWID of the record to be deleted
3131
     * @return the SQL sentence to perform the deletion
3132
     */
3133
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
3134
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
3135
        resp = resp + " WHERE ROWID ='" + id + "'";
3136

    
3137
        return resp;
3138
    }
3139

    
3140
    private static String cropStringValue(String orig_val, int i,
3141
        FieldDescription[] _flds) {
3142
            
3143
        if (orig_val == null) {
3144
            return "NULL";
3145
        }
3146
        
3147
        if (NumberUtilities.isNumeric(_flds[i].getFieldType())
3148
                    && (orig_val.length() == 0)) {
3149
                    return "NULL";
3150
        }
3151

    
3152
        int tpe = _flds[i].getFieldType();
3153
        int max_size = maxSizeForFieldType(tpe);
3154

    
3155
        if (max_size == -1) {
3156
            return orig_val;
3157
        }
3158

    
3159
        int or_size = orig_val.length();
3160

    
3161
        if (or_size <= max_size) {
3162
            return orig_val;
3163
        }
3164

    
3165
        return orig_val.substring(0, max_size);
3166
    }
3167

    
3168
    private static String avoidQuoteProblem(String str) {
3169
        return str.replaceAll("'", "''");
3170
    }
3171

    
3172
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3173
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3174
            return "";
3175
        }
3176

    
3177
        return "'";
3178
    }
3179

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

    
3190
        // --------------------------------------------
3191
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3192
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3193
        DataSource ds = null;
3194

    
3195
        try {
3196
            ds = LayerFactory.getDataSourceFactory()
3197
                             .executeSQL(sql,
3198
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3199

    
3200
            if (ds.getRowCount() == 0) {
3201
                logger.error("EPSG code not found in table: " + epsg);
3202
                throw new Exception("Unknown EPSG: " + epsg);
3203
            }
3204

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

    
3211
                for (int i = 0; i < ds.getRowCount(); i++) {
3212
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3213

    
3214
                    if (i == 0) {
3215
                        resp = "" + aux;
3216
                    }
3217

    
3218
                    logger.error("" + aux);
3219
                }
3220

    
3221
                logger.error("===============");
3222

    
3223
                return resp;
3224
            }
3225

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

    
3233
        return resp;
3234
    }
3235

    
3236
    /**
3237
     * Utility function to translate a SRS code from Oracle to EPSG.
3238
     * Uses a datasource based on a DBF file.
3239
     *
3240
     * @param ora the Oracle code
3241
     * @return the EPSG code
3242
     */
3243
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3244
            
3245
            if (ora == null) return null;
3246
            
3247
        String resp = "4326";
3248

    
3249
        // --------------------------------------------
3250
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3251
            " where ORACLE = " + ora + ";";
3252
        DataSource ds = null;
3253

    
3254
        try {
3255
            ds = LayerFactory.getDataSourceFactory()
3256
                             .executeSQL(sql,
3257
                    DataSourceFactory.AUTOMATIC_OPENING);
3258

    
3259
            if (ds.getRowCount() == 0) {
3260
                logger.error("Oracle Spatial code not found in table: " + ora);
3261
                throw new Exception("Unknown Oracle code: " + ora);
3262
            }
3263

    
3264
            if (ds.getRowCount() > 1) {
3265
                logger.error("===============");
3266
                logger.error(
3267
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3268
                    ora);
3269

    
3270
                for (int i = 0; i < ds.getRowCount(); i++) {
3271
                    String aux = "" +
3272
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3273

    
3274
                    if (i == 0) {
3275
                        resp = aux;
3276
                    }
3277

    
3278
                    logger.error("" + aux);
3279
                }
3280

    
3281
                logger.error("===============");
3282

    
3283
                return resp;
3284
            }
3285

    
3286
            resp = "" +
3287
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3288
        }
3289
        catch (Exception pe) {
3290
            logger.error("Error with SQL statement. " + pe.getMessage());
3291
        }
3292

    
3293
        return resp;
3294
    }
3295

    
3296
    /**
3297
     * This methos creates the datasource used to translate the SRS codes:
3298
     * EPSG <--> Oracle.
3299
     *
3300
     * It's called from several places, so checks that the datasource does not exist.
3301
     */
3302

    
3303

    
3304
    /**
3305
     * Utility method to get a valid Oracle identifier (in terms of length)
3306
     *
3307
     * @param str Proposed string
3308
     * @param ind field index of the given field name (used by the method to
3309
     * improve the renaming)
3310
     * @return an acceptable oracle identifier.
3311
     */
3312
    public static String getValidOracleID(String _str, int ind) {
3313
            
3314
            String str = _str.toUpperCase();
3315
            
3316
        if (str.length() <= MAX_ID_LENGTH) {
3317
            return str;
3318
        }
3319

    
3320
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3321
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3322
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3323
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3324
        resp = resp + "_" + (ind % 1000);
3325

    
3326
        return resp;
3327
    }
3328

    
3329
    private static ArrayList ensureSensibleShell(ArrayList cc) {
3330
        if (sameCoordinate((Coordinate) cc.get(0),
3331
                    (Coordinate) cc.get(cc.size() - 1))) {
3332
            if (cc.size() == 2) {
3333
                ArrayList resp = new ArrayList();
3334
                resp.add(cc.get(0));
3335

    
3336
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3337
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3338
                resp.add(newcoo);
3339

    
3340
                newcoo = new Coordinate((Coordinate) cc.get(0));
3341
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3342
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
3343
                resp.add(newcoo);
3344

    
3345
                resp.add(cc.get(0));
3346

    
3347
                return resp;
3348
            }
3349

    
3350
            if (cc.size() == 3) {
3351
                cc.remove(1);
3352

    
3353
                return ensureSensibleShell(cc);
3354
            }
3355

    
3356
            return cc;
3357
        }
3358
        else {
3359
            cc.add(cc.get(0));
3360

    
3361
            return cc;
3362
        }
3363
    }
3364

    
3365
    private static ArrayList ensureSensibleHole(ArrayList cc) {
3366
        if (sameCoordinate((Coordinate) cc.get(0),
3367
                    (Coordinate) cc.get(cc.size() - 1))) {
3368
            if (cc.size() == 2) {
3369
                ArrayList resp = new ArrayList();
3370
                resp.add(cc.get(0));
3371

    
3372
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3373
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3374
                resp.add(newcoo);
3375

    
3376
                newcoo = new Coordinate((Coordinate) cc.get(0));
3377
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3378
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3379
                resp.add(newcoo);
3380

    
3381
                resp.add(cc.get(0));
3382

    
3383
                return resp;
3384
            }
3385

    
3386
            if (cc.size() == 3) {
3387
                cc.remove(1);
3388

    
3389
                return ensureSensibleHole(cc);
3390
            }
3391

    
3392
            return cc;
3393
        }
3394
        else {
3395
            cc.add(cc.get(0));
3396

    
3397
            return cc;
3398
        }
3399
    }
3400

    
3401
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
3402
        if (cc.size() == 2) {
3403
            if (sameCoordinate((Coordinate) cc.get(0),
3404
                        (Coordinate) cc.get(cc.size() - 1))) {
3405
                ArrayList resp = new ArrayList();
3406
                resp.add(cc.get(0));
3407

    
3408
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3409
                newc.x = newc.x + IRRELEVANT_DISTANCE;
3410
                resp.add(newc);
3411

    
3412
                return resp;
3413
            }
3414
        }
3415

    
3416
        return cc;
3417
    }
3418

    
3419
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3420
        if (c1.x != c2.x) {
3421
            return false;
3422
        }
3423

    
3424
        if (c1.y != c2.y) {
3425
            return false;
3426
        }
3427

    
3428
        return true;
3429
    }
3430

    
3431
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3432
        if (cc.size() == 2) {
3433
            return null;
3434
        }
3435

    
3436
        if (cc.size() == 3) {
3437
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3438
                return null;
3439
            }
3440

    
3441
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3442
                return null;
3443
            }
3444

    
3445
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3446
                return null;
3447
            }
3448

    
3449
            cc.add(cc.get(0));
3450

    
3451
            return cc;
3452
        }
3453

    
3454
        if (!sameCoordinate((Coordinate) cc.get(0),
3455
                    (Coordinate) cc.get(cc.size() - 1))) {
3456
            cc.add(cc.get(0));
3457
        }
3458

    
3459
        return cc;
3460
    }
3461

    
3462
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3463
        Coordinate[] p = new Coordinate[4];
3464
        p[0] = c;
3465

    
3466
        Coordinate nc = new Coordinate(c);
3467
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3468

    
3469
        Coordinate nc2 = new Coordinate(nc);
3470
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3471
        p[1] = nc;
3472
        p[2] = nc2;
3473
        p[3] = new Coordinate(c);
3474

    
3475
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3476
        LinearRing ls = new LinearRing(cs, geomFactory);
3477
        Polygon po = new Polygon(ls, null, geomFactory);
3478
        Polygon[] pos = new Polygon[1];
3479
        pos[0] = po;
3480

    
3481
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3482

    
3483
        return mpo;
3484
    }
3485

    
3486
    public String getSourceProjection(IConnection conn, DBLayerDefinition lyrDef) {
3487
            
3488
            String resp = null;
3489
        try {
3490
            Statement _st = ((ConnectionJDBC) conn).getConnection().createStatement();
3491
            String[] tokens = lyrDef.getName().split("\\u002E", 2);
3492
            String qry;
3493
            if (tokens.length > 1) {
3494
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3495
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
3496
                tokens[1] + "'";
3497
            } else {
3498
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3499
                " where TABLE_NAME = " + "'" + lyrDef.getName() + "'";
3500
            }
3501
            ResultSet _rs = _st.executeQuery(qry);
3502

    
3503
            if (_rs.next()) {
3504
                String aux = getOracleSridFromCurrentRecord(_rs);
3505
                try {
3506
                                        resp = oracleSridToEpsgSrid(aux);
3507
                                } catch (Exception e) {
3508
                                        logger.error("Unknown oracle SRID: " + aux);
3509
                                }
3510
            } else {
3511
                    
3512
            }
3513
        } catch (Exception ex) {
3514
                logger.error("While getting Source Projection: " + ex.getMessage());
3515
        }
3516
        
3517
        if (resp != null) {
3518
                return resp;
3519
        } else {
3520
                return getDestProjection();
3521
        }
3522
        
3523
    }
3524

    
3525
    public String getDestProjection() {
3526
        return destProj;
3527
    }
3528

    
3529
    public void setDestProjection(String toEPSG) {
3530
        destProj = toEPSG;
3531
        try {
3532
                        destProjOracle = epsgSridToOracleSrid(destProj);
3533
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3534

    
3535
                } catch (Exception e) {
3536
                        logger.error("Unknown EPSG code: " + destProj);
3537
                        destProjOracle = oracleSRID;
3538
                        isDestGeogCS = false;
3539
                }
3540

    
3541
    }
3542

    
3543
    public String getDestProjectionOracleCode() {
3544
            return destProjOracle;
3545
    }
3546

    
3547
    public boolean getIsDestProjectionGeog() {
3548
            return isDestGeogCS;
3549
    }
3550

    
3551
    public boolean canReproject(String toEPSGdestinyProjection) {
3552
        return false;
3553
    }
3554

    
3555
    /**
3556
     * Utility function. Says whether a given field name can be a user field name
3557
     * or not (for example, "ROWID" is not a valid one because it's a system
3558
     * reserved word).
3559
     *
3560
     * @param str proposed firld name
3561
     * @return whether it is valid or not for Oracle databases
3562
     */
3563
    private static boolean isOracleAllowedFieldname(String str) {
3564
        if (str.compareToIgnoreCase("rowid") == 0) {
3565
            return false;
3566
        }
3567

    
3568
        if (str.compareToIgnoreCase("rownum") == 0) {
3569
            return false;
3570
        }
3571

    
3572
        return true;
3573
    }
3574

    
3575
    public Hashtable getHashRelate() {
3576
        return hashRelate;
3577
    }
3578

    
3579
    public void setHashRelate(Hashtable m) {
3580
        hashRelate = m;
3581
    }
3582

    
3583
    public void setNumReg(int n) {
3584
        numReg = n;
3585
    }
3586

    
3587
    private int[] getRandomSample(int maxn_one_based, int n) {
3588
        int[] resp = new int[n];
3589

    
3590
        if (maxn_one_based <= n) {
3591
            resp = new int[maxn_one_based];
3592

    
3593
            for (int i = 0; i < maxn_one_based; i++) {
3594
                resp[i] = i;
3595
            }
3596
        }
3597
        else {
3598
            Random rnd = new Random();
3599

    
3600
            for (int i = 0; i < n; i++) {
3601
                resp[i] = rnd.nextInt(maxn_one_based);
3602
            }
3603
        }
3604

    
3605
        return resp;
3606
    }
3607

    
3608
    private String getRowIdRestrictionCondition(int nrecords) {
3609
        int[] zero_based_rows = getRandomSample(nrecords,
3610
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3611
        String resp = "(";
3612
        Object aux = "";
3613
        ROWID riaux = null;
3614

    
3615
        for (int i = 0; i < zero_based_rows.length; i++) {
3616
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3617
            riaux = (ROWID) aux;
3618
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3619
        }
3620

    
3621
        resp = resp.substring(0, resp.length() - 4);
3622
        resp = resp + ")";
3623

    
3624
        return resp;
3625
    }
3626

    
3627
    private Rectangle2D getBoundingFromSample(int n_max) {
3628
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3629
            " WHERE " + getRowIdRestrictionCondition(n_max);
3630
        STRUCT auxstr = null;
3631
        IGeometry theGeom = null;
3632
        Rectangle2D resp = null;
3633

    
3634
        try {
3635
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3636
            ResultSet rs = st.executeQuery(_qry);
3637

    
3638
            if (rs.next()) {
3639
                auxstr = (STRUCT) rs.getObject(1);
3640

    
3641
                if (auxstr != null) {
3642
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3643

    
3644
                    if (resp == null) {
3645
                        resp = theGeom.getBounds2D();
3646
                    }
3647
                    else {
3648
                        resp.add(theGeom.getBounds2D());
3649
                    }
3650
                }
3651

    
3652
                while (rs.next()) {
3653
                    auxstr = (STRUCT) rs.getObject(1);
3654

    
3655
                    if (auxstr != null) {
3656
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3657

    
3658
                        if (resp == null) {
3659
                            resp = theGeom.getBounds2D();
3660
                        }
3661
                        else {
3662
                            resp.add(theGeom.getBounds2D());
3663
                        }
3664
                    }
3665
                }
3666

    
3667
                rs.close();
3668
                st.close();
3669
            }
3670
            else {
3671
                throw new SQLException("Empty resultset from this query: " +
3672
                    _qry);
3673
            }
3674
        }
3675
        catch (SQLException se) {
3676
                logger.error("While getting sample full extent: " +
3677
                se.getMessage());
3678
        }
3679

    
3680
        if (resp == null) {
3681
            logger.warn(
3682
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3683

    
3684
            return new Rectangle2D.Double(-180, -90, 360, 180);
3685
        }
3686

    
3687
        return resp;
3688
    }
3689

    
3690
    /**
3691
     * Does what it says, puts the LinearRing in counter clock wise
3692
     * order.
3693
     * @param ls The ring to set.
3694
     * @param gf a GeometryFactory object
3695
     * @return A new ring in CCW order.
3696
     *
3697
     */
3698
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3699
        Coordinate[] cc = ls.getCoordinates();
3700

    
3701
        if (CGAlgorithms.isCCW(cc)) {
3702
            return gf.createLinearRing(cc);
3703
        }
3704
        else {
3705
            if (ls instanceof LinearRing) {
3706
                return reverseRing((LinearRing) ls, gf);
3707
            }
3708
            else {
3709
                return reverseLineString(ls, gf);
3710
            }
3711
        }
3712
    }
3713

    
3714
    /**
3715
     * Does what it says, reverses the order of the Coordinates in the ring.
3716
     * @param lr The ring to reverse.
3717
     * @return A new ring with the reversed Coordinates.
3718
     *
3719
     */
3720
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3721
        int numPoints = lr.getNumPoints() - 1;
3722
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3723

    
3724
        for (int t = numPoints; t >= 0; t--) {
3725
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3726
        }
3727

    
3728
        return gf.createLinearRing(newCoords);
3729
    }
3730

    
3731
    /**
3732
     * Does what it says, reverses the order of the Coordinates in the linestring.
3733
     * @param ls The ls to reverse.
3734
     * @param gf a GeometryFactory object
3735
     * @return A new ls with the reversed Coordinates.
3736
     *
3737
     */
3738
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3739
        int numPoints = ls.getNumPoints() - 1;
3740
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3741

    
3742
        for (int t = numPoints; t >= 0; t--) {
3743
            newCoords[t] = ls.getCoordinateN(numPoints - t);
3744
        }
3745

    
3746
        return gf.createLinearRing(newCoords);
3747
    }
3748

    
3749
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3750
        if (ge instanceof MultiPolygon) {
3751
            MultiPolygon mp = (MultiPolygon) ge;
3752
            int size = ge.getNumGeometries();
3753
            Polygon[] pols = new Polygon[size];
3754

    
3755
            for (int i = 0; i < size; i++)
3756
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3757
                        gf);
3758

    
3759
            return new MultiPolygon(pols, gf);
3760
        }
3761
        else {
3762
            if (ge instanceof Polygon) {
3763
                Polygon p = (Polygon) ge;
3764
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3765
                int nholes = p.getNumInteriorRing();
3766

    
3767
                if (nholes > 0) {
3768
                    LinearRing[] holes = new LinearRing[nholes];
3769

    
3770
                    for (int i = 0; i < nholes; i++) {
3771
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3772
                    }
3773

    
3774
                    return gf.createPolygon(exterior, holes);
3775
                }
3776
                else {
3777
                    return gf.createPolygon(exterior, null);
3778
                }
3779
            }
3780
            else {
3781
                return ge;
3782
            }
3783
        }
3784
    }
3785

    
3786
    /**
3787
     * Converts from IGeometry to STRUCT
3788
     *
3789
     * @param ig the geometry to convert
3790
     * @param _forced_type forced type to use
3791
     * @param _conn connection
3792
     * @param _o_srid  SRS (oracle code)
3793
     * @param withSrid whether this STRUCT has a non-NULL SRS
3794
     * @param agu_bien whether or not to check the correctness of the holes
3795
     * @param _isGeoCS whether the SRS is geodetic or not
3796
     * @return the generated STRUCT
3797
     */
3798
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
3799
        IConnection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
3800
        boolean _isGeoCS) {
3801
        if (ig instanceof FGeometryCollection) {
3802
            FGeometryCollection coll = (FGeometryCollection) ig;
3803

    
3804
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3805
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3806

    
3807
            // logger.error("Collections no soportadas por ahora.");
3808
            // return null;
3809
        }
3810
        else {
3811
            Shape shp = ig.getInternalShape();
3812

    
3813
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3814
                agu_bien, false, _isGeoCS);
3815
        }
3816
    }
3817

    
3818
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3819
        boolean agu_bien, boolean isView) {
3820

    
3821
            if (shp == null) return null;
3822
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3823
            agu_bien, isView, isGeogCS);
3824
    }
3825

    
3826
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3827
        IConnection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3828
        boolean isView, boolean _isGeoCS) {
3829
        int _srid = -1;
3830

    
3831
        if ((o_srid != null) && (o_srid.length() > 0)) {
3832
            _srid = Integer.parseInt(o_srid);
3833
        }
3834

    
3835
        if (shp == null) {
3836
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3837

    
3838
            return null;
3839
        }
3840

    
3841
        if (shp instanceof Rectangle2D) {
3842
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3843
                _isGeoCS, o_srid, _conn);
3844
        }
3845

    
3846
        try {
3847
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3848
                    _srid, agu_bien, hasSrid);
3849

    
3850
            return the_struct;
3851
        }
3852
        catch (SQLException ex) {
3853
            logger.error("While creating STRUCT: " + ex.getMessage());
3854

    
3855
            return null;
3856
        }
3857
    }
3858

    
3859
    // -------------------------- not ready yet ----------------
3860
    public int getRowIndexByFID(IFeature _fid) {
3861
        if (isNotAvailableYet) {
3862
            return -1;
3863
        }
3864
        else {
3865
            return super.getRowIndexByFID(_fid);
3866
        }
3867
    }
3868

    
3869
    public int getShapeCount() throws ReadDriverException { 
3870
        if (isNotAvailableYet) {
3871
            return 0;
3872
        }
3873
        else {
3874
            return numReg;
3875
        }
3876
    }
3877

    
3878
    public void setNotAvailableYet(boolean nav) {
3879
        isNotAvailableYet = nav;
3880
    }
3881

    
3882
    // -------------------------------------------------------
3883
    // -------------------------------------------------------
3884
    public String[] getTableNames(IConnection conn, String catalog)
3885
        throws DBException {
3886
        try{
3887
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
3888
        String[] types = { "TABLE", "VIEW" };
3889
        // String[] types = { "VIEW" };
3890

    
3891
        ResultSet rs = null;
3892
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3893
                    ORACLE_GEOMETADATA_VIEW, types), ((ConnectionJDBC)conn).getConnection());
3894
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3895
//                          ORACLE_GEOMETADATA_VIEW, types);
3896
        TreeMap ret = new TreeMap();
3897

    
3898
        while (rs.next()) {
3899
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
3900
            ret.put(nomCompleto, nomCompleto);
3901
        }
3902

    
3903
        return (String[]) ret.keySet().toArray(new String[0]);
3904
        }catch (SQLException e) {
3905
                        throw new DBException(e);
3906
                }
3907
    }
3908

    
3909
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3910
        throws SQLException {
3911
        String tablename = "";
3912

    
3913

    
3914

    
3915
        if (res.next()) {
3916
            tablename = res.getString("TABLE_NAME");
3917

    
3918
            // debug
3919
            writeMetaTableToLog(con, tablename);
3920

    
3921
            Statement __st = con.createStatement();
3922

    
3923
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3924
                "union (select VIEW_NAME from USER_VIEWS)) " +
3925
                "intersect (select TABLE_NAME from " + tablename + ")";
3926
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
3927
            ResultSet rs = __st.executeQuery(sql);
3928

    
3929
            return rs;
3930
        }
3931
        else {
3932
            logger.error("Error while getting geometry tables.");
3933

    
3934
            return null;
3935
        }
3936
    }
3937

    
3938
    private void writeMetaTableToLog(Connection con, String tname) {
3939

    
3940
            logger.debug("======================================================");
3941
            logger.debug("=     " + ORACLE_GEOMETADATA_VIEW + "     =====================");
3942
            logger.debug("======================================================");
3943

    
3944
            try {
3945
            Statement _stmt = con.createStatement();
3946
            String sql = "SELECT * FROM " + tname;
3947
            ResultSet res = _stmt.executeQuery(sql);
3948
            while (res.next()) {
3949
                    logger.debug(
3950
                                    "OWNER: " + res.getString("OWNER")
3951
                                    + ", TABLE_NAME: " + res.getString("TABLE_NAME")
3952
                                    + ", COLUMN_NAME: " + res.getString("COLUMN_NAME")
3953
                                    + ", SRID: " + res.getString("SRID"));
3954
                    ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3955
                    String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3956
                    logger.debug("DIMINFO: " + dinfo);
3957
                    logger.debug("=========");
3958
            }
3959
            } catch (Throwable th) {
3960

    
3961
            }
3962

    
3963

    
3964

    
3965

    
3966

    
3967
                // TODO Auto-generated method stub
3968

    
3969
        }
3970

    
3971
        /**
3972
     * Gets the field names that can act as row id (always ROWID)
3973
     */
3974
    public String[] getIdFieldsCandidates(IConnection conn, String table_name)
3975
        throws DBException {
3976
            try{
3977
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
3978
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3979
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3980
            _rs.close();
3981
            _st.close();
3982

    
3983
            String[] resp = { "ROWID" };
3984
        return resp;
3985
            }catch (SQLException e) {
3986
                        throw new DBException(e);
3987
                }
3988
    }
3989

    
3990
    /**
3991
     * Gets the field names that can act as geometry fields
3992
     * (queries the user's geographic metadata).
3993
     */
3994
    public String[] getGeometryFieldsCandidates(IConnection conn,
3995
        String table_name) throws DBException {
3996
            try{
3997
        Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3998
        String[] tokens = table_name.split("\\u002E", 2);
3999
        String qry;
4000
        if (tokens.length > 1)
4001
        {
4002
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
4003
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
4004
            tokens[1] + "'";
4005
        }
4006
        else
4007
        {
4008
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
4009
            " where TABLE_NAME = " + "'" + table_name + "'";
4010

    
4011
        }
4012
        ResultSet _rs = _st.executeQuery(qry);
4013

    
4014
        ArrayList aux = new ArrayList();
4015

    
4016
        while (_rs.next()) {
4017
            String _geo = _rs.getString("COLUMN_NAME");
4018
            aux.add(_geo);
4019
        }
4020

    
4021
        _rs.close();
4022
        _st.close();
4023

    
4024
        String[] resp = (String[]) aux.toArray(new String[0]);
4025

    
4026
        return checkIndexes(conn, resp, table_name);
4027
            }catch (SQLException e) {
4028
                        throw new DBException(e);
4029
                }
4030
    }
4031

    
4032
    private String[] checkIndexes(IConnection c, String[] all, String long_table_name) throws DBException {
4033

    
4034
            ArrayList good_ones = new ArrayList();
4035
            try{
4036
            String t = long_table_name;
4037
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
4038

    
4039
            for (int i=0; i<all.length; i++) {
4040

    
4041
                String qry = "SELECT SRID, DIMINFO FROM " + ORACLE_GEOMETADATA_VIEW +
4042
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
4043
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
4044

    
4045
                Statement _st = ((ConnectionJDBC)c).getConnection().createStatement();
4046
                ResultSet _rs = _st.executeQuery(qry);
4047
                if (_rs.next()) {
4048
                        String _srid = toString((BigDecimal) _rs.getObject(1));
4049
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
4050
                        int len = diminfo.getOracleArray().length;
4051
                        if (allowsGeoQueries(((ConnectionJDBC)c).getConnection(), long_table_name, all[i], _srid, len)) {
4052
                                good_ones.add(all[i]);
4053
                        }
4054
                }
4055
                _rs.close();
4056
                _st.close();
4057
            }
4058

    
4059
            if (good_ones.size() == 0) {
4060
                    throw new SQLException("no_indexes_on_declared_geo_fields");
4061
            }
4062
            }catch (SQLException e) {
4063
                        throw new DBException(e);
4064
                }
4065
            return (String[]) good_ones.toArray(new String[0]);
4066
    }
4067

    
4068
    private String toString(BigDecimal number) {
4069

    
4070
            if (number == null) return "NULL";
4071
            return "" + number.intValue();
4072
        }
4073

    
4074
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
4075
            String p = getPointConstructor(dims, _srid);
4076
            String qry = "SELECT * FROM " + _t.toUpperCase() + " WHERE (ROWNUM = 1)";
4077
            qry = "SELECT * FROM (" + qry + ") WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'";
4078

    
4079
            try {
4080
                        Statement _st = c.createStatement();
4081
                        ResultSet _rs = _st.executeQuery(qry);
4082
                        _rs.close();
4083
                        _st.close();
4084
                } catch (Exception ex) {
4085
                        return false;
4086
                }
4087
                return true;
4088
        }
4089

    
4090
        private String getPointConstructor(int dims, String _srid) {
4091

    
4092
                String coord = "";
4093
                for (int i=0; i<dims; i++) coord = coord + "0, ";
4094
                coord = coord.substring(0, coord.length() - 2);
4095

    
4096
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
4097
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
4098
        }
4099

    
4100
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
4101

    
4102
            if (l == null) return false;
4103
            if (str == null) return false;
4104

    
4105
            String item = "";
4106
            for (int i=0; i<l.size(); i++) {
4107
                    if (l.get(i) instanceof String) {
4108
                            item = (String) l.get(i);
4109
                            if (item.compareToIgnoreCase(str) == 0) return true;
4110
                    }
4111
            }
4112
            return false;
4113
    }
4114

    
4115
        /**
4116
     * Utility method to check if a given table is empty.
4117
     */
4118
    public boolean isEmptyTable(Connection conn, String tableName) {
4119
        boolean res = true;
4120

    
4121
        try {
4122
            Statement st = conn.createStatement();
4123
            ResultSet rs = null;
4124
            rs = st.executeQuery("select * from " + tableName +
4125
                    " where rownum = 1");
4126
            res = !rs.next();
4127
            rs.close();
4128
            st.close();
4129
        }
4130
        catch (Exception ex) {
4131
            res = true;
4132
        }
4133

    
4134
        return res;
4135
    }
4136

    
4137
    /**
4138
     * Gets all the fields from a table name.
4139
     */
4140
    public String[] getAllFields(IConnection conn, String table_name)
4141
        throws DBException {
4142
            try{
4143
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
4144
        ResultSet rs = st.executeQuery("select * from " + table_name +
4145
                " where rownum = 1");
4146
        ResultSetMetaData rsmd = rs.getMetaData();
4147
        String[] ret = new String[rsmd.getColumnCount()];
4148

    
4149
        for (int i = 0; i < ret.length; i++) {
4150
            ret[i] = rsmd.getColumnName(i + 1);
4151
        }
4152

    
4153
        rs.close();
4154
        st.close();
4155

    
4156
        return ret;
4157
            }catch (SQLException e) {
4158
                        throw new DBException(e);
4159
                }
4160
    }
4161

    
4162
    /**
4163
     * Gets all field type names from a table.
4164
     */
4165
    public String[] getAllFieldTypeNames(IConnection conn, String table_name)
4166
        throws DBException {
4167
            try{
4168
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
4169
        ResultSet rs = st.executeQuery("select * from " + table_name +
4170
                " where rownum = 1");
4171
        ResultSetMetaData rsmd = rs.getMetaData();
4172
        String[] ret = new String[rsmd.getColumnCount()];
4173

    
4174
        for (int i = 0; i < ret.length; i++) {
4175
            ret[i] = rsmd.getColumnTypeName(i + 1);
4176
        }
4177

    
4178
        rs.close();
4179
        st.close();
4180

    
4181
        close();
4182

    
4183
        return ret;
4184
            }catch (SQLException e) {
4185
                        throw new DBException(e);
4186
                }
4187
    }
4188

    
4189
    /**
4190
     * Gets Oracle's specific connection string for the given parameters.
4191
     */
4192
    public String getConnectionString(String host, String port, String dbname,
4193
        String user, String pw) {
4194
        String _pw = pw;
4195

    
4196
        if (_pw == null) {
4197
            _pw = "null";
4198
        }
4199

    
4200
        String fullstr = CONN_STR_BEGIN;
4201
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
4202
        fullstr = fullstr + "@" + host.toLowerCase();
4203
        fullstr = fullstr + ":" + port;
4204
        fullstr = fullstr + ":" + dbname.toLowerCase();
4205

    
4206
        return fullstr;
4207
    }
4208

    
4209
    /**
4210
     * Gets the Pracle geometries writer associated with this driver.
4211
     */
4212
    public IWriter getWriter() {
4213
        // on(VectorialEditableDBAdapter.java:290)
4214
        if (writer == null) {
4215

    
4216
                long count = 0;
4217
                        try {
4218
                                count = getRowCount();
4219
                        } catch (ReadDriverException e1) {
4220
                                logger.error("While getting row count: " + e1.getMessage());
4221
                        }
4222
                
4223
            writer = new OracleSpatialWriter(count);
4224
            writer.setDriver(this);
4225
            writer.setLyrShapeType(getShapeType());
4226
            writer.setGeoCS(isGeogCS());
4227
            writer.setGeoColName(geoColName);
4228
            writer.setSRID(oracleSRID);
4229

    
4230
            try {
4231
                writer.initialize(getLyrDef());
4232
            } catch (InitializeWriterException e) {
4233
                logger.error("While initializing OS Writer: " + e.getMessage(), e);
4234
            }
4235

    
4236
            writer.setStoreWithSrid(tableHasSrid);
4237
        }
4238

    
4239
        return writer;
4240
    }
4241

    
4242
    /**
4243
     * Tells whether the SRS is geodetic or not
4244
     * @return whether the SRS is geodetic or not
4245
     */
4246
    public boolean isGeogCS() {
4247
        return isGeogCS;
4248
    }
4249

    
4250
    /**
4251
     * Adds a row id to the inner set od IDs.
4252
     * @param id
4253
     */
4254
    public void addRow(String id) {
4255
        Value aux = ValueFactory.createValue(id);
4256
        Integer intobj = new Integer(numReg);
4257
        hashRelate.put(aux, intobj);
4258
        rowToId.put(intobj, id);
4259

    
4260
        numReg++;
4261
    }
4262

    
4263
    /**
4264
     * Removes a row id to the inner set od IDs.
4265
     * @param id
4266
     */
4267
    public void deleteRow(String id) {
4268
        Value aux = ValueFactory.createValue(id);
4269
        Integer intobj = (Integer) hashRelate.get(aux);
4270
        hashRelate.remove(aux);
4271
        rowToId.remove(intobj);
4272

    
4273
        numReg--;
4274
    }
4275

    
4276
    private String getStandardSelectExpression() {
4277
        if (standardSelectExpressionFalse == null) {
4278
            standardSelectExpressionFalse = "";
4279

    
4280
            String[] flds = getLyrDef().getFieldNames();
4281
            int size = flds.length;
4282

    
4283
            for (int i = 0; i < size; i++) {
4284
                if (i > 0) {
4285
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4286
                        "c.\"" + flds[i] + "\", ";
4287
                }
4288
                else {
4289
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4290
                        flds[i] + ", ";
4291
                }
4292
            }
4293

    
4294
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4295
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4296
                    standardSelectExpressionFalse.length() - 2);
4297
        }
4298

    
4299
        return standardSelectExpressionFalse;
4300
    }
4301

    
4302
    /**
4303
     * Allows the method to decide what to do with the geometry field name
4304
     * (remove/add it from the user selected fields).
4305
     *
4306
     * @param flds
4307
     * @param geof
4308
     * @return the possibly modified field names
4309
     */
4310
    public String[] manageGeometryField(String[] flds, String geof) {
4311
        return addEndIfNotContained(flds, geof);
4312
    }
4313

    
4314
    /**
4315
     * Allows the method to decide what to do with the ID field name
4316
     * (remove/add it from the user selected fields).
4317
     *
4318
     * @param flds
4319
     * @param idf
4320
     * @return the possibly modified field names
4321
     */
4322
    public String[] manageIdField(String[] flds, String idf) {
4323
        return addStartIfNotContained(flds, idf);
4324
    }
4325

    
4326
    private String[] addEndIfNotContained(String[] arr, String item) {
4327
        if (contains(arr, item)) {
4328
            return arr;
4329
        }
4330
        else {
4331
            int size = arr.length;
4332
            String[] resp = new String[size + 1];
4333

    
4334
            for (int i = 0; i < size; i++) {
4335
                resp[i] = arr[i];
4336
            }
4337

    
4338
            resp[size] = item;
4339

    
4340
            return resp;
4341
        }
4342
    }
4343

    
4344
    private String[] addStartIfNotContained(String[] arr, String item) {
4345
        if (contains(arr, item)) {
4346
            return arr;
4347
        }
4348
        else {
4349
            int size = arr.length;
4350
            String[] resp = new String[size + 1];
4351

    
4352
            for (int i = 1; i <= size; i++) {
4353
                resp[i] = arr[i];
4354
            }
4355

    
4356
            resp[0] = item;
4357

    
4358
            return resp;
4359
        }
4360
    }
4361

    
4362
    private boolean contains(String[] arr, String item) {
4363
        for (int i = 0; i < arr.length; i++) {
4364
            if (arr[i].compareTo(item) == 0) {
4365
                return true;
4366
            }
4367
        }
4368

    
4369
        return false;
4370
    }
4371

    
4372
    /**
4373
     * This method is called when the user removes the layer from the view.
4374
     * If the IDs were being loaded, the driver will check this field and will
4375
     * let the thread 'die' quietly.
4376
     *
4377
     */
4378
    public void remove() {
4379
        cancelIDLoad = true;
4380
    }
4381

    
4382
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4383
            // if (!isgeodetic) return true;
4384
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true;
4385
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true;
4386
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true;
4387
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true;
4388
            return false;
4389
    }
4390

    
4391
    private Rectangle2D getFastEstimatedExtent(
4392
                    String tname,
4393
                    String gfield,
4394
                    IConnection c,
4395
                    int sample_size,
4396
                    double enlargement,
4397
                    boolean is_geo) {
4398

    
4399
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4400
            Rectangle2D resp_aux = null;
4401
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4402
            ResultSet _rs = null;
4403

    
4404
            try {
4405
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
4406
                        _rs = _st.executeQuery();
4407
                        while (_rs.next()) {
4408
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4409
                                IGeometry ig = getGeometryUsing(aux, false);
4410

    
4411
                                if (ig == null) continue;
4412

    
4413
                                if (resp_aux == null) {
4414
                                        resp_aux = ig.getBounds2D();
4415
                                } else {
4416
                                        resp_aux.add(ig.getBounds2D());
4417
                                }
4418

    
4419
                        }
4420
                } catch (Exception ex) {
4421
                        logger.error("While getting random sample: " + ex.getMessage());
4422
                }
4423

    
4424
                if (resp_aux == null) {
4425
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
4426
                        return world;
4427
                }
4428
                
4429
                double w = resp_aux.getWidth();
4430
                double h = resp_aux.getHeight();
4431
                double x = resp_aux.getMinX();
4432
                double y = resp_aux.getMinY();
4433

    
4434
                // enlarge n times:
4435
                double newx = x - (0.5 * (enlargement - 1)) * w;
4436
                double newy = y - (0.5 * (enlargement - 1)) * h;
4437
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4438
                                enlargement * w,
4439
                                enlargement * h);
4440

    
4441
                if (is_geo) {
4442
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4443
                        logger.debug("FAST BB: " + resp_aux.toString());
4444
                        return resp_aux;
4445
                } else {
4446
                        logger.debug("FAST BB: " + resp_aux_large.toString());
4447
                        return resp_aux_large;
4448
                }
4449

    
4450
    }
4451

    
4452
    private Rectangle2D getEstimatedExtent(
4453
                    String tname,
4454
                    String gfield,
4455
                    IConnection c,
4456
                    int sample_size,
4457
                    double enlargement,
4458
                    boolean is_geo) {
4459

    
4460
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4461

    
4462
            ArrayList ids = new ArrayList();
4463
            int _rnd_index = 0;
4464
            ROWID _id = null;
4465
            Random rnd = new Random(System.currentTimeMillis());
4466

    
4467
            for (int i=0; i<sample_size; i++) {
4468
                    _rnd_index = rnd.nextInt(numReg);
4469
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
4470
                    ids.add(_id.stringValue());
4471
            }
4472

    
4473
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
4474
            for (int i=0; i<ids.size(); i++) {
4475
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR ";
4476
            }
4477
            qry = qry.substring(0, qry.length() - 4) + ")";
4478

    
4479
            Rectangle2D resp_aux = null;
4480
            ResultSet _rs = null;
4481

    
4482
            try {
4483
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
4484
                        _rs = _st.executeQuery();
4485
                        while (_rs.next()) {
4486
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4487
                                IGeometry ig = getGeometryUsing(aux, false);
4488

    
4489
                                if (ig == null) continue;
4490

    
4491
                                if (resp_aux == null) {
4492
                                        resp_aux = ig.getBounds2D();
4493
                                } else {
4494
                                        resp_aux.add(ig.getBounds2D());
4495
                                }
4496

    
4497
                        }
4498
                } catch (Exception ex) {
4499
                        logger.error("While getting random sample: " + ex.getMessage());
4500
                }
4501

    
4502
                if (resp_aux == null) {
4503
                        logger.warn("ERROR, ESTIMATED BB = WORLD");
4504
                        return world;
4505
                }
4506
                
4507
                double w = resp_aux.getWidth();
4508
                double h = resp_aux.getHeight();
4509
                double x = resp_aux.getMinX();
4510
                double y = resp_aux.getMinY();
4511

    
4512
                // enlarge 10 times:
4513
                double newx = x - (0.5 * (enlargement - 1)) * w;
4514
                double newy = y - (0.5 * (enlargement - 1)) * h;
4515
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4516
                                enlargement * w,
4517
                                enlargement * h);
4518

    
4519
                if (is_geo) {
4520
                        Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4521
                        logger.debug("ESTIMATED BB: " + resp_aux.toString());
4522
                        return resp_aux;
4523
                } else {
4524
                        logger.debug("ESTIMATED BB: " + resp_aux_large.toString());
4525
                        return resp_aux_large;
4526
                }
4527

    
4528
    }
4529

    
4530
    public void setUserName(String u) {
4531
            userName = u;
4532
    }
4533

    
4534
    public String getUserName() {
4535
            return userName;
4536
    }
4537

    
4538
    public static final int JGeometry_GTYPE_COLLECTION = 4;
4539
    public static final int JGeometry_GTYPE_CURVE = 2;
4540
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
4541
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
4542
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
4543
    public static final int JGeometry_GTYPE_POINT = 1;
4544
    public static final int JGeometry_GTYPE_POLYGON = 3;
4545
        
4546

    
4547
    // ------------------------------
4548
    
4549
    public void setXMLEntity(XMLEntity xml) throws XMLException {
4550
            
4551
            super.setXMLEntity(xml);
4552
            workingAreaInTablesCS = workingArea;
4553
            
4554
            try {
4555
                    int[] ftypes = xml.getIntArrayProperty("fieldTypes");
4556
                    setLyrDefFieldTypes(ftypes);
4557
            } catch (Exception ex) {
4558
                    logger.warn("Apparently, an old GVP file has been opened," +
4559
                                    " field type values are not accurate after this point.");
4560
            }
4561
            
4562
    }
4563
    
4564
    public XMLEntity getXMLEntity() {
4565
                // ---------------------
4566

    
4567
                XMLEntity xml = new XMLEntity();
4568
                xml.putProperty("className", getClass().getName());
4569

    
4570
                xml.putProperty("catalog", getLyrDef().getCatalogName());
4571

    
4572
                int aux = userName.indexOf("@");
4573
                if (aux != -1)
4574
                        userName = userName.substring(0, aux);
4575
                xml.putProperty("username", userName);
4576

    
4577
                xml.putProperty("driverclass", ORACLE_JAR_FILE_NAME);
4578

    
4579
                xml.putProperty("tablename", getTableName());
4580
                xml.putProperty("fields", lyrDef.getFieldNames());
4581
                xml.putProperty("fieldTypes", getLyrDefFieldTypes());
4582
                xml.putProperty("FID", lyrDef.getFieldID());
4583
                xml.putProperty("THE_GEOM", lyrDef.getFieldGeometry());
4584
                xml.putProperty("whereclause", getWhereClause());
4585
                xml.putProperty("SRID", lyrDef.getSRID_EPSG());
4586

    
4587
                xml.putProperty("host", host);
4588
                xml.putProperty("port", port);
4589
                xml.putProperty("dbName", dbName);
4590
                xml.putProperty("connName", connName);
4591

    
4592
                if (workingAreaInTablesCS != null) {
4593
                        xml.putProperty("minXworkArea", workingAreaInTablesCS.getMinX());
4594
                        xml.putProperty("minYworkArea", workingAreaInTablesCS.getMinY());
4595
                        xml.putProperty("HworkArea", workingAreaInTablesCS.getHeight());
4596
                        xml.putProperty("WworkArea", workingAreaInTablesCS.getWidth());
4597
                }
4598

    
4599
                return xml;
4600
        }
4601
    
4602
    private int[] getLyrDefFieldTypes() {
4603
            FieldDescription[] fd = lyrDef.getFieldsDesc();
4604
            int sz = fd.length;
4605
            int[] resp = new int[sz];
4606
            for (int i=0; i<sz; i++) resp[i] = fd[i].getFieldType();
4607
                return resp;
4608
        }
4609
    
4610
    private void setLyrDefFieldTypes(int[] tt) {
4611
            FieldDescription[] fd = lyrDef.getFieldsDesc();
4612
            
4613
            int sz_fd = fd.length;
4614
            int sz_tt = tt.length;
4615
            int sz = sz_tt;
4616
            
4617
            if (sz_tt != sz_fd) {
4618
                    logger.error("Field count does not match. lyrDef has " + sz_fd + " fields," +
4619
                                    " but this method was called with " + sz_tt + " items (?)");
4620
                    sz = Math.min(sz_fd, sz_tt);
4621
            }
4622
            
4623
            for (int i=0; i<sz; i++) lyrDef.getFieldsDesc()[i].setFieldType(tt[i]);
4624
    }
4625

    
4626
        public String[] getTableFields(IConnection conex, String table) throws DBException {
4627
                try{
4628
                Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
4629
        // ResultSet rs = dbmd.getTables(catalog, null, dbLayerDefinition.getTable(), null);
4630
                ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
4631
                ResultSetMetaData rsmd = rs.getMetaData();
4632

    
4633
                String[] ret = new String[rsmd.getColumnCount()];
4634

    
4635
                for (int i = 0; i < ret.length; i++) {
4636
                        ret[i] = rsmd.getColumnName(i+1);
4637
                }
4638

    
4639
                return ret;
4640
                }catch (SQLException e) {
4641
                        throw new DBException(e);
4642
                }
4643
        }
4644

    
4645
    // Overwritten to keep old behavior: returns "schema.table_name" if
4646
    // schema is not current user
4647
        public String getTableName() {
4648
            return fullTableName; 
4649
        }
4650
        
4651
    private Timestamp flexibleTimeStamp(String s) {
4652
            
4653
            String aux = s.replace('-', ' ');
4654
            aux = aux.replace(':', ' ');
4655
            aux = aux.replace('.', ' ');
4656
            // sample: 2007 12 31 23 59 59 9999
4657
            String[] parts = aux.trim().split(" ");
4658
            
4659
            int year;
4660
            int month;
4661
            int day;
4662
            int hour;
4663
            int minute;
4664
            int second;
4665
            int a_nanos;
4666

    
4667
            if (parts.length == 7) {
4668

    
4669
                    try {
4670

    
4671
                            year = Integer.parseInt(parts[0]) - 1900;
4672
                            month = Integer.parseInt(parts[1]) - 1;
4673
                            day = Integer.parseInt(parts[2]);
4674
                            hour = Integer.parseInt(parts[3]);
4675
                            minute = Integer.parseInt(parts[4]);
4676
                            second = Integer.parseInt(parts[5]);
4677
                            a_nanos = Integer.parseInt(parts[6]);
4678
                            
4679
                    } catch (Exception ex) {
4680
                        logger.debug("Bad time stamp: " + ex.getMessage());
4681
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4682
                    }
4683

    
4684
            } else {
4685
                    
4686
                if (parts.length == 6) {
4687
                        
4688
                        try {
4689
                            year = Integer.parseInt(parts[0]) - 1900;
4690
                            month = Integer.parseInt(parts[1]) - 1;
4691
                            day = Integer.parseInt(parts[2]);
4692
                            hour = Integer.parseInt(parts[3]);
4693
                            minute = Integer.parseInt(parts[4]);
4694
                            second = Integer.parseInt(parts[5]);
4695
                            a_nanos = 0;
4696
                            
4697
                        } catch (Exception ex) {
4698
                                
4699
                            logger.debug("Bad time stamp: " + ex.getMessage());
4700
                            return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4701
                        }
4702

    
4703
                } else {
4704
                        
4705
                        logger.debug("Bad time stamp: " + s);
4706
                        return new Timestamp(1970, 1, 1, 0, 0, 0, 0);
4707
                        
4708
                }
4709
            }
4710
            
4711
            return new Timestamp(year, month, day, hour, minute, second, a_nanos);
4712
    }
4713

    
4714
        public void write(DataWare arg0) throws WriteDriverException, ReadDriverException {
4715
        }
4716
        
4717
        public static int nvarchar2Limited(int n) {
4718
                if (n <= VARCHAR2_LONG_SIZE) return n;
4719
                return VARCHAR2_LONG_SIZE;
4720
        }
4721
        
4722
        private class AnEmptyFeatureIterator implements IFeatureIterator {
4723
                public boolean hasNext() throws ReadDriverException { return false; }
4724
                public IFeature next() throws ReadDriverException { return null; }
4725
                public void closeIterator() throws ReadDriverException { }                
4726
        }
4727

    
4728
    
4729

    
4730
}