Statistics
| Revision:

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

History | View | Annotate | Download (132 KB)

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

    
45
import com.hardcode.driverManager.IDelayedDriver;
46

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

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

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

    
106
import oracle.jdbc.OracleConnection;
107

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

    
110
import oracle.sql.ARRAY;
111
import oracle.sql.Datum;
112
import oracle.sql.NUMBER;
113
import oracle.sql.ROWID;
114
import oracle.sql.STRUCT;
115
import oracle.sql.StructDescriptor;
116

    
117
import org.apache.log4j.Logger;
118
import org.cresques.cts.ICoordTrans;
119
import org.cresques.cts.IProjection;
120

    
121
//import org.geotools.data.oracle.sdo.GeometryConverter;
122

    
123
import java.awt.Shape;
124
import java.awt.geom.Point2D;
125
import java.awt.geom.Rectangle2D;
126

    
127
import java.io.File;
128
import java.io.IOException;
129
import java.math.BigDecimal;
130

    
131
import java.sql.Connection;
132
import java.sql.DatabaseMetaData;
133
import java.sql.Driver;
134
import java.sql.DriverManager;
135
import java.sql.PreparedStatement;
136
import java.sql.ResultSet;
137
import java.sql.ResultSetMetaData;
138
import java.sql.SQLException;
139
import java.sql.Statement;
140
import java.sql.Types;
141

    
142
import java.text.ParseException;
143

    
144
import java.util.ArrayList;
145
import java.util.HashMap;
146
import java.util.Hashtable;
147
import java.util.Iterator;
148
import java.util.Random;
149
import java.util.TreeMap;
150

    
151

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

    
173
    // constants
174
    public static final int GEODETIC_FULLEXTENT_SAMPLE_SIZE = 50;
175
    public static final String GEODETIC_SRID = "8307";
176
    public static final String ASSUMED_ORACLE_SRID = "8307";
177

    
178
    // ------------------------------------------------
179
    public static final String NAME = "Oracle Spatial Database Driver";
180
    public static final int ID_COLUMN_INDEX = 1;
181
    public static final String ORACLE_GEOMETADATA_VIEW = "ALL_SDO_GEOM_METADATA";
182
    public static final String ORACLE_EPSG_TABLE_NAME = "ORA_EPSG";
183
    public static final String ORACLE_EPSG_FILE_NAME = "ORA_EPSG.DBF";
184
    public static final String DEFAULT_GEO_FIELD = "GEOMETRY";
185
    // public static final String DEFAULT_GEO_FIELD = "MERGEDGEOMETRY";
186

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

    
198
        public static final String ORACLE_JAR_FILE_NAME = "oracle.jdbc.driver.OracleDriver";
199

    
200
    static {
201
        try {
202
            Class.forName(ORACLE_JAR_FILE_NAME);
203
        }
204
        catch (ClassNotFoundException e) {
205
            throw new RuntimeException(e);
206
        }
207
    }
208

    
209
    private OracleSpatialWriter writer = null;
210

    
211
    // utility object to convert geometries.
212
//    private GeometryConverter geotools_conv;
213

    
214
    // switch variable
215
    private boolean use_geotools = false;
216
    private boolean tableHasSrid = true;
217

    
218
    // ------------------------------------------------
219
    private boolean isNotAvailableYet = true;
220
    private IGeometry nullGeom = new FNullGeometry();
221
    private Value nullVal = ValueFactory.createNullValue();
222
    private IdLoaderThread idLoader;
223
    private DriverAttributes drvAtts;
224
    private int[] pkOneBasedIndexes;
225
    private String[] fieldNames;
226
    private String not_restricted_sql = "";
227

    
228
    private Rectangle2D workingAreaInViewsCS = null;
229
    private Rectangle2D workingAreaInTablesCS = null;
230
    private STRUCT workingAreaInTablesCSStruct = null;
231

    
232
    private String idFieldNames;
233
    private int oneBasedGeoColInd = 0;
234
    private int shapeType = -1;
235
    private boolean needsCollectionLayer = true;
236

    
237
    // ----------------------------------------------
238
    // one feature is cached to avoid querying for each attribute request:
239
    private IFeature singleCachedFeature = null;
240
    private long singleCachedFeatureRowNum = -1;
241

    
242
    // ----------------------------------------------
243
    private boolean cancelIDLoad = false;
244

    
245
    // ----------------------------------------------
246
    private String geoColName = "";
247
    private String oracleSRID;
248
    private String epsgSRID;
249
    private String destProj = "";
250
    private Rectangle2D full_Extent = null;
251
    private boolean emptyWhereClause = true;
252
    private boolean isGeogCS = false;
253
    private boolean hasRealiableExtent = true;
254

    
255
    // new hash map to perform queries by row number:
256
    private HashMap rowToId = new HashMap();
257
    private String standardSelectExpressionFalse = null;
258
        private String destProjOracle;
259
        private boolean isDestGeogCS = false;
260

    
261
    public OracleSpatialDriver() {
262
        drvAtts = new DriverAttributes();
263
        drvAtts.setLoadedInMemory(false);
264
    }
265

    
266
        public String getWhereClause() {
267
            return lyrDef.getWhereClause();
268
        }
269

    
270

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

    
282
    private void adjustLyrDef() throws SQLException {
283
        DBLayerDefinition ldef = getLyrDef();
284
        int cnt = metaData.getColumnCount();
285

    
286
        FieldDescription[] _new = new FieldDescription[cnt];
287

    
288
        for (int i = 0; i < cnt; i++) {
289
            _new[i] = new FieldDescription();
290
            _new[i].setFieldName(metaData.getColumnName(i + 1));
291
            _new[i].setDefaultValue(ValueFactory.createNullValue());
292
            _new[i].setFieldAlias(_new[i].getFieldName());
293
            _new[i].setFieldLength(getFieldWidth(i));
294

    
295
            int _type = metaData.getColumnType(i + 1);
296
            _new[i].setFieldType(_type);
297

    
298
            if ((_type == Types.FLOAT) || (_type == Types.DOUBLE) ||
299
                    (_type == Types.DECIMAL) || (_type == Types.REAL)) {
300
                _new[i].setFieldDecimalCount(6);
301
            }
302
            else {
303
                _new[i].setFieldDecimalCount(0);
304
            }
305
        }
306

    
307
        ldef.setFieldsDesc(_new);
308
        setLyrDef(ldef);
309
    }
310

    
311
    /**
312
     * Standard initializing method.
313
     */
314
    public void setData(IConnection _conn, DBLayerDefinition lyrDef) {
315
        conn = _conn;
316

    
317
        // This metadata is required to store layer in GVP
318
        // without problems:
319
        ConnectionWithParams _cwp =
320
                SingleVectorialDBConnectionManager.instance().findConnection(conn);
321
                host = _cwp.getHost();
322
                port = _cwp.getPort();
323
                dbName = _cwp.getDb();
324
                connName = _cwp.getName();
325
        // ------------------
326

    
327
        lyrDef.setConnection(conn);
328

    
329
        setLyrDef(lyrDef);
330

    
331
        geoColName = lyrDef.getFieldGeometry();
332
        not_restricted_sql = "select " + getStandardSelectExpression() +
333
            " from " + getTableName() + " c ";
334

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

    
341
        setDestProjection(lyrDef.getSRID_EPSG());
342

    
343
        IProjection viewProj = CRSFactory.getCRS("EPSG:" + destProj);
344
        IProjection tableProj = CRSFactory.getCRS("EPSG:" + epsgSRID);
345
        ICoordTrans reprojecter = viewProj.getCT(tableProj);
346

    
347
        workingAreaInViewsCS = lyrDef.getWorkingArea();
348
        if (workingAreaInViewsCS != null) {
349
                workingAreaInTablesCS = reprojecter.convert(workingAreaInViewsCS);
350
        }
351
        workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
352
                FShape.NULL, tableHasSrid, false, true);
353

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

    
359
        /**
360
     * Utility method to load IDs in a different thred, so that gvsig's gui
361
     * does not get blocked.
362
     *
363
     */
364
    public void getMetaDataInThisThread() {
365
        getMetadata();
366
    }
367

    
368
    private void getMetadata() {
369

    
370
            long id_load_start = System.currentTimeMillis();
371
        setIdRowTable();
372
        long id_load_end = System.currentTimeMillis();
373

    
374
        long delay = id_load_end - id_load_start;
375
        if (delay < ID_MIN_DELAY) {
376
                logger.info("Ids thread delayed by: " + (ID_MIN_DELAY - delay) + " ms.");
377
                try {
378
                                Thread.sleep(ID_MIN_DELAY - delay);
379
                        } catch (InterruptedException e) {
380
                                logger.error("While delaying ids thread: " + e.getMessage());
381
                        }
382
        }
383

    
384
        if (!hasRealiableExtent) {
385
                full_Extent = getEstimatedGeodeticExtent(
386
                                getTableName(), geoColName, conn, 20, 1.5);
387
        }
388

    
389

    
390
        if (cancelIDLoad) {
391
            return;
392
        }
393
    }
394

    
395
    private boolean needsCollectionLayer() {
396
        try {
397
            // SELECT DISTINCT(C.GEOM.SDO_GTYPE) FROM COMUICV C
398
            // String qry = "select distinct(c."  + geoColName + ".SDO_GTYPE) from " + getTableName() + " c";
399
            String qry = "select c." + geoColName + ".SDO_ELEM_INFO from " +
400
                getTableName() + " c";
401

    
402
            // SDO_ELEM_INFO
403
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
404
            ResultSet _rs = _st.executeQuery(qry);
405

    
406
            ArrayList types = new ArrayList();
407
            int aux = 0;
408

    
409
            ARRAY info_aux;
410
            int[] info_aux_int;
411
            int size;
412

    
413
            while (_rs.next()) {
414
                // aux = _rs.getInt(1);
415
                info_aux = (ARRAY) _rs.getObject(1);
416
                info_aux_int = info_aux.getIntArray();
417
                size = info_aux_int.length / 3;
418

    
419
                for (int i = 0; i < size; i++) {
420
                    aux = info_aux_int[(3 * i) + 1];
421
                }
422

    
423
                types.add(new Integer(aux % 1000));
424

    
425
                if ((aux % 1000) != 3) {
426
                    System.err.println("x");
427
                }
428
            }
429

    
430
            _rs.close();
431
            _st.close();
432

    
433
            boolean resp = hasSeveralGeometryTypes(types, false);
434

    
435
            return resp;
436
        }
437
        catch (Exception se) {
438
            System.err.println("Error while getting SDO metadata: " +
439
                se.getMessage());
440
        }
441

    
442
        return false;
443
    }
444

    
445
    private boolean hasSeveralGeometryTypes(ArrayList tt, boolean are_dims) {
446
        if (tt.size() == 0) {
447
            return false;
448
        }
449

    
450
        HashMap m = new HashMap();
451

    
452
        for (int i = 0; i < tt.size(); i++) {
453
            Integer integ = (Integer) tt.get(i);
454
            int val = integ.intValue();
455

    
456
            if ((val == 4) && (!are_dims)) {
457
                return true;
458
            }
459

    
460
            m.put("" + (val % 4), "a type");
461
        }
462

    
463
        Iterator iter = m.keySet().iterator();
464
        iter.next();
465

    
466
        return iter.hasNext();
467
    }
468

    
469
    private String getOracleSridFromCurrentRecord(ResultSet _rs)
470
        throws SQLException {
471
        Object obj = _rs.getObject("SRID");
472

    
473
        if (obj == null) {
474
            logger.warn("No SRID found for this table.");
475
            tableHasSrid = false;
476

    
477
            return ASSUMED_ORACLE_SRID;
478
        }
479

    
480
        return obj.toString();
481
    }
482

    
483
    private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
484
        throws SQLException {
485
        ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
486

    
487
        if (dim_info_array == null) {
488
            // no full extent found:
489
            return null;
490
        }
491
        else {
492
            Datum[] da = dim_info_array.getOracleArray();
493

    
494
            STRUCT sx = (STRUCT) da[0];
495
            STRUCT sy = (STRUCT) da[1];
496

    
497
            try {
498
                double minx = Double.parseDouble(sx.getAttributes()[1].toString());
499
                double maxx = Double.parseDouble(sx.getAttributes()[2].toString());
500
                double miny = Double.parseDouble(sy.getAttributes()[1].toString());
501
                double maxy = Double.parseDouble(sy.getAttributes()[2].toString());
502

    
503
                if (minx > maxx) {
504
                    double aux = minx;
505
                    minx = maxx;
506
                    maxx = aux;
507
                }
508

    
509
                if (miny > maxy) {
510
                    double aux = miny;
511
                    miny = maxy;
512
                    maxy = aux;
513
                }
514

    
515
                return getRectangle(minx, maxx, miny, maxy);
516

    
517
                // fullExtentJTS = shapeToGeometry(fullExtent);
518
            }
519
            catch (Exception ex) {
520
                System.err.println(
521
                    "Error while getting full extent from metadata table.");
522

    
523
                return null;
524

    
525
                // fullExtentJTS = null;
526
            }
527
        }
528
    }
529

    
530
    private void loadSdoMetadata() {
531
        try {
532
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
533
            String[] tokens = getTableName().split("\\u002E", 2);
534
            String qry;
535
            if (tokens.length > 1)
536
            {
537
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
538
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
539
                tokens[1] + "'";
540
            }
541
            else
542
            {
543
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
544
                " where TABLE_NAME = " + "'" + getTableName() + "'";
545

    
546
            }
547
//            String qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
548
//                " where TABLE_NAME = " + "'" + getTableName() + "'";
549
            ResultSet _rs = _st.executeQuery(qry);
550

    
551
            if (_rs.next()) {
552
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
553

    
554
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
555

    
556
                try {
557
                                        epsgSRID = oracleSridToEpsgSrid(oracleSRID);
558
                                } catch (Exception e) {
559
                                        logger.error("Unknown oracle SRID: " + oracleSRID);
560
                                        tableHasSrid = false;
561
                                }
562
                full_Extent = getFullExtentFromCurrentRecord(_rs);
563

    
564
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS);
565

    
566
                if (!hasRealiableExtent) {
567
                        full_Extent = getFastEstimatedGeodeticExtent(
568
                                        getTableName(), geoColName, conn, 20, 10);
569
                }
570

    
571
                _rs.close();
572
                _st.close();
573
            }
574
            else {
575
                throw new SQLException("Empty resultset from this query: " +
576
                    qry);
577
            }
578
        }
579
        catch (SQLException se) {
580
            System.err.println("Error while getting SDO metadata: " +
581
                se.getMessage());
582
        }
583
    }
584

    
585
    /**
586
     * Utility method to find out if a coordinate system is geodetic or not.
587
     *
588
     * @param oracleSRID2 the coordinate system's oracle code
589
     * @param thas whether the table has a coordinate system set.
590
     * if not, the method returns false.
591
     * @return whether the coordinate system is geodetic or not.
592
     */
593
    public static boolean getIsGCS(String oracleSRID2, boolean thas) {
594

    
595
        if (!thas) return false;
596
        int ora_cs = 0;
597

    
598
        try {
599
            ora_cs = Integer.parseInt(oracleSRID2);
600
        }
601
        catch (Exception ex) {
602
            return false;
603
        }
604

    
605
        if (((ora_cs >= 8000) && (ora_cs <= 8999)) || (ora_cs == 524288)) {
606
            return true;
607
        } else {
608
                return false;
609
        }
610
    }
611

    
612
    private Rectangle2D getRectangle(double minx, double maxx, double miny,
613
        double maxy) {
614
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
615
                maxy - miny);
616

    
617
        return resp;
618
    }
619

    
620
    private void oneRowMetadata() {
621
        try {
622
            String _sql = "select " + getStandardSelectExpression() + ", c." +
623
                geoColName + " from " + getTableName() + " c ";
624

    
625
            st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
626
                    ResultSet.CONCUR_READ_ONLY);
627

    
628
            ResultSet _rs = st.executeQuery(_sql + " where (rownum = 1)");
629

    
630
            if (_rs.next()) {
631
                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
632
                shapeType = getShapeTypeOfStruct(sample_geo);
633
            }
634
            else {
635
                shapeType = FShape.MULTI;
636
            }
637

    
638
            // -----------------------
639
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
640
            metaData = _rs.getMetaData();
641

    
642
            userName = ((ConnectionJDBC)conn).getConnection().getMetaData().getUserName();
643

    
644
            // geoColInd = _rs.findColumn(geoColName);
645
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
646

    
647
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
648
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
649

    
650
            int cnt = metaData.getColumnCount();
651
            fieldNames = new String[cnt];
652

    
653
            for (int i = 0; i < cnt; i++) {
654
                fieldNames[i] = metaData.getColumnName(i + 1);
655
            }
656

    
657
            getIdFieldNames();
658

    
659
            adjustLyrDef();
660

    
661
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan
662
        }
663
        catch (SQLException se) {
664
            logger.error("While getting metadata. " + se.getMessage());
665
        }
666
    }
667

    
668
    private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
669
        int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue() % 10;
670

    
671
        switch (code) {
672
        case 1:
673
            return FShape.POINT;
674

    
675
        case 2:
676
            return FShape.LINE;
677

    
678
        case 3:
679
            return FShape.POLYGON;
680

    
681
        case 4:
682
            return FShape.MULTI;
683

    
684
        case 5:
685
            return FShape.MULTIPOINT;
686

    
687
        case 6:
688
            return FShape.LINE;
689

    
690
        case 7:
691
            return FShape.POLYGON;
692
        }
693

    
694
        logger.error("Unknown geometry type: " + code);
695

    
696
        return FShape.NULL;
697
    }
698

    
699
    private String getIdFieldNames() {
700
        try {
701
            idFieldNames = "";
702

    
703
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
704
                idFieldNames = idFieldNames +
705
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
706
            }
707
        }
708
        catch (SQLException se) {
709
        }
710

    
711
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
712

    
713
        return idFieldNames;
714
    }
715

    
716
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
717
        int[] _res = new int[1];
718
        _res[0] = 1;
719

    
720
        return _res;
721
    }
722

    
723
    public String getSqlTotal() {
724
        // TODO Auto-generated method stub
725
        return "";
726
    }
727

    
728
    public String getCompleteWhere() {
729
        // TODO Auto-generated method stub
730
        return "";
731
    }
732

    
733
    /**
734
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
735
     * and uses directly that sentence to query the table).
736
     */
737
    public IFeatureIterator getFeatureIterator(String sql)
738
        throws DriverException {
739
        if (isNotAvailableYet) {
740
            return null;
741
        }
742

    
743
        singleCachedFeatureRowNum = -1;
744

    
745
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
746

    
747
        ResultSet localrs = (ResultSet) rs_st[0];
748
        Statement _st = (Statement) rs_st[1];
749

    
750
        return new OracleSpatialFeatureIterator(this, localrs, _st,
751
            oneBasedGeoColInd, use_geotools);
752
    }
753

    
754
    /**
755
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
756
     */
757
    public String getConnectionStringBeginning() {
758
        // oracle
759
        return CONN_STR_BEGIN;
760
    }
761

    
762
    public void open() throws DriverException {
763
    }
764

    
765
    /**
766
     * Gets Oracle's default port: 1521
767
     */
768
    public int getDefaultPort() {
769
        // oracle port
770
        return 1521;
771
    }
772

    
773
    /**
774
     * Gets the feature iterator for a given rectangle (the view's bounding box)
775
     * and a SRS.
776
     */
777
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
778
        throws DriverException {
779
        if (isNotAvailableYet) {
780
            return null;
781
        }
782

    
783
        singleCachedFeatureRowNum = -1;
784

    
785
        STRUCT local_st = shapeToStruct(r, FShape.NULL, true, false, true);
786

    
787
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
788

    
789
        ResultSet localrs = (ResultSet) rs_st[0];
790
        Statement _st = (Statement) rs_st[1];
791

    
792
        return new OracleSpatialFeatureIterator(this, localrs, _st,
793
            oneBasedGeoColInd, use_geotools);
794
    }
795

    
796
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
797
        if (workingAreaInTablesCS == null) return r;
798
        return doIntersect(r, workingAreaInTablesCS);
799
    }
800

    
801
    /**
802
     * This method reverts to the one without the fields specification.
803
     * The fields have been selected from the start.
804
     */
805
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
806
        String[] alphaNumericFieldsNeeded) throws DriverException {
807
        if (isNotAvailableYet) {
808
            return null;
809
        }
810

    
811
        singleCachedFeatureRowNum = -1;
812

    
813
        return getFeatureIterator(r, strEPSG);
814
    }
815

    
816
    public String getGeometryField(String fieldName) {
817
        return fieldName;
818

    
819
        // return "ASBINARY(" + fieldName + ")";
820
    }
821

    
822
    public DriverAttributes getDriverAttributes() {
823
        return drvAtts;
824
    }
825

    
826
    /**
827
     * Gets the requested geometry. Always performs a new query in this case.
828
     * This should be a rare way to get the geometries. The standard way is by using
829
     * the iterators.
830
     */
831
    public IGeometry getShape(int _ind) throws IOException {
832
        if (isNotAvailableYet) {
833
            return nullGeom;
834
        }
835

    
836
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
837

    
838
        String _sql = "select " + geoColName + " from " + getTableName() +
839
            " where rowid = ?";
840

    
841
        try {
842
            java.sql.PreparedStatement ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(_sql);
843
            ps.setObject(1, r_id);
844

    
845
            // Statement stmnt = conn.createStatement();
846
            ps.execute();
847

    
848
            ResultSet _res = ps.getResultSet();
849

    
850
            if (_res.next()) {
851
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
852
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
853
                _res.close();
854
                ps.close();
855

    
856
                return theGeom;
857
            }
858
            else {
859
                logger.error("Unable to get shape: " + _ind +
860
                    " (probably due to edition)");
861

    
862
                return nullGeom;
863
            }
864
        }
865
        catch (SQLException se) {
866
            throw new IOException("SQLException: " + se.getMessage());
867
        }
868
    }
869

    
870
    public boolean isWritable() {
871
        return true;
872
    }
873

    
874
    public String getName() {
875
        return NAME;
876
    }
877

    
878
    public int[] getPrimaryKeys()
879
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
880
        return pkOneBasedIndexes;
881
    }
882

    
883
    public void write(DataWare dataWare)
884
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
885
    }
886

    
887
    private void setIdRowTable() {
888
        hashRelate = new Hashtable();
889

    
890
        java.sql.PreparedStatement ps = null;
891

    
892
        try {
893
            String _sql = getIdAndElemInfoFullResulltSetQuery();
894

    
895
            logger.debug("SQL para leer ids: " + _sql);
896
            Statement st = null;
897

    
898

    
899
            st = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
900
                        ResultSet.CONCUR_READ_ONLY);
901

    
902
            st.setFetchSize(FETCH_SIZE);
903
            logger.info("FETCH_SIZE = " + FETCH_SIZE);
904

    
905
            ResultSet _r = null;
906
            _r = st.executeQuery(_sql);
907

    
908
            ROWID ri = null;
909

    
910
            int row = 0;
911
            String gid;
912
            Value aux = null;
913

    
914
            // ----------------------------------- types init
915
            ArrayList types = new ArrayList();
916
            int types_aux = 0;
917

    
918
            ARRAY info_aux;
919
            int[] info_aux_int;
920
            int size;
921

    
922
            // ----------------------------------- types init
923
            logger.debug("Beginning of result set:");
924

    
925
            while (_r.next()) {
926
                // ---------------------------------------
927
                ri = (ROWID) _r.getObject(1);
928
                gid = ri.stringValue();
929
                aux = ValueFactory.createValue(gid);
930

    
931
                Integer intobj = new Integer(row);
932
                hashRelate.put(aux, intobj);
933
                rowToId.put(intobj, ri);
934

    
935
                if ((row % 5000) == 0) {
936
                    // ------------------------------------------- cancel load
937
                    if (cancelIDLoad) {
938
                        hashRelate.clear();
939
                        rowToId.clear();
940

    
941
                        return;
942
                    }
943

    
944
                    // -------------------------------------------
945
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
946
                    logger.info("IDs read: " + fmt);
947
                }
948

    
949
                row++;
950

    
951
                // --------------------------------------- types
952
                info_aux = (ARRAY) _r.getObject(2);
953

    
954
                if (info_aux == null) {
955
                    // logger.debug("NULL info array found in record: " + row);
956
                }
957
                else {
958
                    info_aux_int = info_aux.getIntArray();
959
                    size = info_aux_int.length / 3;
960

    
961
                    for (int i = 0; i < size; i++) {
962
                        types_aux = info_aux_int[(3 * i) + 1];
963
                        types.add(new Integer(types_aux % 1000));
964
                    }
965
                }
966

    
967
                // --------------------------------------- types end
968
            }
969

    
970
            _r.close();
971
//            ps.close();
972
            st.close();
973
            numReg = row;
974

    
975
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
976

    
977
            if (needsCollectionLayer) {
978
                shapeType = FShape.MULTI;
979
            }
980
        }
981
        catch (SQLException e) {
982
            System.err.println("While setting id-row hashmap: " +
983
                e.getMessage());
984
        }
985
    }
986

    
987
    public int getFieldCount()
988
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
989
        try {
990
            return metaData.getColumnCount();
991
        }
992
        catch (SQLException e) {
993
            System.err.println("While getting field count: " + e.getMessage());
994
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e.getMessage());
995
        }
996
    }
997

    
998
    public String[] getFieldNames() {
999
        return fieldNames;
1000
    }
1001

    
1002
    public String getTotalFields() {
1003
        String strAux = "";
1004

    
1005
        for (int i = 0; i < fieldNames.length; i++) {
1006
            if (i == 0) {
1007
                strAux = fieldNames[i];
1008
            }
1009
            else {
1010
                strAux = strAux + ", " + fieldNames[i];
1011
            }
1012
        }
1013

    
1014
        return strAux;
1015
    }
1016

    
1017
    public int getFieldType(int idField)
1018
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1019
        int i = 0;
1020

    
1021
        try {
1022
            i = idField + 1; // idField viene basado en 0
1023

    
1024
            int __type = metaData.getColumnType(i);
1025

    
1026
            // we must add this entry because we did not remove the 'geometry' column
1027
            if (__type == Types.STRUCT) {
1028
                return Types.VARCHAR; // .STRUCT;
1029
                                      // ----------------------------------------------------------------------
1030
            }
1031

    
1032
            if (__type == Types.VARCHAR) {
1033
                return Types.VARCHAR;
1034
            }
1035

    
1036
            if (__type == Types.FLOAT) {
1037
                return Types.FLOAT;
1038
            }
1039

    
1040
            if (__type == Types.DOUBLE) {
1041
                return Types.DOUBLE;
1042
            }
1043

    
1044
            if (__type == Types.INTEGER) {
1045
                return Types.INTEGER;
1046
            }
1047

    
1048
            if (__type == Types.SMALLINT) {
1049
                return Types.SMALLINT;
1050
            }
1051

    
1052
            if (__type == Types.TINYINT) {
1053
                return Types.TINYINT;
1054
            }
1055

    
1056
            if (__type == Types.BIGINT) {
1057
                return Types.BIGINT;
1058
            }
1059

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

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

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

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

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

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

    
1084
            if (__type == Types.TIMESTAMP) {
1085
                return Types.TIMESTAMP;
1086
            }
1087
        }
1088
        catch (SQLException e) {
1089
            System.err.println("i = " + i);
1090
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e);
1091
        }
1092

    
1093
        return -1;
1094
    }
1095

    
1096
    public Value[] getAttributes(ResultSet rs) {
1097
        Value[] res = null;
1098

    
1099
        try {
1100
            int fcount = rs.getMetaData().getColumnCount();
1101
            res = new Value[fcount];
1102

    
1103
            for (int i = 0; i < fcount; i++) {
1104
                Object obj = rs.getObject(i + 1);
1105
                String objToString = null;
1106
                int _type = -1;
1107

    
1108
                if (obj instanceof String) {
1109
                    objToString = (String) obj;
1110
                    _type = Types.VARCHAR;
1111
                }
1112
                else {
1113
                    if (obj instanceof ROWID) {
1114
                        objToString = ((ROWID) obj).stringValue();
1115
                        _type = Types.VARCHAR;
1116
                    }
1117
                    else {
1118
                        if (obj instanceof STRUCT) {
1119
                            objToString = "STRUCT";
1120
                            _type = Types.VARCHAR;
1121
                        }
1122
                        else {
1123
                            objToString = (obj == null) ? "NULL" : obj.toString();
1124
                            _type = getFieldType(i);
1125
                        }
1126
                    }
1127
                }
1128

    
1129
                // /*
1130
                if (_type == -1) {
1131
                    obj = null;
1132
                }
1133

    
1134
                // */
1135
                if (obj == null) {
1136
                    res[i] = ValueFactory.createNullValue();
1137
                }
1138
                else {
1139
                    if (_type == Types.DATE) {
1140
                        objToString = objToString.replace('-', '/');
1141
                    }
1142

    
1143
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1144
                }
1145
            }
1146
        }
1147
        catch (SQLException se) {
1148
            System.err.println("Error while getting attributes: " +
1149
                se.getMessage());
1150

    
1151
            return null;
1152
        }
1153
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1154
            System.err.println("Error while getting attributes: " +
1155
                e.getMessage());
1156

    
1157
            return null;
1158
        }
1159
        catch (ParseException e) {
1160
            System.err.println("Error while getting attributes: " +
1161
                e.getMessage());
1162

    
1163
            return null;
1164
        }
1165

    
1166
        return res;
1167
    }
1168

    
1169
    public Value[] getAttributesUsingMainMetadata(ResultSet rs) {
1170
        Value[] res = null;
1171

    
1172
        try {
1173
            int fcount = metaData.getColumnCount();
1174
            res = new Value[fcount];
1175

    
1176
            for (int i = 0; i < fcount; i++) {
1177
                Object obj = rs.getObject(i + 1);
1178
                String objToString = null;
1179
                int _type = -1;
1180

    
1181
                if (obj instanceof String) {
1182
                    objToString = (String) obj;
1183
                    _type = Types.VARCHAR;
1184
                }
1185
                else {
1186
                    if (obj instanceof ROWID) {
1187
                        objToString = ((ROWID) obj).stringValue();
1188
                        _type = Types.VARCHAR;
1189
                    }
1190
                    else {
1191
                        if (obj instanceof STRUCT) {
1192
                            objToString = "STRUCT";
1193
                            _type = Types.VARCHAR;
1194
                        }
1195
                        else {
1196
                            objToString = (obj == null) ? "NULL" : obj.toString();
1197
                            _type = getFieldType(i);
1198
                        }
1199
                    }
1200
                }
1201

    
1202
                // /*
1203
                if (_type == -1) {
1204
                    obj = null;
1205
                }
1206

    
1207
                // */
1208
                if (obj == null) {
1209
                    res[i] = ValueFactory.createNullValue();
1210
                }
1211
                else {
1212
                    if (_type == Types.DATE) {
1213
                        objToString = objToString.replace('-', '/');
1214
                    }
1215

    
1216
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1217
                }
1218
            }
1219
        }
1220
        catch (SQLException se) {
1221
            System.err.println("Error while getting attributes: " +
1222
                se.getMessage());
1223

    
1224
            return null;
1225
        }
1226
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1227
            System.err.println("Error while getting attributes: " +
1228
                e.getMessage());
1229

    
1230
            return null;
1231
        }
1232
        catch (ParseException e) {
1233
            System.err.println("Error while getting attributes: " +
1234
                e.getMessage());
1235

    
1236
            return null;
1237
        }
1238

    
1239
        return res;
1240
    }
1241

    
1242

    
1243
    public String getFieldName(int fieldId)
1244
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1245
        return fieldNames[fieldId];
1246
    }
1247

    
1248
    public int getFieldWidth(int fieldId) {
1249
        int i = -1;
1250

    
1251
        try {
1252
            int aux = fieldId + 1; // fieldId viene basado en 0
1253
            i = metaData.getColumnDisplaySize(aux);
1254
        }
1255
        catch (SQLException e) {
1256
            System.err.println("While getting field width: " + e.getMessage());
1257
        }
1258

    
1259
        if (i < 0) {
1260
            i = 255;
1261
        }
1262

    
1263
        return i;
1264
    }
1265

    
1266
    public Value getFieldValue(long rowIndex, int field_Id)
1267
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1268
        if (isNotAvailableYet) {
1269
            return nullVal;
1270
        }
1271

    
1272
        if ((singleCachedFeature != null) &&
1273
                (rowIndex == singleCachedFeatureRowNum)) {
1274
            return singleCachedFeature.getAttributes()[field_Id];
1275
        }
1276

    
1277
        // return ValueFactory.createNullValue();
1278
        ResultSet _r = null;
1279
        java.sql.PreparedStatement ps = null;
1280

    
1281
        try {
1282
            String rnq = getSearchId();
1283
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1284

    
1285
            ps = ((ConnectionJDBC)conn).getConnection().prepareStatement(rnq);
1286
            ps.setObject(1, _id);
1287

    
1288
            ps.execute();
1289
            _r = ps.getResultSet();
1290
            _r.next();
1291
        }
1292
        catch (SQLException se) {
1293
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(se.getMessage());
1294
        }
1295

    
1296
        IFeature ife = null;
1297
        Value[] atts = null;
1298

    
1299
        try {
1300
            ROWID ri = (ROWID) _r.getObject(1);
1301
            atts = getAttributesUsingMainMetadata(_r);
1302

    
1303
            String gid = ri.stringValue();
1304
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1305
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1306
            ife = new DefaultFeature(theGeom, atts, gid);
1307
            _r.close();
1308
            ps.close();
1309
        }
1310
        catch (SQLException se) {
1311
            logger.error("Error while doing next(): " + se.getMessage(), se);
1312
        }
1313

    
1314
        // -------------------------------
1315
        singleCachedFeature = ife;
1316
        singleCachedFeatureRowNum = rowIndex;
1317

    
1318
        // -------------------------------
1319
        if (atts == null) {
1320
            return ValueFactory.createNullValue();
1321
        }
1322
        else {
1323
            return atts[field_Id];
1324
        }
1325
    }
1326

    
1327
    public static void showMemory() {
1328
        Runtime r = Runtime.getRuntime();
1329
        long mem = r.totalMemory() - r.freeMemory();
1330
        System.err.println("Memoria total: " + mem);
1331
    }
1332

    
1333
    public Rectangle2D getFullExtent() {
1334
            return full_Extent;
1335
    }
1336

    
1337
    /**
1338
     * Utility method to get a geometry from a struct.
1339
     *
1340
     * @param theStruct the struct to be converted
1341
     * @param use_gtools switch to use geotools classes or not
1342
     * @return the geometry
1343
     * @throws SQLException
1344
     */
1345
    public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
1346
        throws SQLException {
1347
        IGeometry _igeom = null;
1348

    
1349
        if (theStruct == null) {
1350
            return nullGeom;
1351
        }
1352

    
1353
        if (use_gtools) { // geotools
1354
//            _igeom = getGeotoolsIGeometry(theStruct);
1355
        }
1356
        else { // jgeometry
1357
            _igeom = getFMapGeometry(theStruct, false);
1358
        }
1359

    
1360
        return _igeom;
1361
    }
1362

    
1363
    /*
1364
    private IGeometry getFMapGeometry(JGeometry jg, boolean force_not_collection) {
1365
        int jgtype = jg.getType();
1366
        int dim = jg.getDimensions();
1367
        IGeometry ig = null;
1368

1369
        if ((jgtype != JGeometry.GTYPE_COLLECTION) &&
1370
                (isActuallyACollection(jg))) {
1371
            jgtype = JGeometry.GTYPE_COLLECTION;
1372
        }
1373

1374
        switch (jgtype) {
1375
        case JGeometry.GTYPE_COLLECTION:
1376

1377
            int srid = jg.getSRID();
1378
            ig = getFMapGeometryCollection(jg, dim, srid);
1379

1380
            break;
1381

1382
        case JGeometry.GTYPE_POINT:
1383
        case JGeometry.GTYPE_MULTIPOINT:
1384
            ig = getFMapGeometryPoint(jg, dim);
1385

1386
            break;
1387

1388
        case JGeometry.GTYPE_CURVE:
1389
        case JGeometry.GTYPE_MULTICURVE:
1390
            ig = getFMapGeometryMultiLineString(jg, dim);
1391

1392
            break;
1393

1394
        case JGeometry.GTYPE_POLYGON:
1395
        case JGeometry.GTYPE_MULTIPOLYGON:
1396
            ig = getFMapGeometryMultipolygon(jg, dim);
1397

1398
            break;
1399
        }
1400

1401
        return ig;
1402
    }
1403
    */
1404

    
1405
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim) {
1406
        // int __srid) {
1407

    
1408
            NUMBER _srid = new NUMBER(0);
1409
        NUMBER main_type = new NUMBER((dim * 1000) +
1410
                OracleSpatialUtils.getStructType(the_data));
1411

    
1412

    
1413
        Datum[] all_info_array = null;
1414
        Object[] elems_info_aray = null;
1415
        Datum[] all_ords = null;
1416

    
1417
        Object[] ords_of_groups = null;
1418
        Object[] _elems_info_aray = null;
1419
        try {
1420
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1421
            elems_info_aray = groupByElement(all_info_array);
1422
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1423

    
1424
            ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1425
            _elems_info_aray = new Object[elems_info_aray.length];
1426
        }
1427
        catch (SQLException e) {
1428
            logger.error("Unexpected error: " + e.getMessage());
1429
        }
1430

    
1431

    
1432
        for (int i = 0; i < elems_info_aray.length; i++) {
1433
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1434
        }
1435

    
1436
        // _elems_info_aray, ords_of_groups
1437
        int no_of_elems = ords_of_groups.length;
1438
        IGeometry[] geoms = new IGeometry[no_of_elems];
1439

    
1440
        for (int i = 0; i < no_of_elems; i++) {
1441
            Datum[] item_info_array = null;
1442
            Datum[] item_ords = null;
1443
            NUMBER gtype = null;
1444

    
1445
            try {
1446
                item_info_array = (Datum[]) _elems_info_aray[i];
1447
                item_ords = (Datum[]) ords_of_groups[i];
1448

    
1449
                gtype = new NUMBER((dim * 1000) +
1450
                        (item_info_array[1].intValue() % 1000));
1451

    
1452
                if (tableHasSrid) {
1453
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1454
                }
1455
            }
1456
            catch (SQLException se) {
1457
                logger.error("Unexpected error: " + se.getMessage());
1458
            }
1459

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

    
1463
            STRUCT itemst = null;
1464

    
1465
            if (tableHasSrid) {
1466

    
1467
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1468
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1469
            }
1470
            else {
1471
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1472
                        item_info_array, item_ords, ((ConnectionJDBC)conn).getConnection());
1473
            }
1474

    
1475
            geoms[i] = getFMapGeometry(itemst, true);
1476
        }
1477

    
1478
        return new FGeometryCollection(geoms);
1479
    }
1480

    
1481
    /**
1482
     * Utility method to transform a struct into a IGeometry.
1483
     *
1484
     * @param st the struct to be converted
1485
     * @param force_not_collection t5his parameter is currently ignored
1486
     * @return the IGeometry
1487
     */
1488
    public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1489

    
1490
            if (st == null) {
1491
                    return new FNullGeometry();
1492
            }
1493

    
1494
        Datum[] the_data = null;
1495

    
1496
        try {
1497
            the_data = st.getOracleAttributes();
1498

    
1499
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1500
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1501

    
1502
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1503

    
1504
            if (dim < 2) {
1505
                dim = 2;
1506
            }
1507

    
1508
            IGeometry ig = null;
1509

    
1510
            if (isActuallyACollection(the_data)) {
1511
                    logger.debug("isActuallyACollection(the_data) = TRUE");
1512
                jgtype = FShape.MULTI;
1513
            }
1514

    
1515
            switch (jgtype) {
1516
            case FShape.MULTI:
1517

    
1518
                // int srid = ((NUMBER) the_data[1]).intValue();
1519
                ig = getFMapGeometryCollection(the_data, dim);
1520

    
1521
                break;
1522

    
1523
            case FShape.POINT:
1524
                ig = getFMapGeometryPoint(the_data, dim);
1525

    
1526
                break;
1527

    
1528
            case FShape.LINE:
1529
                ig = getFMapGeometryMultiLineString(the_data, dim);
1530

    
1531
                break;
1532

    
1533
            case FShape.POLYGON:
1534
                ig = getFMapGeometryMultipolygon(the_data, dim);
1535

    
1536
                break;
1537
            }
1538

    
1539
            return ig;
1540
        }
1541
        catch (SQLException e) {
1542
            logger.error(e);
1543
        }
1544

    
1545
        return null;
1546
    }
1547

    
1548
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1549
        int size = input.length / n;
1550
        double[] resp = new double[size];
1551

    
1552
        for (int i = 0; i < size; i++) {
1553
            resp[i] = input[(i * n) + ind];
1554
        }
1555

    
1556
        return resp;
1557
    }
1558

    
1559
    private double[] getIndBigDecimalModule(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
    /*
1571
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1572
        IGeometry ig = null;
1573

1574
        if (jg.isCircle()) {
1575
            ig = getCircleFromJGeometry(jg);
1576
        }
1577
        else {
1578
            Shape shape = jg.createShape();
1579
            GeneralPathX gpx = new GeneralPathX(shape);
1580

1581
            if (dim == 2) {
1582
                ig = ShapeFactory.createPolygon2D(gpx);
1583
            }
1584
            else {
1585
                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1586
                ig = ShapeFactory.createPolygon3D(gpx, z);
1587
            }
1588
        }
1589

1590
        return ig;
1591
    }
1592
    */
1593

    
1594
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1595
        IGeometry ig = null;
1596

    
1597
        if (OracleSpatialUtils.isCircle(the_data)) {
1598
            ig = getCircleFromStruct(the_data);
1599
        }
1600
        else {
1601
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1602

    
1603
            if (dim == 2) {
1604
                ig = ShapeFactory.createPolygon2D(gpx);
1605
            }
1606
            else {
1607
                double[] ords = null;
1608

    
1609
                try {
1610
                    ords = ((ARRAY) the_data[4]).getDoubleArray();
1611
                }
1612
                catch (SQLException se) {
1613
                    logger.error("While getting ordinates: " + se.getMessage(),
1614
                        se);
1615
                }
1616

    
1617
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1618
                ig = ShapeFactory.createPolygon3D(gpx, z);
1619
            }
1620
        }
1621

    
1622
        return ig;
1623
    }
1624

    
1625
    /*
1626
    private IGeometry getCircleFromJGeometry(JGeometry jg) {
1627
        double[] threep = jg.getOrdinatesArray();
1628
        Point2D[] three = new Point2D.Double[3];
1629
        three[0] = new Point2D.Double(threep[0], threep[1]);
1630
        three[1] = new Point2D.Double(threep[2], threep[3]);
1631
        three[2] = new Point2D.Double(threep[4], threep[5]);
1632

1633
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1634

1635
        Point2D cent = (Point2D) cent_rad[0];
1636
        double radius = ((Double) cent_rad[1]).doubleValue();
1637

1638
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1639

1640
        return circ;
1641
    }
1642
    */
1643

    
1644
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1645
        double[] threep = null;
1646

    
1647
        try {
1648
            threep = ((ARRAY) the_data[4]).getDoubleArray();
1649
        }
1650
        catch (SQLException se) {
1651
            logger.error("While getting ords from struct: " + se.getMessage(),
1652
                se);
1653

    
1654
            return new FNullGeometry();
1655
        }
1656

    
1657
        Point2D[] three = new Point2D.Double[3];
1658
        three[0] = new Point2D.Double(threep[0], threep[1]);
1659
        three[1] = new Point2D.Double(threep[2], threep[3]);
1660
        three[2] = new Point2D.Double(threep[4], threep[5]);
1661

    
1662
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1663

    
1664
        Point2D cent = (Point2D) cent_rad[0];
1665
        double radius = ((Double) cent_rad[1]).doubleValue();
1666

    
1667
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1668

    
1669
        return circ;
1670
    }
1671

    
1672
    /*
1673
    private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1674
        Shape shape = jg.createShape();
1675
        GeneralPathX gpx = new GeneralPathX(shape);
1676
        IGeometry ig = null;
1677

1678
        if (dim == 2) {
1679
            ig = ShapeFactory.createPolyline2D(gpx);
1680
        }
1681
        else {
1682
            double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1683
            ig = ShapeFactory.createPolyline3D(gpx, z);
1684
        }
1685

1686
        return ig;
1687
    }
1688
    */
1689

    
1690
    private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1691
        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1692
        IGeometry ig = null;
1693
        double[] ords = null;
1694

    
1695
        if (dim == 2) {
1696
            ig = ShapeFactory.createPolyline2D(gpx);
1697
        }
1698
        else {
1699
            ords = OracleSpatialUtils.getOrds(the_data);
1700

    
1701
            double[] z = getIndBigDecimalModule(ords, 2, dim);
1702
            ig = ShapeFactory.createPolyline3D(gpx, z);
1703
        }
1704

    
1705
        return ig;
1706
    }
1707

    
1708
    /*
1709
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1710
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1711

1712
            return getFMapGeometrySdoPoint(jg_point, dim);
1713
        }
1714

1715
        IGeometry ig = null;
1716
        int total_size = jg_point.getOrdinatesArray().length;
1717
        int no_po = total_size / dim;
1718
        double[] x = new double[no_po];
1719
        double[] y = new double[no_po];
1720
        double[] z = new double[no_po];
1721

1722
        for (int i = 0; i < no_po; i++) {
1723
            x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1724
            y[i] = jg_point.getOrdinatesArray()[(i * dim) + 1];
1725

1726
            if (dim >= 3) {
1727
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1728
            }
1729
        }
1730

1731
        if (dim == 2) {
1732
            if (no_po == 1) {
1733
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1734
            }
1735
            else {
1736
                ig = ShapeFactory.createMultipoint2D(x, y);
1737
            }
1738
        }
1739
        else {
1740
            if (no_po == 1) {
1741
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1742
            }
1743
            else {
1744
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1745
            }
1746
        }
1747

1748
        return ig;
1749
    }
1750
    */
1751

    
1752
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1753
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1754

    
1755
        if (ords == null) { // sdo_point
1756

    
1757
            return getFMapGeometrySdoPoint(the_data, dim);
1758
        }
1759

    
1760
        IGeometry ig = null;
1761
        int total_size = ords.length;
1762
        int no_po = total_size / dim;
1763
        double[] x = new double[no_po];
1764
        double[] y = new double[no_po];
1765
        double[] z = new double[no_po];
1766

    
1767
        for (int i = 0; i < no_po; i++) {
1768
            x[i] = ords[i * dim]; // pp[i].getX();
1769
            y[i] = ords[(i * dim) + 1];
1770

    
1771
            if (dim >= 3) {
1772
                z[i] = ords[(i * dim) + 2];
1773
            }
1774
        }
1775

    
1776
        if (dim == 2) {
1777
            if (no_po == 1) {
1778
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1779
            }
1780
            else {
1781
                ig = ShapeFactory.createMultipoint2D(x, y);
1782
            }
1783
        }
1784
        else {
1785
            if (no_po == 1) {
1786
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1787
            }
1788
            else {
1789
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1790
            }
1791
        }
1792

    
1793
        return ig;
1794
    }
1795

    
1796
    /*
1797
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1798
        double[] p = jgp.getPoint();
1799
        IGeometry ig = null;
1800

1801
        if (d == 2) {
1802
            ig = ShapeFactory.createPoint2D(p[0], p[1]);
1803
        }
1804
        else {
1805
            ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1806
        }
1807

1808
        return ig;
1809
    }
1810
    */
1811

    
1812
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1813
        double x = 0;
1814
        double y = 0;
1815
        double z = 0;
1816

    
1817
        try {
1818
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1819
            x = ((NUMBER) aux[0]).doubleValue();
1820
            y = ((NUMBER) aux[1]).doubleValue();
1821

    
1822
            if (d > 2) {
1823
                z = ((NUMBER) aux[2]).doubleValue();
1824
            }
1825
        }
1826
        catch (SQLException se) {
1827
            logger.error("While getting sdo point ordinates: " +
1828
                se.getMessage(), se);
1829
        }
1830

    
1831
        IGeometry ig = null;
1832

    
1833
        if (d == 2) {
1834
            ig = ShapeFactory.createPoint2D(x, y);
1835
        }
1836
        else {
1837
            ig = ShapeFactory.createPoint3D(x, y, z);
1838
        }
1839

    
1840
        return ig;
1841
    }
1842

    
1843
    /*
1844
    private boolean isActuallyACollection(JGeometry jg) {
1845
        int[] info = jg.getElemInfo();
1846

1847
        if (info == null) {
1848
            return false; // sdo_point
1849
        }
1850

1851
        int size = info.length / 3;
1852

1853
        if (size == 1) {
1854
            return false;
1855
        }
1856

1857
        if (size == 2) {
1858
            return ((info[1] % 1000) != (info[4] % 1000));
1859
        }
1860

1861
        int second = info[4] % 1000;
1862

1863
        for (int i = 2; i < size; i++) {
1864
            if ((info[(i * 3) + 1] % 1000) != second) {
1865
                return true;
1866
            }
1867
        }
1868

1869
        return false;
1870
    }
1871
    */
1872

    
1873
    private boolean isActuallyACollection(Datum[] the_data) {
1874
        int[] info = null;
1875

    
1876
        try {
1877
            ARRAY aux = (ARRAY) the_data[3];
1878

    
1879
            if (aux == null) {
1880
                return false;
1881
            }
1882

    
1883
            info = aux.getIntArray();
1884
        }
1885
        catch (SQLException se) {
1886
            logger.error("While checking collection: " + se.getMessage());
1887
            return false;
1888
        }
1889

    
1890
        if (info == null) {
1891
            return false; // sdo_point
1892
        }
1893

    
1894
        int size = info.length / 3;
1895

    
1896
        if (size == 1) {
1897
            return false;
1898
        }
1899

    
1900
        if (size == 2) {
1901
            return ((info[1] % 1000) != (info[4] % 1000)) &&
1902
            ( ! ((info[1] == 1005) && (info[4] == 2)) );
1903
        }
1904

    
1905
        int second = info[4] % 1000;
1906
        int item = 0;
1907

    
1908
        for (int i = 2; i < size; i++) {
1909
                item = info[(i * 3) + 1] % 1000;
1910
            if ((item != second) &&
1911
                            ( ! ((item == 5) && (second == 2)) )
1912
                            ) {
1913
                return true;
1914
            }
1915
        }
1916

    
1917
        return false;
1918
    }
1919

    
1920
    /*
1921
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1922
        int main_type = jg.getType();
1923

1924
        int[] all_info_array = jg.getElemInfo();
1925
        Object[] elems_info_aray = groupByElement(all_info_array);
1926
        double[] all_ords = jg.getOrdinatesArray();
1927
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1928
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1929

1930
        for (int i = 0; i < elems_info_aray.length; i++) {
1931
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1932
        }
1933

1934
        // _elems_info_aray, ords_of_groups
1935
        int no_of_elems = ords_of_groups.length;
1936
        IGeometry[] geoms = new IGeometry[no_of_elems];
1937

1938
        for (int i = 0; i < no_of_elems; i++) {
1939
            int[] item_info_array = (int[]) _elems_info_aray[i];
1940
            double[] item_ords = (double[]) ords_of_groups[i];
1941
            int gtype = (dim * 1000) + (item_info_array[1] % 1000);
1942

1943
            // if it's the first geometry, the type is the collection's main type (no?)
1944
            if (i == 0) {
1945
                gtype = main_type;
1946
            }
1947

1948
            JGeometry itemjg = null;
1949

1950
            if (tableHasSrid) {
1951
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1952
            }
1953
            else {
1954
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1955
            }
1956

1957
            geoms[i] = getFMapGeometry(itemjg, true);
1958
        }
1959

1960
        return new FGeometryCollection(geoms);
1961
    }
1962
    */
1963

    
1964
    private Datum[] updateIndexes(Datum[] info) {
1965
        int size = info.length / 3;
1966
        NUMBER[] resp = new NUMBER[3 * size];
1967

    
1968
        try {
1969
            int rest = info[0].intValue() - 1;
1970

    
1971
            for (int i = 0; i < size; i++) {
1972
                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1973
                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
1974
                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
1975
            }
1976
        }
1977
        catch (SQLException se) {
1978
            logger.error("Unexpected error: " + se.getMessage());
1979
        }
1980

    
1981
        return resp;
1982
    }
1983

    
1984
    private int[] updateIndexes(int[] info) {
1985
        int size = info.length / 3;
1986
        int[] resp = new int[3 * size];
1987
        int rest = info[0] - 1;
1988

    
1989
        for (int i = 0; i < size; i++) {
1990
            resp[3 * i] = info[3 * i] - rest;
1991
            resp[(3 * i) + 1] = info[(3 * i) + 1];
1992
            resp[(3 * i) + 2] = info[(3 * i) + 2];
1993
        }
1994

    
1995
        return resp;
1996
    }
1997

    
1998
    private int[] appendIntArrays(int[] head, int[] tail) {
1999
        int[] resp = new int[head.length + tail.length];
2000
        int hsize = head.length;
2001

    
2002
        for (int i = 0; i < hsize; i++) {
2003
            resp[i] = head[i];
2004
        }
2005

    
2006
        for (int i = 0; i < tail.length; i++) {
2007
            resp[hsize + i] = tail[i];
2008
        }
2009

    
2010
        return resp;
2011
    }
2012

    
2013
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
2014
        Datum[] resp = new Datum[head.length + tail.length];
2015
        int hsize = head.length;
2016

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

    
2021
        for (int i = 0; i < tail.length; i++) {
2022
            resp[hsize + i] = tail[i];
2023
        }
2024

    
2025
        return resp;
2026
    }
2027

    
2028
    private int[] getNthGroupOfThree(int[] list, int n) {
2029
        int[] resp = new int[3];
2030
        resp[0] = list[3 * n];
2031
        resp[1] = list[(3 * n) + 1];
2032
        resp[2] = list[(3 * n) + 2];
2033

    
2034
        return resp;
2035
    }
2036

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

    
2043
        return resp;
2044
    }
2045

    
2046
    private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
2047
        Datum[] resp = new Datum[last_inc - first_inc + 1];
2048

    
2049
        for (int i = first_inc; i <= last_inc; i++) {
2050
            resp[i - first_inc] = all[i];
2051
        }
2052

    
2053
        return resp;
2054
    }
2055

    
2056
    private double[] getSubSet(double[] all, int first_inc, int last_inc) {
2057
        double[] resp = new double[last_inc - first_inc + 1];
2058

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

    
2063
        return resp;
2064
    }
2065

    
2066
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) throws SQLException {
2067
        Object[] resp = new Object[groups.length];
2068

    
2069
        if (resp.length == 1) {
2070
            resp[0] = all;
2071

    
2072
            return resp;
2073
        }
2074

    
2075
        int ind = 0;
2076
        Datum[] aux = (Datum[]) groups[1];
2077
        int _end = aux[0].intValue() - 2;
2078
        Datum[] ord_aux = getSubSet(all, 0, _end);
2079

    
2080
        int _start = _end + 1;
2081
        resp[ind] = ord_aux;
2082
        ind++;
2083

    
2084
        for (int i = 2; i < groups.length; i++) {
2085
            aux = (Datum[]) groups[i];
2086
            _end = aux[0].intValue() - 2;
2087
            ord_aux = getSubSet(all, _start, _end);
2088
            resp[ind] = ord_aux;
2089
            ind++;
2090
            _start = _end + 1;
2091
        }
2092

    
2093
        // last
2094
        _end = all.length - 1;
2095
        ord_aux = getSubSet(all, _start, _end);
2096
        resp[groups.length - 1] = ord_aux;
2097

    
2098
        return resp;
2099
    }
2100

    
2101
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2102
        Object[] resp = new Object[groups.length];
2103

    
2104
        if (resp.length == 1) {
2105
            resp[0] = all;
2106

    
2107
            return resp;
2108
        }
2109

    
2110
        int ind = 0;
2111
        int[] aux = (int[]) groups[1];
2112
        int _end = aux[0] - 2;
2113
        double[] ord_aux = getSubSet(all, 0, _end);
2114

    
2115
        int _start = _end + 1;
2116
        resp[ind] = ord_aux;
2117
        ind++;
2118

    
2119
        for (int i = 2; i < groups.length; i++) {
2120
            aux = (int[]) groups[i];
2121
            _end = aux[0] - 2;
2122
            ord_aux = getSubSet(all, _start, _end);
2123
            resp[ind] = ord_aux;
2124
            ind++;
2125
            _start = _end + 1;
2126
        }
2127

    
2128
        // last
2129
        _end = all.length - 1;
2130
        ord_aux = getSubSet(all, _start, _end);
2131
        resp[groups.length - 1] = ord_aux;
2132

    
2133
        return resp;
2134
    }
2135

    
2136
    private Object[] groupByElement(int[] all_elem) {
2137
        ArrayList resp = new ArrayList();
2138

    
2139
        int size = all_elem.length / 3;
2140

    
2141
        int[] aux = getNthGroupOfThree(all_elem, 0);
2142

    
2143
        int[] newaux;
2144
        int i = 1;
2145

    
2146
        while (i < size) {
2147
            newaux = getNthGroupOfThree(all_elem, i);
2148

    
2149
            if (newaux[0] == aux[0]) {
2150
                // aux[2] says how many components
2151
                for (int j = 0; j < aux[2]; j++) {
2152
                    aux = appendIntArrays(aux,
2153
                            getNthGroupOfThree(all_elem, j + i));
2154
                }
2155

    
2156
                resp.add(aux);
2157
                i = i + aux[2];
2158
                aux = getNthGroupOfThree(all_elem, i);
2159
            }
2160
            else {
2161
                if (newaux[1] == 2003) {
2162
                    aux = appendIntArrays(aux, newaux);
2163
                }
2164
                else {
2165
                    resp.add(aux);
2166
                    aux = getNthGroupOfThree(all_elem, i);
2167
                }
2168
            }
2169

    
2170
            i++;
2171
        }
2172

    
2173
        resp.add(aux);
2174

    
2175
        return resp.toArray();
2176
    }
2177

    
2178
    private Object[] groupByElement(Datum[] all_elem) {
2179
        ArrayList resp = new ArrayList();
2180

    
2181
        int size = all_elem.length / 3;
2182

    
2183
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2184

    
2185
        Datum[] newaux;
2186
        int i = 1;
2187

    
2188
        try {
2189
            while (i < size) {
2190
                newaux = getNthGroupOfThree(all_elem, i);
2191

    
2192
                if (newaux[0] == aux[0]) {
2193
                    // aux[2] says how many components
2194
                    for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
2195
                        aux = appendDatArrays(aux,
2196
                                getNthGroupOfThree(all_elem, j + i));
2197
                    }
2198

    
2199
                    resp.add(aux);
2200
                    i = i + ((NUMBER) aux[2]).intValue();
2201
                    aux = getNthGroupOfThree(all_elem, i);
2202
                }
2203
                else {
2204
                    if (((NUMBER) newaux[1]).intValue() == 2003) {
2205
                        aux = appendDatArrays(aux, newaux);
2206
                    }
2207
                    else {
2208
                        resp.add(aux);
2209
                        aux = getNthGroupOfThree(all_elem, i);
2210
                    }
2211
                }
2212

    
2213
                i++;
2214
            }
2215
        }
2216
        catch (SQLException se) {
2217
            logger.error("Unexpected error: " + se.getMessage());
2218
        }
2219

    
2220
        resp.add(aux);
2221

    
2222
        return resp.toArray();
2223
    }
2224

    
2225
    /*
2226
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2227
        Point2D p = _jgeom.getJavaPoint();
2228
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2229

2230
        return ig;
2231
    }
2232

2233
    private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2234
        Point2D[] pp = _jgeom.getJavaPoints();
2235
        int l = pp.length;
2236
        double[] x = new double[l];
2237
        double[] y = new double[l];
2238

2239
        for (int i = 0; i < l; i++) {
2240
            x[i] = pp[i].getX();
2241
            y[i] = pp[i].getY();
2242
        }
2243

2244
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2245

2246
        return ig;
2247
    }
2248

2249
    private IGeometry getJGeometryOther(JGeometry _jgeom) {
2250
        int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2251
        Shape shape = _jgeom.createShape();
2252
        GeneralPathX gpx = new GeneralPathX(shape);
2253
        IGeometry ig = null;
2254

2255
        switch (type) {
2256
        case FShape.LINE:
2257

2258
            FPolyline2D fpl = new FPolyline2D(gpx);
2259
            ig = ShapeFactory.createPolyline2D(gpx);
2260

2261
            break;
2262

2263
        case FShape.POLYGON:
2264

2265
            FPolygon2D fpg = new FPolygon2D(gpx);
2266
            ig = ShapeFactory.createPolygon2D(gpx);
2267

2268
            break;
2269
        }
2270

2271
        return ig;
2272
    }
2273
    */
2274

    
2275
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
2276
        /*
2277
         * Tipos en Oracle Spatial usando JGeometry
2278
         *
2279
         * GTYPE_COLLECTION collection geometry type
2280
         * GTYPE_CURVE curve geoemtry type
2281
         * GTYPE_MULTICURVE multi-curve geometry type
2282
         * GTYPE_MULTIPOINT multi-point geometry type
2283
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
2284
         * GTYPE_POINT point geometry type
2285
         * GTYPE_POLYGON  polygon geometry type
2286
         *
2287
         * Tipos gvSIG FShape
2288
         *
2289
         * NULL = 0;
2290
         * POINT = 1;
2291
         * LINE = 2;
2292
         * POLYGON = 4;
2293
         * TEXT = 8;
2294
         * MULTI = 16;
2295
         * MULTIPOINT = 32;
2296
         * CIRCLE = 64;
2297
         * ARC = 128;
2298
         * ELLIPSE=256;
2299
         * Z=512
2300
         */
2301
        switch (type) {
2302
        case JGeometry_GTYPE_POLYGON:
2303
        case JGeometry_GTYPE_MULTIPOLYGON:
2304
            return FShape.POLYGON;
2305

    
2306
        case JGeometry_GTYPE_CURVE:
2307
        case JGeometry_GTYPE_MULTICURVE:
2308
            return FShape.LINE;
2309
        }
2310

    
2311
        System.err.println("Unhandled Oracle Spatial geometry type: " + type +
2312
            " (conversion returned FShape.NULL)");
2313

    
2314
        return FShape.NULL;
2315
    }
2316

    
2317
    private void cleanWhereClause() {
2318
        emptyWhereClause = false;
2319

    
2320
        String aux = getWhereClauseWithoutWhere();
2321

    
2322
        for (int i = 0; i < aux.length(); i++)
2323
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
2324
                return;
2325
            }
2326

    
2327
        getLyrDef().setWhereClause("");
2328
        emptyWhereClause = true;
2329
    }
2330

    
2331
    private String getValidViewConstructor(
2332
                    STRUCT _st,
2333
                    String ora_srid,
2334
                    boolean _hassrid,
2335
                    boolean _isgeocs) {
2336

    
2337
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
2338
            String resp = "";
2339
            if ((_hassrid) && (_isgeocs)) {
2340
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
2341
            } else {
2342
                    resp = sdo;
2343
            }
2344

    
2345
            return resp;
2346
    }
2347

    
2348
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2349
        String resp = "";
2350

    
2351
        if (isGeogCS) {
2352
            String vport = "sdo_filter(" + geoColName +
2353
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
2354
                "), 'querytype=window') = 'TRUE'";
2355

    
2356
                resp = "select " + getStandardSelectExpression() + ", c." +
2357
                    geoColName + " from " + getTableName() + " c where ";
2358
                if (idsLoadWhere.length() > 0) {
2359
                        resp = resp + " (" + idsLoadWhere + ") AND ";
2360
                }
2361
                resp = resp + "(" + vport + ")";
2362
        }
2363
        else {
2364
                resp = "select " + getStandardSelectExpression() + ", c." +
2365
                    geoColName + " from " + getTableName() + " c where ";
2366
                if (idsLoadWhere.length() > 0) {
2367
                        resp = resp + " (" + idsLoadWhere + ") AND ";
2368
                }
2369
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
2370
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
2371
        }
2372

    
2373
//        return "select " + getStandardSelectExpression() + ", c." +
2374
//        geoColName + " from " + getTableName() + " c";
2375
        return resp;
2376
    }
2377

    
2378
    public void setWorkingArea(Rectangle2D rect) {
2379
    }
2380

    
2381
    private void setWAStructt() {
2382
    }
2383

    
2384
    private Geometry shapeToGeometry(Shape shp) {
2385
        if (shp == null) {
2386
            return null;
2387
        }
2388

    
2389
        int type = FShape.POLYGON;
2390

    
2391
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2392
            type = FShape.LINE;
2393
        }
2394

    
2395
        if (shp instanceof FPoint2D) {
2396
            type = FShape.POINT;
2397
        }
2398

    
2399
        if (shp instanceof FMultiPoint2D) {
2400
            type = FShape.MULTIPOINT;
2401
        }
2402

    
2403
        GeneralPathX wagp = new GeneralPathX(shp);
2404
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2405

    
2406
        return FConverter.java2d_to_jts(fwagp);
2407
    }
2408

    
2409
    /*
2410
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2411
        Shape shape = _jg.createShape();
2412

2413
        return shape.getBounds2D();
2414
    }
2415
    */
2416

    
2417
    private void printStruct(STRUCT st) {
2418
        System.out.println("----------------------------------------------");
2419

    
2420
        try {
2421
            Object[] att = st.getAttributes();
2422
            int l = att.length;
2423

    
2424
            for (int i = 0; i < l; i++) {
2425
                System.out.println("ATT " + i + ": " + att[i].toString());
2426
            }
2427
        }
2428
        catch (Exception ex) {
2429
            System.out.println(
2430
                "- Error ---------------------------------------");
2431
        }
2432

    
2433
        System.out.println("----------------------------------------------");
2434
    }
2435

    
2436
    private static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
2437
        boolean isView, boolean _isGeogCS, String _oracleSRID, IConnection __conn) {
2438
        Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2439
        Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2440

    
2441
        if ((_isGeogCS) && (isView)) {
2442
            c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2443
            c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2444
        }
2445

    
2446
        STRUCT resp = null;
2447

    
2448
        try {
2449
            // System.out.println("ABIERTA: " + (!conn.isClosed()));
2450
            // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2451
            // Object[] old_obj = resp.getAttributes();
2452
            int size = 5;
2453
            Object[] new_obj = new Object[size];
2454

    
2455
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2456
            new_obj[0] = new NUMBER(2003);
2457

    
2458
            if (hasSrid) {
2459
                new_obj[1] = new NUMBER(_oracleSRID);
2460
            }
2461
            else {
2462
                new_obj[1] = null;
2463
            }
2464

    
2465
            new_obj[2] = null;
2466

    
2467
            NUMBER[] elem_info = new NUMBER[3];
2468
            elem_info[0] = new NUMBER(1);
2469
            elem_info[1] = new NUMBER(1003);
2470
            elem_info[2] = new NUMBER(3);
2471
            new_obj[3] = elem_info;
2472

    
2473
            NUMBER[] ords = null;
2474
            ords = new NUMBER[4];
2475
            ords[0] = new NUMBER(c1.getX());
2476
            ords[1] = new NUMBER(c1.getY());
2477
            ords[2] = new NUMBER(c2.getX());
2478
            ords[3] = new NUMBER(c2.getY());
2479
            new_obj[4] = ords;
2480

    
2481
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2482
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2483
                            ((ConnectionJDBC)__conn).getConnection());
2484

    
2485
            resp = new STRUCT(dsc,((ConnectionJDBC)__conn).getConnection(), new_obj);
2486
        }
2487
        catch (Exception ex) {
2488
            logger.error("Error while creating rect struct: " +
2489
                ex.getMessage(), ex);
2490
        }
2491

    
2492
        return resp;
2493
    }
2494

    
2495
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2496
        boolean hasSrid) throws DriverException {
2497
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
2498
        String main_sel = "";
2499

    
2500
        if (fixsql == null) {
2501
            // main_sel = getMainSelect3(var_name);
2502
                String idswhere = getIdsQueryWhereClause(false);
2503
            main_sel = getMainSelect(sdo_intersect, idswhere);
2504
        }
2505
        else {
2506
            main_sel = fixsql;
2507
        }
2508

    
2509
        logger.debug("MAIN SEL = " + main_sel);
2510

    
2511
        ResultSet _rs = null;
2512
        Statement _stmnt = null;
2513
        Object[] _resp = new Object[2];
2514

    
2515
        try {
2516
            _stmnt = ((ConnectionJDBC)conn).getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY,
2517
                    ResultSet.CONCUR_READ_ONLY);
2518
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2519
            _stmnt.setFetchSize(FETCH_SIZE);
2520

    
2521
            _rs = _stmnt.executeQuery(main_sel);
2522

    
2523
            // stmnt.close();
2524
        }
2525
        catch (SQLException se) {
2526
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
2527
                se);
2528
            throw new DriverException(se);
2529
        }
2530

    
2531
        // this method returns the statement too, so that it can be closed afterwards
2532
        _resp[0] = _rs;
2533
        _resp[1] = _stmnt;
2534

    
2535
        return _resp;
2536
    }
2537

    
2538
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2539
        String resp = "";
2540

    
2541
        try {
2542
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2543
            String mdsys_sdo_ordinate_array = "";
2544
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2545

    
2546
            for (int i = 0; i < vertices.length; i++) {
2547
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2548
                    vertices[i].doubleValue() + ", ";
2549
            }
2550

    
2551
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2552
                    mdsys_sdo_ordinate_array.length() - 2);
2553
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2554
                mdsys_sdo_ordinate_array + ")";
2555

    
2556
            String aux = "";
2557

    
2558
            if (hasSrid) {
2559
                aux = oracleSRID;
2560

    
2561
                if (_isGeogCS) {
2562
                    aux = "0";
2563
                }
2564
            }
2565
            else {
2566
                aux = "null";
2567
            }
2568

    
2569
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
2570
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
2571
                ")";
2572
        }
2573
        catch (Exception ex) {
2574
            System.err.println("Error while getting sdo contructor: " +
2575
                ex.getMessage());
2576
        }
2577

    
2578
        return resp;
2579
    }
2580

    
2581
    private String getIdsQueryWhereClause(boolean with_where) {
2582
                String resp = "";
2583

    
2584
                String _where = "";
2585
                if (with_where) _where = " where ";
2586

    
2587
                if (workingAreaInTablesCSStruct == null) {
2588
                        if (emptyWhereClause) {
2589
                                // return "select rowid from " + getTableName();
2590
                        } else {
2591
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
2592
                                                + ")";
2593
                        }
2594
                } else {
2595
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
2596
                                        oracleSRID, tableHasSrid, isGeogCS);
2597

    
2598
                        if (emptyWhereClause) {
2599
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
2600
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2601
                        } else {
2602
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
2603
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
2604
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2605
                        }
2606
                }
2607

    
2608
                // resp = resp + " order by rowid";
2609
                return resp;
2610
        }
2611

    
2612
    public String getIdAndElemInfoFullResulltSetQuery() {
2613
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
2614
            getTableName() + " c";
2615

    
2616
        resp = resp + getIdsQueryWhereClause(true);
2617
        return resp;
2618
    }
2619

    
2620
    private String getSearchId() {
2621
        if (emptyWhereClause) {
2622
            return "select " + getStandardSelectExpression() + ", c." +
2623
            geoColName + " from " + getTableName() + " c where rowid = ?";
2624
        }
2625
        else {
2626
            return "select " + getStandardSelectExpression() + ", c." +
2627
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
2628
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
2629
        }
2630
    }
2631

    
2632
    public int getShapeType() {
2633
        return shapeType;
2634
    }
2635

    
2636
    private String getWhereClauseWithoutWhere() {
2637
        String resp = "";
2638
        String old = getLyrDef().getWhereClause();
2639
        resp = old;
2640

    
2641
        if (old.length() <= 6) {
2642
            return old;
2643
        }
2644

    
2645
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2646
            resp = resp.substring(6, resp.length());
2647
        }
2648

    
2649
        return resp;
2650
    }
2651

    
2652
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2653
        if (r1.getMaxX() <= r2.getMinX()) {
2654
            return null;
2655
        }
2656

    
2657
        if (r2.getMaxX() <= r1.getMinX()) {
2658
            return null;
2659
        }
2660

    
2661
        if (r1.getMaxY() <= r2.getMinY()) {
2662
            return null;
2663
        }
2664

    
2665
        if (r2.getMaxY() <= r1.getMinY()) {
2666
            return null;
2667
        }
2668

    
2669
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2670
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2671
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2672
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2673

    
2674
        double w = maxx - minx;
2675
        double h = maxy - miny;
2676

    
2677
        return new Rectangle2D.Double(minx, miny, w, h);
2678
    }
2679

    
2680
    private static int maxSizeForFieldType(int _type) {
2681
        switch (_type) {
2682
        case Types.VARCHAR:
2683
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2684

    
2685
        case Types.LONGVARCHAR:
2686
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2687
        }
2688

    
2689
        return -1;
2690
    }
2691

    
2692
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2693
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2694

    
2695
        switch (fieldDesc.getFieldType()) {
2696
        case Types.SMALLINT:
2697
            aux = "NUMBER(5, 0)";
2698

    
2699
            break;
2700

    
2701
        case Types.INTEGER:
2702
            aux = "NUMBER(10, 0)";
2703

    
2704
            break;
2705

    
2706
        case Types.BIGINT:
2707
            aux = "NUMBER(38, 0)";
2708

    
2709
            break;
2710

    
2711
        case Types.BOOLEAN:
2712
            aux = "NUMBER(1, 0)";
2713

    
2714
            break;
2715

    
2716
        case Types.DECIMAL:
2717
            aux = "NUMBER";
2718

    
2719
            break;
2720

    
2721
        case Types.NUMERIC:
2722
            aux = "NUMBER";
2723

    
2724
            break;
2725

    
2726
        case Types.DOUBLE:
2727
            aux = "FLOAT";
2728

    
2729
            break;
2730

    
2731
        case Types.FLOAT:
2732
            aux = "FLOAT";
2733

    
2734
            break;
2735

    
2736
        case Types.CHAR:
2737
            aux = "CHAR(1 BYTE)";
2738

    
2739
            break;
2740

    
2741
        case Types.VARCHAR:
2742
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2743

    
2744
            break;
2745

    
2746
        case Types.LONGVARCHAR:
2747
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2748

    
2749
            break;
2750
        }
2751

    
2752
        return aux;
2753
    }
2754

    
2755
    // -----------------------------------------------------------
2756
    // -----------------------------------------------------------
2757
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2758
        return "DROP TABLE " + dbLayerDef.getTableName() +
2759
        " CASCADE CONSTRAINTS";
2760
    }
2761

    
2762
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2763
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2764

    
2765
        String type = "";
2766
        String name = "";
2767

    
2768
        String resp = "CREATE TABLE " + dbLayerDef.getTableName() + " ( ";
2769

    
2770
        for (int i = 0; i < flds.length; i++) {
2771
            name = flds[i].getFieldName();
2772

    
2773
            // -------------- FORBIDDEN FIELD NAMES -----------------
2774
            if (!isOracleAllowedFieldname(name)) {
2775
                continue;
2776
            }
2777

    
2778
            // ------------------------------------------------------
2779
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
2780
            }
2781
            else {
2782
                name = getValidOracleID(name, i);
2783
                resp = resp + "\"" + name + "\" ";
2784
                type = fieldTypeToSqlStringType(flds[i]);
2785
                resp = resp + type + ", ";
2786
            }
2787
        }
2788

    
2789
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2790
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2791
        resp = resp + ", ";
2792

    
2793
        String pk = "CONSTRAINT " + getDerivedNAme(dbLayerDef.getTableName(), "PK") +
2794
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD +
2795
            "\") ENABLE";
2796

    
2797
        resp = resp + pk + " )";
2798

    
2799
        return resp;
2800
    }
2801

    
2802
    private static String getDerivedNAme(String tname, String suffix) {
2803

    
2804
            int ind = tname.lastIndexOf(".");
2805
            if (ind == -1) {
2806

    
2807
                    int l = Math.min(28, tname.length());
2808
                    return tname.substring(0, l) + "_" + suffix;
2809

    
2810
            } else {
2811

    
2812
                    String pre = tname.substring(0, ind);
2813
                    String post = tname.substring(ind + 1, tname.length());
2814
                    int lpost = Math.min(24, post.length());
2815
                    int lpre = Math.min(3, pre.length());
2816
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
2817
            }
2818

    
2819
    }
2820

    
2821
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2822
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
2823
            " ON " + dbLayerDef.getTableName() + " (\"" +
2824
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
2825
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2826

    
2827
        return resp;
2828
    }
2829

    
2830
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2831

    
2832
            String tname = dbLayerDef.getTableName();
2833
            int ind = tname.lastIndexOf(".");
2834
            if (ind != -1) {
2835
                    String schema = tname.substring(0, ind);
2836
                    tname = tname.substring(ind + 1, tname.length());
2837
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2838
            " WHERE TABLE_NAME = '" + tname + "' AND OWNER = '" + schema + "'";
2839

    
2840
            } else{
2841
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2842
            " WHERE TABLE_NAME = '" + tname + "'";
2843
            }
2844
    }
2845

    
2846
    /**
2847
     * UTility method to get the SQL sentence needed to update the geographic metadata table
2848
     * with a new bounding box and SRS
2849
     *
2850
     * @param tName table name
2851
     * @param ora_srid new SRS
2852
     * @param bbox new bounding box
2853
     * @param dim geometries dimension
2854
     * @param withsrid False if the SRS is set to NULL. True otherwise.
2855
     * @return the SQL sentence to perform the update
2856
     */
2857
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
2858
        Rectangle2D bbox, int dim, boolean withsrid) {
2859
        String[] dim_name = new String[dim];
2860
        double tolerance = 0.5;
2861

    
2862
        if (ora_srid.compareTo(GEODETIC_SRID) == 0) {
2863
            dim_name[0] = "LONGITUDE";
2864
            dim_name[1] = "LATITUDE";
2865
        }
2866
        else {
2867
            dim_name[0] = "X";
2868
            dim_name[1] = "Y";
2869

    
2870
            if (dim > 2) {
2871
                dim_name[2] = "Z";
2872

    
2873
                if (dim > 3) {
2874
                    dim_name[3] = "T";
2875
                }
2876
            }
2877
        }
2878

    
2879
        String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " " +
2880
            " ( OWNER, TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
2881
            + "'" + schema + "', "
2882
            + "'" + tName + "', "
2883
            + "'" + DEFAULT_GEO_FIELD + "', " +
2884
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2885
            bbox.getMinX() + ", " + bbox.getMaxX() + ", " + tolerance + " ), " +
2886
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + bbox.getMinY() + ", " +
2887
            bbox.getMaxY() + ", " + tolerance + " ))";
2888

    
2889
        if (dim > 2) {
2890
            resp = resp.substring(0, resp.length() - 1) + ",";
2891
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
2892
                "', 0.0, 100.0, " + tolerance + " ))";
2893

    
2894
            if (dim > 3) {
2895
                resp = resp.substring(0, resp.length() - 1) + ",";
2896
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
2897
                    "', 0.0, 100.0, " + tolerance + " ))";
2898
            }
2899
        }
2900

    
2901
        if (withsrid) {
2902
            resp = resp + ", " + ora_srid + " )";
2903
        }
2904
        else {
2905
            resp = resp + ", NULL )";
2906
        }
2907

    
2908
        return resp;
2909
    }
2910

    
2911
    /**
2912
     * Gets the SQL sentence to perform an insertion.
2913
     *
2914
     * @param feat feature to be added
2915
     * @param dbLayerDef layer definition
2916
     * @param rowInd row index
2917
     * @param _geoColName geometry field name
2918
     * @return the SQL sentence to perform the insertion
2919
     */
2920
    public static String getRowInsertSql(IFeature feat,
2921
        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2922
        String name = "";
2923
        int ftype = -1;
2924
        String aux_orig = "";
2925
        String aux_limited = "";
2926
        String aux_quotes_ok = "";
2927

    
2928
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2929

    
2930
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
2931

    
2932
        for (int i = 0; i < fieldsDescr.length; i++) {
2933
            name = fieldsDescr[i].getFieldName();
2934
            ftype = fieldsDescr[i].getFieldType();
2935

    
2936
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2937
            if (!isOracleAllowedFieldname(name)) continue;
2938
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2939
            // ------------------------------------------------------
2940
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2941
            }
2942
            else {
2943
                name = getValidOracleID(name, i);
2944
                resp = resp + "\"" + name + "\"" + " , ";
2945
            }
2946
        }
2947

    
2948
        resp = resp + _geoColName + " ) VALUES ( ";
2949

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

    
2954
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2955
            if (!isOracleAllowedFieldname(name)) continue;
2956
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2957
            // ------------------------------------------------------
2958
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2959

    
2960
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2961
            }
2962
            else {
2963
                if (name.compareToIgnoreCase(
2964
                            OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2965
                    resp = resp + rowInd + " , ";
2966
                }
2967
                else {
2968
                    Value attValue = feat.getAttribute(i);
2969

    
2970
                    if (attValue.toString() == null) {
2971
                        resp = resp + "NULL , ";
2972
                    }
2973
                    else {
2974
                        if (sur.length() > 0) {
2975
                            aux_orig = attValue.toString();
2976
                            aux_limited = cropStringValue(aux_orig, i,
2977
                                    fieldsDescr);
2978
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2979

    
2980
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2981
                        }
2982
                        else {
2983
                            String _aux = attValue.toString();
2984

    
2985
                            if (_aux.length() == 0) {
2986
                                _aux = "NULL";
2987
                            }
2988

    
2989
                            resp = resp + _aux + " , ";
2990
                        }
2991
                    }
2992
                }
2993
            }
2994
        }
2995

    
2996
        resp = resp + " ? )";
2997
        /*
2998
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
2999
                        + "2002, NULL, NULL,"
3000
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
3001
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
3002
                        + "), ? )";
3003

3004
        resp = resp + " " + test + " )";
3005
        */
3006
        return resp;
3007
    }
3008

    
3009
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
3010

    
3011
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
3012
                    return true;
3013
            }
3014

    
3015
            if ((ftype == Types.BINARY)
3016
                || (ftype == Types.ARRAY)
3017
                || (ftype == Types.BLOB)
3018
                || (ftype == Types.CLOB)
3019
                || (ftype == Types.STRUCT)
3020
            ) {
3021
                    return false;
3022
            }
3023
                return true;
3024
        }
3025

    
3026
        /**
3027
     * Gets the SQL sentence to perform an update.
3028
     *
3029
     * @param feat feature to be updated
3030
     * @param dbLayerDef layer definition
3031
     * @param rowInd row index
3032
     * @param geoFieldName geometry field name
3033
     * @return the SQL sentence to perform the update
3034
     */
3035
    public static String getRowUpdateSql(IFeature feat,
3036
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
3037
        String name = "";
3038
        String aux_orig = "";
3039
        String aux_limited = "";
3040
        String aux_quotes_ok = "";
3041

    
3042
        Value[] atts = feat.getAttributes();
3043
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
3044

    
3045
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
3046

    
3047
        for (int i = 0; i < _fieldsDescr.length; i++) {
3048
            name = _fieldsDescr[i].getFieldName();
3049

    
3050
            // -------------- FORBIDDEN FIELD NAMES -----------------
3051
            if (!isOracleAllowedFieldname(name)) {
3052
                logger.info("Field: " + name + " will not be updated.");
3053
                continue;
3054
            }
3055

    
3056
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
3057
                        geoFieldName)) {
3058
                logger.info("Field: " + name + " will not be updated (it's a struct).");
3059
                continue;
3060
            }
3061

    
3062
            // ------------------------------------------------------
3063
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
3064
                // resp = resp + "\"" + name + "\"" + " = ?, ";
3065
            }
3066
            else {
3067
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
3068
                aux_orig = atts[i].toString();
3069
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
3070
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
3071
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
3072
                    sur + ", ";
3073
            }
3074
        }
3075

    
3076
        resp = resp + "\"" + geoFieldName + "\" = ?";
3077
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
3078

    
3079
        return resp;
3080
    }
3081

    
3082
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
3083
        String geoname) {
3084
        if (ftype == Types.STRUCT) {
3085
            if (fldname.compareToIgnoreCase(geoname) != 0) {
3086
                return true;
3087
            }
3088
        }
3089

    
3090
        return false;
3091
    }
3092

    
3093
    /**
3094
     * Gets the SQL sentence to perform a deletion.
3095
     *
3096
     * @param dbLayerDef layer definition
3097
     * @param id ROWID of the record to be deleted
3098
     * @return the SQL sentence to perform the deletion
3099
     */
3100
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
3101
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
3102
        resp = resp + " WHERE ROWID ='" + id + "'";
3103

    
3104
        return resp;
3105
    }
3106

    
3107
    private static String cropStringValue(String orig_val, int i,
3108
        FieldDescription[] _flds) {
3109
        if (orig_val == null) {
3110
            return "NULL";
3111
        }
3112

    
3113
        int tpe = _flds[i].getFieldType();
3114
        int max_size = maxSizeForFieldType(tpe);
3115

    
3116
        if (max_size == -1) {
3117
            return orig_val;
3118
        }
3119

    
3120
        int or_size = orig_val.length();
3121

    
3122
        if (or_size <= max_size) {
3123
            return orig_val;
3124
        }
3125

    
3126
        return orig_val.substring(0, max_size);
3127
    }
3128

    
3129
    private static String avoidQuoteProblem(String str) {
3130
        return str.replaceAll("'", "''");
3131
    }
3132

    
3133
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3134
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3135
            return "";
3136
        }
3137

    
3138
        return "'";
3139
    }
3140

    
3141
    /**
3142
     * Utility function to translate a SRS code from EPSG to Oracle.
3143
     * Uses a datasource based on a DBF file.
3144
     *
3145
     * @param epsg the EPSG code
3146
     * @return the Oracle code
3147
     */
3148
    public static String epsgSridToOracleSrid(String epsg) throws Exception {
3149
        String resp = "8307";
3150

    
3151
        // --------------------------------------------
3152
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3153
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3154
        DataSource ds = null;
3155

    
3156
        try {
3157
            ds = LayerFactory.getDataSourceFactory()
3158
                             .executeSQL(sql,
3159
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3160

    
3161
            if (ds.getRowCount() == 0) {
3162
                logger.error("EPSG code not found in table: " + epsg);
3163
                throw new Exception("Unknown EPSG: " + epsg);
3164
            }
3165

    
3166
            if (ds.getRowCount() > 1) {
3167
                logger.error("===============");
3168
                logger.error(
3169
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
3170
                    epsg);
3171

    
3172
                for (int i = 0; i < ds.getRowCount(); i++) {
3173
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3174

    
3175
                    if (i == 0) {
3176
                        resp = "" + aux;
3177
                    }
3178

    
3179
                    logger.error("" + aux);
3180
                }
3181

    
3182
                logger.error("===============");
3183

    
3184
                return resp;
3185
            }
3186

    
3187
            resp = "" +
3188
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3189
        }
3190
        catch (Exception pe) {
3191
            logger.error("Error with SQL statement. " + pe.getMessage());
3192
        }
3193

    
3194
        return resp;
3195
    }
3196

    
3197
    /**
3198
     * Utility function to translate a SRS code from Oracle to EPSG.
3199
     * Uses a datasource based on a DBF file.
3200
     *
3201
     * @param ora the Oracle code
3202
     * @return the EPSG code
3203
     */
3204
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3205
        String resp = "4326";
3206

    
3207
        // --------------------------------------------
3208
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3209
            " where ORACLE = " + ora + ";";
3210
        DataSource ds = null;
3211

    
3212
        try {
3213
            ds = LayerFactory.getDataSourceFactory()
3214
                             .executeSQL(sql,
3215
                    DataSourceFactory.AUTOMATIC_OPENING);
3216

    
3217
            if (ds.getRowCount() == 0) {
3218
                logger.error("Oracle Spatial code not found in table: " + ora);
3219
                throw new Exception("Unknown Oracle code: " + ora);
3220
            }
3221

    
3222
            if (ds.getRowCount() > 1) {
3223
                logger.error("===============");
3224
                logger.error(
3225
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3226
                    ora);
3227

    
3228
                for (int i = 0; i < ds.getRowCount(); i++) {
3229
                    String aux = "" +
3230
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3231

    
3232
                    if (i == 0) {
3233
                        resp = aux;
3234
                    }
3235

    
3236
                    logger.error("" + aux);
3237
                }
3238

    
3239
                logger.error("===============");
3240

    
3241
                return resp;
3242
            }
3243

    
3244
            resp = "" +
3245
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3246
        }
3247
        catch (Exception pe) {
3248
            logger.error("Error with SQL statement. " + pe.getMessage());
3249
        }
3250

    
3251
        return resp;
3252
    }
3253

    
3254
    /**
3255
     * This methos creates the datasource used to translate the SRS codes:
3256
     * EPSG <--> Oracle.
3257
     *
3258
     * It's called from several places, so checks that the datasource does not exist.
3259
     */
3260

    
3261

    
3262
    /**
3263
     * Utility method to get a valid Oracle identifier (in terms of length)
3264
     *
3265
     * @param str Proposed string
3266
     * @param ind field index of the given field name (used by the method to
3267
     * improve the renaming)
3268
     * @return an acceptable oracle identifier.
3269
     */
3270
    public static String getValidOracleID(String str, int ind) {
3271
        if (str.length() <= MAX_ID_LENGTH) {
3272
            return str;
3273
        }
3274

    
3275
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3276
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3277
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3278
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3279
        resp = resp + "_" + (ind % 1000);
3280

    
3281
        return resp;
3282
    }
3283

    
3284
    private static ArrayList ensureSensibleShell(ArrayList cc) {
3285
        if (sameCoordinate((Coordinate) cc.get(0),
3286
                    (Coordinate) cc.get(cc.size() - 1))) {
3287
            if (cc.size() == 2) {
3288
                ArrayList resp = new ArrayList();
3289
                resp.add(cc.get(0));
3290

    
3291
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3292
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3293
                resp.add(newcoo);
3294

    
3295
                newcoo = new Coordinate((Coordinate) cc.get(0));
3296
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3297
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
3298
                resp.add(newcoo);
3299

    
3300
                resp.add(cc.get(0));
3301

    
3302
                return resp;
3303
            }
3304

    
3305
            if (cc.size() == 3) {
3306
                cc.remove(1);
3307

    
3308
                return ensureSensibleShell(cc);
3309
            }
3310

    
3311
            return cc;
3312
        }
3313
        else {
3314
            cc.add(cc.get(0));
3315

    
3316
            return cc;
3317
        }
3318
    }
3319

    
3320
    private static ArrayList ensureSensibleHole(ArrayList cc) {
3321
        if (sameCoordinate((Coordinate) cc.get(0),
3322
                    (Coordinate) cc.get(cc.size() - 1))) {
3323
            if (cc.size() == 2) {
3324
                ArrayList resp = new ArrayList();
3325
                resp.add(cc.get(0));
3326

    
3327
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3328
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3329
                resp.add(newcoo);
3330

    
3331
                newcoo = new Coordinate((Coordinate) cc.get(0));
3332
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3333
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3334
                resp.add(newcoo);
3335

    
3336
                resp.add(cc.get(0));
3337

    
3338
                return resp;
3339
            }
3340

    
3341
            if (cc.size() == 3) {
3342
                cc.remove(1);
3343

    
3344
                return ensureSensibleHole(cc);
3345
            }
3346

    
3347
            return cc;
3348
        }
3349
        else {
3350
            cc.add(cc.get(0));
3351

    
3352
            return cc;
3353
        }
3354
    }
3355

    
3356
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
3357
        if (cc.size() == 2) {
3358
            if (sameCoordinate((Coordinate) cc.get(0),
3359
                        (Coordinate) cc.get(cc.size() - 1))) {
3360
                ArrayList resp = new ArrayList();
3361
                resp.add(cc.get(0));
3362

    
3363
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3364
                newc.x = newc.x + IRRELEVANT_DISTANCE;
3365
                resp.add(newc);
3366

    
3367
                return resp;
3368
            }
3369
        }
3370

    
3371
        return cc;
3372
    }
3373

    
3374
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3375
        if (c1.x != c2.x) {
3376
            return false;
3377
        }
3378

    
3379
        if (c1.y != c2.y) {
3380
            return false;
3381
        }
3382

    
3383
        return true;
3384
    }
3385

    
3386
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3387
        if (cc.size() == 2) {
3388
            return null;
3389
        }
3390

    
3391
        if (cc.size() == 3) {
3392
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3393
                return null;
3394
            }
3395

    
3396
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3397
                return null;
3398
            }
3399

    
3400
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3401
                return null;
3402
            }
3403

    
3404
            cc.add(cc.get(0));
3405

    
3406
            return cc;
3407
        }
3408

    
3409
        if (!sameCoordinate((Coordinate) cc.get(0),
3410
                    (Coordinate) cc.get(cc.size() - 1))) {
3411
            cc.add(cc.get(0));
3412
        }
3413

    
3414
        return cc;
3415
    }
3416

    
3417
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3418
        Coordinate[] p = new Coordinate[4];
3419
        p[0] = c;
3420

    
3421
        Coordinate nc = new Coordinate(c);
3422
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3423

    
3424
        Coordinate nc2 = new Coordinate(nc);
3425
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3426
        p[1] = nc;
3427
        p[2] = nc2;
3428
        p[3] = new Coordinate(c);
3429

    
3430
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3431
        LinearRing ls = new LinearRing(cs, geomFactory);
3432
        Polygon po = new Polygon(ls, null, geomFactory);
3433
        Polygon[] pos = new Polygon[1];
3434
        pos[0] = po;
3435

    
3436
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3437

    
3438
        return mpo;
3439
    }
3440

    
3441
    public String getSourceProjection() {
3442
        // TODO Auto-generated method stub
3443
        if (tableHasSrid) {
3444
            return epsgSRID;
3445
        }
3446

    
3447
        return destProj;
3448
    }
3449

    
3450
    public String getDestProjection() {
3451
        return destProj;
3452
    }
3453

    
3454
    public void setDestProjection(String toEPSG) {
3455
        destProj = toEPSG;
3456
        try {
3457
                        destProjOracle = epsgSridToOracleSrid(destProj);
3458
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3459

    
3460
                } catch (Exception e) {
3461
                        logger.error("Unknown EPSG code: " + destProj);
3462
                        destProjOracle = oracleSRID;
3463
                        isDestGeogCS = false;
3464
                }
3465

    
3466
    }
3467

    
3468
    public String getDestProjectionOracleCode() {
3469
            return destProjOracle;
3470
    }
3471

    
3472
    public boolean getIsDestProjectionGeog() {
3473
            return isDestGeogCS;
3474
    }
3475

    
3476
    public String getTableProjectionOracleCode() {
3477
            return oracleSRID;
3478
    }
3479

    
3480
    public boolean canReproject(String toEPSGdestinyProjection) {
3481
        return false;
3482
    }
3483

    
3484
    /**
3485
     * Utility function. Says whether a given field name can be a user field name
3486
     * or not (for example, "ROWID" is not a valid one because it's a system
3487
     * reserved word).
3488
     *
3489
     * @param str proposed firld name
3490
     * @return whether it is valid or not for Oracle databases
3491
     */
3492
    private static boolean isOracleAllowedFieldname(String str) {
3493
        if (str.compareToIgnoreCase("rowid") == 0) {
3494
            return false;
3495
        }
3496

    
3497
        if (str.compareToIgnoreCase("rownum") == 0) {
3498
            return false;
3499
        }
3500

    
3501
        return true;
3502
    }
3503

    
3504
    public Hashtable getHashRelate() {
3505
        return hashRelate;
3506
    }
3507

    
3508
    public void setHashRelate(Hashtable m) {
3509
        hashRelate = m;
3510
    }
3511

    
3512
    public void setNumReg(int n) {
3513
        numReg = n;
3514
    }
3515

    
3516
    private int[] getRandomSample(int maxn_one_based, int n) {
3517
        int[] resp = new int[n];
3518

    
3519
        if (maxn_one_based <= n) {
3520
            resp = new int[maxn_one_based];
3521

    
3522
            for (int i = 0; i < maxn_one_based; i++) {
3523
                resp[i] = i;
3524
            }
3525
        }
3526
        else {
3527
            Random rnd = new Random();
3528

    
3529
            for (int i = 0; i < n; i++) {
3530
                resp[i] = rnd.nextInt(maxn_one_based);
3531
            }
3532
        }
3533

    
3534
        return resp;
3535
    }
3536

    
3537
    private String getRowIdRestrictionCondition(int nrecords) {
3538
        int[] zero_based_rows = getRandomSample(nrecords,
3539
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3540
        String resp = "(";
3541
        Object aux = "";
3542
        ROWID riaux = null;
3543

    
3544
        for (int i = 0; i < zero_based_rows.length; i++) {
3545
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3546
            riaux = (ROWID) aux;
3547
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3548
        }
3549

    
3550
        resp = resp.substring(0, resp.length() - 4);
3551
        resp = resp + ")";
3552

    
3553
        return resp;
3554
    }
3555

    
3556
    private Rectangle2D getBoundingFromSample(int n_max) {
3557
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3558
            " WHERE " + getRowIdRestrictionCondition(n_max);
3559
        STRUCT auxstr = null;
3560
        IGeometry theGeom = null;
3561
        Rectangle2D resp = null;
3562

    
3563
        try {
3564
            Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
3565
            ResultSet rs = st.executeQuery(_qry);
3566

    
3567
            if (rs.next()) {
3568
                auxstr = (STRUCT) rs.getObject(1);
3569

    
3570
                if (auxstr != null) {
3571
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3572

    
3573
                    if (resp == null) {
3574
                        resp = theGeom.getBounds2D();
3575
                    }
3576
                    else {
3577
                        resp.add(theGeom.getBounds2D());
3578
                    }
3579
                }
3580

    
3581
                while (rs.next()) {
3582
                    auxstr = (STRUCT) rs.getObject(1);
3583

    
3584
                    if (auxstr != null) {
3585
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3586

    
3587
                        if (resp == null) {
3588
                            resp = theGeom.getBounds2D();
3589
                        }
3590
                        else {
3591
                            resp.add(theGeom.getBounds2D());
3592
                        }
3593
                    }
3594
                }
3595

    
3596
                rs.close();
3597
                st.close();
3598
            }
3599
            else {
3600
                throw new SQLException("Empty resultset from this query: " +
3601
                    _qry);
3602
            }
3603
        }
3604
        catch (SQLException se) {
3605
            System.err.println("Error while getting sample full extent: " +
3606
                se.getMessage());
3607
        }
3608

    
3609
        if (resp == null) {
3610
            logger.warn(
3611
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3612

    
3613
            return new Rectangle2D.Double(-180, -90, 360, 180);
3614
        }
3615

    
3616
        return resp;
3617
    }
3618

    
3619
    /**
3620
     * Does what it says, puts the LinearRing in counter clock wise
3621
     * order.
3622
     * @param ls The ring to set.
3623
     * @param gf a GeometryFactory object
3624
     * @return A new ring in CCW order.
3625
     *
3626
     */
3627
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3628
        Coordinate[] cc = ls.getCoordinates();
3629

    
3630
        if (CGAlgorithms.isCCW(cc)) {
3631
            return gf.createLinearRing(cc);
3632
        }
3633
        else {
3634
            if (ls instanceof LinearRing) {
3635
                return reverseRing((LinearRing) ls, gf);
3636
            }
3637
            else {
3638
                return reverseLineString(ls, gf);
3639
            }
3640
        }
3641
    }
3642

    
3643
    /**
3644
     * Does what it says, reverses the order of the Coordinates in the ring.
3645
     * @param lr The ring to reverse.
3646
     * @return A new ring with the reversed Coordinates.
3647
     *
3648
     */
3649
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3650
        int numPoints = lr.getNumPoints() - 1;
3651
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3652

    
3653
        for (int t = numPoints; t >= 0; t--) {
3654
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3655
        }
3656

    
3657
        return gf.createLinearRing(newCoords);
3658
    }
3659

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

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

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

    
3678
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3679
        if (ge instanceof MultiPolygon) {
3680
            MultiPolygon mp = (MultiPolygon) ge;
3681
            int size = ge.getNumGeometries();
3682
            Polygon[] pols = new Polygon[size];
3683

    
3684
            for (int i = 0; i < size; i++)
3685
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3686
                        gf);
3687

    
3688
            return new MultiPolygon(pols, gf);
3689
        }
3690
        else {
3691
            if (ge instanceof Polygon) {
3692
                Polygon p = (Polygon) ge;
3693
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3694
                int nholes = p.getNumInteriorRing();
3695

    
3696
                if (nholes > 0) {
3697
                    LinearRing[] holes = new LinearRing[nholes];
3698

    
3699
                    for (int i = 0; i < nholes; i++) {
3700
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3701
                    }
3702

    
3703
                    return gf.createPolygon(exterior, holes);
3704
                }
3705
                else {
3706
                    return gf.createPolygon(exterior, null);
3707
                }
3708
            }
3709
            else {
3710
                return ge;
3711
            }
3712
        }
3713
    }
3714

    
3715
    /**
3716
     * Converts from IGeometry to STRUCT
3717
     *
3718
     * @param ig the geometry to convert
3719
     * @param _forced_type forced type to use
3720
     * @param _conn connection
3721
     * @param _o_srid  SRS (oracle code)
3722
     * @param withSrid whether this STRUCT has a non-NULL SRS
3723
     * @param agu_bien whether or not to check the correctness of the holes
3724
     * @param _isGeoCS whether the SRS is geodetic or not
3725
     * @return the generated STRUCT
3726
     */
3727
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
3728
        IConnection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
3729
        boolean _isGeoCS) {
3730
        if (ig instanceof FGeometryCollection) {
3731
            FGeometryCollection coll = (FGeometryCollection) ig;
3732

    
3733
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3734
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3735

    
3736
            // logger.error("Collections no soportadas por ahora.");
3737
            // return null;
3738
        }
3739
        else {
3740
            Shape shp = ig.getInternalShape();
3741

    
3742
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3743
                agu_bien, false, _isGeoCS);
3744
        }
3745
    }
3746

    
3747
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3748
        boolean agu_bien, boolean isView) {
3749

    
3750
            if (shp == null) return null;
3751
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3752
            agu_bien, isView, isGeogCS);
3753
    }
3754

    
3755
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3756
        IConnection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3757
        boolean isView, boolean _isGeoCS) {
3758
        int _srid = -1;
3759

    
3760
        if (o_srid.length() > 0) {
3761
            _srid = Integer.parseInt(o_srid);
3762
        }
3763

    
3764
        if (shp == null) {
3765
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3766

    
3767
            return null;
3768
        }
3769

    
3770
        if (shp instanceof Rectangle2D) {
3771
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3772
                _isGeoCS, o_srid, _conn);
3773
        }
3774

    
3775
        try {
3776
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3777
                    _srid, agu_bien, hasSrid);
3778

    
3779
            return the_struct;
3780
        }
3781
        catch (SQLException ex) {
3782
            logger.error("While creating STRUCT: " + ex.getMessage());
3783

    
3784
            return null;
3785
        }
3786
    }
3787

    
3788
    // -------------------------- not ready yet ----------------
3789
    public int getRowIndexByFID(IFeature _fid) {
3790
        if (isNotAvailableYet) {
3791
            return -1;
3792
        }
3793
        else {
3794
            return super.getRowIndexByFID(_fid);
3795
        }
3796
    }
3797

    
3798
    public int getShapeCount() throws IOException {
3799
        if (isNotAvailableYet) {
3800
            return 0;
3801
        }
3802
        else {
3803
            return numReg;
3804
        }
3805
    }
3806

    
3807
    public void setNotAvailableYet(boolean nav) {
3808
        isNotAvailableYet = nav;
3809
    }
3810

    
3811
    // -------------------------------------------------------
3812
    // -------------------------------------------------------
3813
    public String[] getTableNames(IConnection conn, String catalog)
3814
        throws DBException {
3815
        try{
3816
            DatabaseMetaData dbmd = ((ConnectionJDBC)conn).getConnection().getMetaData();
3817
        String[] types = { "TABLE", "VIEW" };
3818
        // String[] types = { "VIEW" };
3819

    
3820
        ResultSet rs = null;
3821
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3822
                    ORACLE_GEOMETADATA_VIEW, types), ((ConnectionJDBC)conn).getConnection());
3823
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3824
//                          ORACLE_GEOMETADATA_VIEW, types);
3825
        TreeMap ret = new TreeMap();
3826

    
3827
        while (rs.next()) {
3828
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
3829
            ret.put(nomCompleto, nomCompleto);
3830
        }
3831

    
3832
        return (String[]) ret.keySet().toArray(new String[0]);
3833
        }catch (SQLException e) {
3834
                        throw new DBException(e);
3835
                }
3836
    }
3837

    
3838
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3839
        throws SQLException {
3840
        String tablename = "";
3841

    
3842

    
3843

    
3844
        if (res.next()) {
3845
            tablename = res.getString("TABLE_NAME");
3846

    
3847
            // debug
3848
            writeMetaTableToLog(con, tablename);
3849

    
3850
            Statement __st = con.createStatement();
3851

    
3852
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3853
                "union (select VIEW_NAME from USER_VIEWS)) " +
3854
                "intersect (select TABLE_NAME from " + tablename + ")";
3855
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
3856
            ResultSet rs = __st.executeQuery(sql);
3857

    
3858
            return rs;
3859
        }
3860
        else {
3861
            logger.error("Error while getting geometry tables.");
3862

    
3863
            return null;
3864
        }
3865
    }
3866

    
3867
    private void writeMetaTableToLog(Connection con, String tname) {
3868

    
3869
            logger.debug("======================================================");
3870
            logger.debug("=     " + ORACLE_GEOMETADATA_VIEW + "     =====================");
3871
            logger.debug("======================================================");
3872

    
3873
            try {
3874
            Statement _stmt = con.createStatement();
3875
            String sql = "SELECT * FROM " + tname;
3876
            ResultSet res = _stmt.executeQuery(sql);
3877
            while (res.next()) {
3878
                    logger.debug("======================================================");
3879
                    logger.debug("OWNER: " + res.getString("OWNER"));
3880
                    logger.debug("TABLE_NAME: " + res.getString("TABLE_NAME"));
3881
                    logger.debug("COLUMN_NAME: " + res.getString("COLUMN_NAME"));
3882
                    logger.debug("SRID: " + res.getString("SRID"));
3883

    
3884
                    ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3885
                    String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3886
                    logger.debug("DIMINFO: " + dinfo);
3887
                    logger.debug("======================================================");
3888

    
3889
            }
3890
            } catch (Throwable th) {
3891

    
3892
            }
3893

    
3894

    
3895

    
3896

    
3897

    
3898
                // TODO Auto-generated method stub
3899

    
3900
        }
3901

    
3902
        /**
3903
     * Gets the field names that can act as row id (always ROWID)
3904
     */
3905
    public String[] getIdFieldsCandidates(IConnection conn, String table_name)
3906
        throws DBException {
3907
            try{
3908
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
3909
            Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3910
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3911
            _rs.close();
3912
            _st.close();
3913

    
3914
            String[] resp = { "ROWID" };
3915
        return resp;
3916
            }catch (SQLException e) {
3917
                        throw new DBException(e);
3918
                }
3919
    }
3920

    
3921
    /**
3922
     * Gets the field names that can act as geometry fields
3923
     * (queries the user's geographic metadata).
3924
     */
3925
    public String[] getGeometryFieldsCandidates(IConnection conn,
3926
        String table_name) throws DBException {
3927
            try{
3928
        Statement _st = ((ConnectionJDBC)conn).getConnection().createStatement();
3929
        String[] tokens = table_name.split("\\u002E", 2);
3930
        String qry;
3931
        if (tokens.length > 1)
3932
        {
3933
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3934
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" +
3935
            tokens[1] + "'";
3936
        }
3937
        else
3938
        {
3939
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3940
            " where TABLE_NAME = " + "'" + table_name + "'";
3941

    
3942
        }
3943
        ResultSet _rs = _st.executeQuery(qry);
3944

    
3945
        ArrayList aux = new ArrayList();
3946

    
3947
        while (_rs.next()) {
3948
            String _geo = _rs.getString("COLUMN_NAME");
3949
            aux.add(_geo);
3950
        }
3951

    
3952
        _rs.close();
3953
        _st.close();
3954

    
3955
        String[] resp = (String[]) aux.toArray(new String[0]);
3956

    
3957
        return checkIndexes(conn, resp, table_name);
3958
            }catch (SQLException e) {
3959
                        throw new DBException(e);
3960
                }
3961
    }
3962

    
3963
    private String[] checkIndexes(IConnection c, String[] all, String long_table_name) throws DBException {
3964

    
3965
            ArrayList good_ones = new ArrayList();
3966
            try{
3967
            String t = long_table_name;
3968
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
3969

    
3970
            for (int i=0; i<all.length; i++) {
3971

    
3972
                String qry = "SELECT SRID, DIMINFO FROM " + ORACLE_GEOMETADATA_VIEW +
3973
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
3974
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
3975

    
3976
                Statement _st = ((ConnectionJDBC)c).getConnection().createStatement();
3977
                ResultSet _rs = _st.executeQuery(qry);
3978
                if (_rs.next()) {
3979
                        String _srid = toString((BigDecimal) _rs.getObject(1));
3980
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
3981
                        int len = diminfo.getOracleArray().length;
3982
                        if (allowsGeoQueries(((ConnectionJDBC)c).getConnection(), long_table_name, all[i], _srid, len)) {
3983
                                good_ones.add(all[i]);
3984
                        }
3985
                }
3986
                _rs.close();
3987
                _st.close();
3988
            }
3989

    
3990
            if (good_ones.size() == 0) {
3991
                    throw new SQLException("no_indexes_on_declared_geo_fields");
3992
            }
3993
            }catch (SQLException e) {
3994
                        throw new DBException(e);
3995
                }
3996
            return (String[]) good_ones.toArray(new String[0]);
3997
    }
3998

    
3999
    private String toString(BigDecimal number) {
4000

    
4001
            if (number == null) return "NULL";
4002
            return "" + number.intValue();
4003
        }
4004

    
4005
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
4006
            String p = getPointConstructor(dims, _srid);
4007
            String qry = "SELECT * FROM " + _t.toUpperCase() + " WHERE (ROWNUM = 1)";
4008
            qry = "SELECT * FROM (" + qry + ") WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'";
4009

    
4010
            try {
4011
                        Statement _st = c.createStatement();
4012
                        ResultSet _rs = _st.executeQuery(qry);
4013
                        _rs.close();
4014
                        _st.close();
4015
                } catch (Exception ex) {
4016
                        return false;
4017
                }
4018
                return true;
4019
        }
4020

    
4021
        private String getPointConstructor(int dims, String _srid) {
4022

    
4023
                String coord = "";
4024
                for (int i=0; i<dims; i++) coord = coord + "0, ";
4025
                coord = coord.substring(0, coord.length() - 2);
4026

    
4027
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
4028
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
4029
        }
4030

    
4031
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
4032

    
4033
            if (l == null) return false;
4034
            if (str == null) return false;
4035

    
4036
            String item = "";
4037
            for (int i=0; i<l.size(); i++) {
4038
                    if (l.get(i) instanceof String) {
4039
                            item = (String) l.get(i);
4040
                            if (item.compareToIgnoreCase(str) == 0) return true;
4041
                    }
4042
            }
4043
            return false;
4044
    }
4045

    
4046
        /**
4047
     * Utility method to check if a given table is empty.
4048
     */
4049
    public boolean isEmptyTable(Connection conn, String tableName) {
4050
        boolean res = true;
4051

    
4052
        try {
4053
            Statement st = conn.createStatement();
4054
            ResultSet rs = null;
4055
            rs = st.executeQuery("select * from " + tableName +
4056
                    " where rownum = 1");
4057
            res = !rs.next();
4058
            rs.close();
4059
            st.close();
4060
        }
4061
        catch (Exception ex) {
4062
            res = true;
4063
        }
4064

    
4065
        return res;
4066
    }
4067

    
4068
    /**
4069
     * Gets all the fields from a table name.
4070
     */
4071
    public String[] getAllFields(IConnection conn, String table_name)
4072
        throws DBException {
4073
            try{
4074
        Statement st = ((ConnectionJDBC)conn).getConnection().createStatement();
4075
        ResultSet rs = st.executeQuery("select * from " + table_name +
4076
                " where rownum = 1");
4077
        ResultSetMetaData rsmd = rs.getMetaData();
4078
        String[] ret = new String[rsmd.getColumnCount()];
4079

    
4080
        for (int i = 0; i < ret.length; i++) {
4081
            ret[i] = rsmd.getColumnName(i + 1);
4082
        }
4083

    
4084
        rs.close();
4085
        st.close();
4086

    
4087
        return ret;
4088
            }catch (SQLException e) {
4089
                        throw new DBException(e);
4090
                }
4091
    }
4092

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

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

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

    
4112
        close();
4113

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

    
4120
    /**
4121
     * Gets Oracle's specific connection string for the given parameters.
4122
     */
4123
    public String getConnectionString(String host, String port, String dbname,
4124
        String user, String pw) {
4125
        String _pw = pw;
4126

    
4127
        if (_pw == null) {
4128
            _pw = "null";
4129
        }
4130

    
4131
        String fullstr = CONN_STR_BEGIN;
4132
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
4133
        fullstr = fullstr + "@" + host.toLowerCase();
4134
        fullstr = fullstr + ":" + port;
4135
        fullstr = fullstr + ":" + dbname.toLowerCase();
4136

    
4137
        return fullstr;
4138
    }
4139

    
4140
    /**
4141
     * Gets the Pracle geometries writer associated with this driver.
4142
     */
4143
    public IWriter getWriter() {
4144
        // on(VectorialEditableDBAdapter.java:290)
4145
        if (writer == null) {
4146
            writer = new OracleSpatialWriter(getRowCount());
4147
            writer.setDriver(this);
4148
            writer.setLyrShapeType(getShapeType());
4149
            writer.setGeoCS(isGeogCS());
4150
            writer.setGeoColName(geoColName);
4151
            writer.setSRID(oracleSRID);
4152

    
4153
            try {
4154
                writer.initialize(getLyrDef());
4155
            }
4156
            catch (EditionException e) {
4157
                logger.error("While initializing OS Writer: " + e.getMessage(),
4158
                    e);
4159
            }
4160

    
4161
            writer.setStoreWithSrid(tableHasSrid);
4162
        }
4163

    
4164
        return writer;
4165
    }
4166

    
4167
    /**
4168
     * Tells whether the SRS is geodetic or not
4169
     * @return whether the SRS is geodetic or not
4170
     */
4171
    public boolean isGeogCS() {
4172
        return isGeogCS;
4173
    }
4174

    
4175
    /**
4176
     * Adds a row id to the inner set od IDs.
4177
     * @param id
4178
     */
4179
    public void addRow(String id) {
4180
        Value aux = ValueFactory.createValue(id);
4181
        Integer intobj = new Integer(numReg);
4182
        hashRelate.put(aux, intobj);
4183
        rowToId.put(intobj, id);
4184

    
4185
        numReg++;
4186
    }
4187

    
4188
    /**
4189
     * Removes a row id to the inner set od IDs.
4190
     * @param id
4191
     */
4192
    public void deleteRow(String id) {
4193
        Value aux = ValueFactory.createValue(id);
4194
        Integer intobj = (Integer) hashRelate.get(aux);
4195
        hashRelate.remove(aux);
4196
        rowToId.remove(intobj);
4197

    
4198
        numReg--;
4199
    }
4200

    
4201
    private String getStandardSelectExpression() {
4202
        if (standardSelectExpressionFalse == null) {
4203
            standardSelectExpressionFalse = "";
4204

    
4205
            String[] flds = getLyrDef().getFieldNames();
4206
            int size = flds.length;
4207

    
4208
            for (int i = 0; i < size; i++) {
4209
                if (i > 0) {
4210
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4211
                        "c.\"" + flds[i] + "\", ";
4212
                }
4213
                else {
4214
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4215
                        flds[i] + ", ";
4216
                }
4217
            }
4218

    
4219
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4220
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4221
                    standardSelectExpressionFalse.length() - 2);
4222
        }
4223

    
4224
        return standardSelectExpressionFalse;
4225
    }
4226

    
4227
    /**
4228
     * Allows the method to decide what to do with the geometry field name
4229
     * (remove/add it from the user selected fields).
4230
     *
4231
     * @param flds
4232
     * @param geof
4233
     * @return the possibly modified field names
4234
     */
4235
    public String[] manageGeometryField(String[] flds, String geof) {
4236
        return addEndIfNotContained(flds, geof);
4237
    }
4238

    
4239
    /**
4240
     * Allows the method to decide what to do with the ID field name
4241
     * (remove/add it from the user selected fields).
4242
     *
4243
     * @param flds
4244
     * @param idf
4245
     * @return the possibly modified field names
4246
     */
4247
    public String[] manageIdField(String[] flds, String idf) {
4248
        return addStartIfNotContained(flds, idf);
4249
    }
4250

    
4251
    private String[] addEndIfNotContained(String[] arr, String item) {
4252
        if (contains(arr, item)) {
4253
            return arr;
4254
        }
4255
        else {
4256
            int size = arr.length;
4257
            String[] resp = new String[size + 1];
4258

    
4259
            for (int i = 0; i < size; i++) {
4260
                resp[i] = arr[i];
4261
            }
4262

    
4263
            resp[size] = item;
4264

    
4265
            return resp;
4266
        }
4267
    }
4268

    
4269
    private String[] addStartIfNotContained(String[] arr, String item) {
4270
        if (contains(arr, item)) {
4271
            return arr;
4272
        }
4273
        else {
4274
            int size = arr.length;
4275
            String[] resp = new String[size + 1];
4276

    
4277
            for (int i = 1; i <= size; i++) {
4278
                resp[i] = arr[i];
4279
            }
4280

    
4281
            resp[0] = item;
4282

    
4283
            return resp;
4284
        }
4285
    }
4286

    
4287
    private boolean contains(String[] arr, String item) {
4288
        for (int i = 0; i < arr.length; i++) {
4289
            if (arr[i].compareTo(item) == 0) {
4290
                return true;
4291
            }
4292
        }
4293

    
4294
        return false;
4295
    }
4296

    
4297
    /**
4298
     * This method is called when the user removes the layer from the view.
4299
     * If the IDs were being loaded, the driver will check this field and will
4300
     * let the thread 'die' quietly.
4301
     *
4302
     */
4303
    public void remove() {
4304
        cancelIDLoad = true;
4305
    }
4306

    
4307
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4308
            // if (!isgeodetic) return true;
4309
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true;
4310
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true;
4311
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true;
4312
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true;
4313
            return false;
4314
    }
4315

    
4316
    private Rectangle2D getFastEstimatedGeodeticExtent(
4317
                    String tname, String gfield, IConnection c, int sample_size, double enlargement) {
4318

    
4319
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4320
            Rectangle2D resp_aux = null;
4321
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4322
            ResultSet _rs = null;
4323

    
4324
            try {
4325
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
4326
                        _rs = _st.executeQuery();
4327
                        while (_rs.next()) {
4328
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4329
                                IGeometry ig = getGeometryUsing(aux, false);
4330

    
4331
                                if (ig == null) continue;
4332

    
4333
                                if (resp_aux == null) {
4334
                                        resp_aux = ig.getBounds2D();
4335
                                } else {
4336
                                        resp_aux.add(ig.getBounds2D());
4337
                                }
4338

    
4339
                        }
4340
                } catch (Exception ex) {
4341
                        logger.error("While getting random sample: " + ex.getMessage());
4342
                        return world;
4343
                }
4344

    
4345
                if (resp_aux == null) return world;
4346
                double w = resp_aux.getWidth();
4347
                double h = resp_aux.getHeight();
4348
                double x = resp_aux.getMinX();
4349
                double y = resp_aux.getMinY();
4350

    
4351
                // enlarge 10 times:
4352
                double newx = x - (0.5 * (enlargement - 1)) * w;
4353
                double newy = y - (0.5 * (enlargement - 1)) * w;
4354
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4355
                                enlargement * w,
4356
                                enlargement * h);
4357

    
4358

    
4359
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4360

    
4361
                logger.debug("FAST BB:");
4362
                logger.debug(" min x:" + resp_aux.getMinX());
4363
                logger.debug(" min y:" + resp_aux.getMinY());
4364
                logger.debug("     w:" + resp_aux.getWidth());
4365
                logger.debug("     h:" + resp_aux.getHeight());
4366
                return resp_aux;
4367
    }
4368

    
4369
    private Rectangle2D getEstimatedGeodeticExtent(
4370
                    String tname, String gfield, IConnection c, int sample_size, double enlargement) {
4371

    
4372
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4373

    
4374
            ArrayList ids = new ArrayList();
4375
            int _rnd_index = 0;
4376
            ROWID _id = null;
4377
            Random rnd = new Random(System.currentTimeMillis());
4378

    
4379
            for (int i=0; i<sample_size; i++) {
4380
                    _rnd_index = rnd.nextInt(numReg);
4381
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
4382
                    ids.add(_id.stringValue());
4383
            }
4384

    
4385
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
4386
            for (int i=0; i<ids.size(); i++) {
4387
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR ";
4388
            }
4389
            qry = qry.substring(0, qry.length() - 4) + ")";
4390

    
4391
            Rectangle2D resp_aux = null;
4392
            ResultSet _rs = null;
4393

    
4394
            try {
4395
                        PreparedStatement _st = ((ConnectionJDBC)c).getConnection().prepareStatement(qry);
4396
                        _rs = _st.executeQuery();
4397
                        while (_rs.next()) {
4398
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4399
                                IGeometry ig = getGeometryUsing(aux, false);
4400

    
4401
                                if (ig == null) continue;
4402

    
4403
                                if (resp_aux == null) {
4404
                                        resp_aux = ig.getBounds2D();
4405
                                } else {
4406
                                        resp_aux.add(ig.getBounds2D());
4407
                                }
4408

    
4409
                        }
4410
                } catch (Exception ex) {
4411
                        logger.error("While getting random sample: " + ex.getMessage());
4412
                        return world;
4413
                }
4414

    
4415
                if (resp_aux == null) return world;
4416
                double w = resp_aux.getWidth();
4417
                double h = resp_aux.getHeight();
4418
                double x = resp_aux.getMinX();
4419
                double y = resp_aux.getMinY();
4420

    
4421
                // enlarge 10 times:
4422
                double newx = x - (0.5 * (enlargement - 1)) * w;
4423
                double newy = y - (0.5 * (enlargement - 1)) * w;
4424
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4425
                                enlargement * w,
4426
                                enlargement * h);
4427

    
4428

    
4429
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4430
                return resp_aux;
4431
    }
4432

    
4433
    public void setUserName(String u) {
4434
            userName = u;
4435
    }
4436

    
4437
    public String getUserName() {
4438
            return userName;
4439
    }
4440

    
4441
    public static final int JGeometry_GTYPE_COLLECTION = 4;
4442
    public static final int JGeometry_GTYPE_CURVE = 2;
4443
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
4444
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
4445
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
4446
    public static final int JGeometry_GTYPE_POINT = 1;
4447
    public static final int JGeometry_GTYPE_POLYGON = 3;
4448

    
4449
    // ------------------------------
4450

    
4451
    public XMLEntity getXMLEntity() {
4452
                // ---------------------
4453

    
4454
                XMLEntity xml = new XMLEntity();
4455
                xml.putProperty("className", getClass().getName());
4456

    
4457
                xml.putProperty("catalog", getLyrDef().getCatalogName());
4458

    
4459
                int aux = userName.indexOf("@");
4460
                if (aux != -1)
4461
                        userName = userName.substring(0, aux);
4462
                xml.putProperty("username", userName);
4463

    
4464
                xml.putProperty("driverclass", ORACLE_JAR_FILE_NAME);
4465

    
4466
                xml.putProperty("tablename", getTableName());
4467
                xml.putProperty("fields", lyrDef.getFieldNames());
4468
                xml.putProperty("FID", lyrDef.getFieldID());
4469
                xml.putProperty("THE_GEOM", lyrDef.getFieldGeometry());
4470
                xml.putProperty("whereclause", getWhereClause());
4471
                xml.putProperty("SRID", lyrDef.getSRID_EPSG());
4472

    
4473
                xml.putProperty("host", host);
4474
                xml.putProperty("port", port);
4475
                xml.putProperty("dbName", dbName);
4476
                xml.putProperty("connName", connName);
4477

    
4478
                if (getWorkingArea() != null) {
4479
                        xml.putProperty("minXworkArea", getWorkingArea().getMinX());
4480
                        xml.putProperty("minYworkArea", getWorkingArea().getMinY());
4481
                        xml.putProperty("HworkArea", getWorkingArea().getHeight());
4482
                        xml.putProperty("WworkArea", getWorkingArea().getWidth());
4483
                }
4484

    
4485
                return xml;
4486
        }
4487
    public String[] getTableFields(IConnection conex, String table) throws DBException {
4488
                try{
4489
                Statement st = ((ConnectionJDBC)conex).getConnection().createStatement();
4490
        // ResultSet rs = dbmd.getTables(catalog, null, dbLayerDefinition.getTable(), null);
4491
                ResultSet rs = st.executeQuery("select * from " + table + " LIMIT 1");
4492
                ResultSetMetaData rsmd = rs.getMetaData();
4493

    
4494
                String[] ret = new String[rsmd.getColumnCount()];
4495

    
4496
                for (int i = 0; i < ret.length; i++) {
4497
                        ret[i] = rsmd.getColumnName(i+1);
4498
                }
4499

    
4500
                return ret;
4501
                }catch (SQLException e) {
4502
                        throw new DBException(e);
4503
                }
4504
        }
4505

    
4506
}