Statistics
| Revision:

root / branches / v10 / extensions / extOracleSpatial / src / es / prodevelop / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialDriver.java @ 13991

History | View | Annotate | Download (124 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.FGeometryCollection;
60
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
61
import com.iver.cit.gvsig.fmap.core.FNullGeometry;
62
import com.iver.cit.gvsig.fmap.core.FPoint2D;
63
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
64
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
65
import com.iver.cit.gvsig.fmap.core.FShape;
66
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
67
import com.iver.cit.gvsig.fmap.core.ICanReproject;
68
import com.iver.cit.gvsig.fmap.core.IFeature;
69
import com.iver.cit.gvsig.fmap.core.IGeometry;
70
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
71
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
72
import com.iver.cit.gvsig.fmap.crs.CRSFactory;
73
import com.iver.cit.gvsig.fmap.drivers.DBLayerDefinition;
74
import com.iver.cit.gvsig.fmap.drivers.DefaultDBDriver;
75
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
76
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
77
import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator;
78
import com.iver.cit.gvsig.fmap.drivers.dbf.DBFDriver;
79
import com.iver.cit.gvsig.fmap.edition.EditableAdapter;
80
import com.iver.cit.gvsig.fmap.edition.EditionException;
81
import com.iver.cit.gvsig.fmap.edition.IWriteable;
82
import com.iver.cit.gvsig.fmap.edition.IWriter;
83
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
84
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
85
import com.iver.cit.gvsig.project.documents.table.ProjectTable;
86
import com.iver.cit.gvsig.project.documents.table.ProjectTableFactory;
87
import com.iver.utiles.NumberUtilities;
88

    
89
import com.vividsolutions.jts.algorithm.CGAlgorithms;
90
import com.vividsolutions.jts.geom.Coordinate;
91
import com.vividsolutions.jts.geom.Geometry;
92
import com.vividsolutions.jts.geom.GeometryFactory;
93
import com.vividsolutions.jts.geom.LineString;
94
import com.vividsolutions.jts.geom.LinearRing;
95
import com.vividsolutions.jts.geom.MultiPolygon;
96
import com.vividsolutions.jts.geom.Polygon;
97
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
98

    
99
import oracle.jdbc.OracleConnection;
100

    
101
import oracle.spatial.geometry.JGeometry;
102

    
103
import oracle.sql.ARRAY;
104
import oracle.sql.Datum;
105
import oracle.sql.NUMBER;
106
import oracle.sql.ROWID;
107
import oracle.sql.STRUCT;
108
import oracle.sql.StructDescriptor;
109

    
110
import org.apache.log4j.Logger;
111
import org.cresques.cts.ICoordTrans;
112
import org.cresques.cts.IProjection;
113

    
114
//import org.geotools.data.oracle.sdo.GeometryConverter;
115

    
116
import java.awt.Shape;
117
import java.awt.geom.Point2D;
118
import java.awt.geom.Rectangle2D;
119

    
120
import java.io.File;
121
import java.io.IOException;
122

    
123
import java.sql.Connection;
124
import java.sql.DatabaseMetaData;
125
import java.sql.PreparedStatement;
126
import java.sql.ResultSet;
127
import java.sql.ResultSetMetaData;
128
import java.sql.SQLException;
129
import java.sql.Statement;
130
import java.sql.Types;
131

    
132
import java.text.ParseException;
133

    
134
import java.util.ArrayList;
135
import java.util.HashMap;
136
import java.util.Hashtable;
137
import java.util.Iterator;
138
import java.util.Random;
139
import java.util.TreeMap;
140

    
141

    
142
/**
143
 * Vectorial driver to access Oracle databases geometries.
144
 * Should work on Oracle Locator.
145
 *
146
 * It contains switches to test different modules to perform the
147
 * translation oracle structs --> gvsig geometries:
148
 *
149
 * - Parsing the structs directly.
150
 * - Using Oracle's JGeometry static methods
151
 * - Using Geotools utilities
152
 *
153
 *  (currently, the driver parses the structs directly)
154
 *
155
 * @author jldominguez
156
 *
157
 */
158
public class OracleSpatialDriver extends DefaultDBDriver
159
    implements IDelayedDriver, ICanReproject, IWriteable {
160
    private static Logger logger = Logger.getLogger(OracleSpatialDriver.class.getName());
161
    private static int FETCH_SIZE = 15000;
162

    
163
    // constants 
164
    public static final int GEODETIC_FULLEXTENT_SAMPLE_SIZE = 50;
165
    public static final String GEODETIC_SRID = "8307";
166
    public static final String ASSUMED_ORACLE_SRID = "8307";
167

    
168
    // ------------------------------------------------
169
    public static final String NAME = "Oracle Spatial Database Driver";
170
    public static final int ID_COLUMN_INDEX = 1;
171
    public static final String ORACLE_GEOMETADATA_VIEW = "USER_SDO_GEOM_METADATA";
172
    public static final String ORACLE_EPSG_TABLE_NAME = "ORA_EPSG";
173
    public static final String ORACLE_EPSG_FILE_NAME = "ora_epsg.dbf";
174
    public static final String DEFAULT_GEO_FIELD = "GEOMETRY";
175
    public static final String ORACLE_ID_FIELD = "ROWID";
176
    public static final String DEFAULT_ID_FIELD = "GID";
177
    public static final String ORACLE_GEO_SCHEMA = "MDSYS";
178
    public static final String CONN_STR_BEGIN = "jdbc:oracle:thin:";
179
    public static final int VARCHAR2_STANDARD_SIZE = 80;
180
    public static final int VARCHAR2_LONG_SIZE = 256;
181
    public static final int MAX_ID_LENGTH = 30;
182
    private final static GeometryFactory geomFactory = new GeometryFactory();
183
    public static final double IRRELEVANT_DISTANCE = 0.00000001;
184
        private static final String EXTENSION_DIR_NAME = "com.iver.cit.gvsig.jdbc_spatial";
185

    
186
    static {
187
        try {
188
            Class.forName("oracle.jdbc.driver.OracleDriver");
189
        }
190
        catch (ClassNotFoundException e) {
191
            throw new RuntimeException(e);
192
        }
193
        createOracleEpsgTable();
194
    }
195

    
196
    private OracleSpatialWriter writer = null;
197

    
198
    // utility object to convert geometries.
199
//    private GeometryConverter geotools_conv;
200

    
201
    // switch variable
202
    private boolean use_geotools = false;
203
    private boolean tableHasSrid = true;
204

    
205
    // ------------------------------------------------
206
    private boolean isNotAvailableYet = true;
207
    private IGeometry nullGeom = new FNullGeometry();
208
    private Value nullVal = ValueFactory.createNullValue();
209
    private IdLoaderThread idLoader;
210
    private DriverAttributes drvAtts;
211
    private int[] pkOneBasedIndexes;
212
    private String[] fieldNames;
213
    private String not_restricted_sql = "";
214
    
215
    private Rectangle2D workingAreaInViewsCS = null;
216
    private Rectangle2D workingAreaInTablesCS = null;
217
    private STRUCT workingAreaInTablesCSStruct = null;
218

    
219
    private String idFieldNames;
220
    private int oneBasedGeoColInd = 0;
221
    private int shapeType = -1;
222
    private boolean needsCollectionLayer = true;
223

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

    
229
    // ----------------------------------------------
230
    private boolean cancelIDLoad = false;
231

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

    
242
    // new hash map to perform queries by row number:
243
    private HashMap rowToId = new HashMap();
244
    private String standardSelectExpressionFalse = null;
245
        private String destProjOracle;
246
        private boolean isDestGeogCS = false;
247

    
248
    public OracleSpatialDriver() {
249
        drvAtts = new DriverAttributes();
250
        drvAtts.setLoadedInMemory(false);
251
    }
252

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

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

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

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

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

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

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

    
294
    /**
295
     * Standard initializing method.
296
     */
297
    public void setData(Connection _conn, DBLayerDefinition lyrDef) {
298
        createOracleEpsgTable();
299

    
300
        conn = _conn;
301

    
302
//        geotools_conv = new GeometryConverter((OracleConnection) conn);
303
        lyrDef.setConnection(conn);
304

    
305
        setLyrDef(lyrDef);
306

    
307
        geoColName = lyrDef.getFieldGeometry();
308
        not_restricted_sql = "select " + getStandardSelectExpression() +
309
            " from " + getTableName() + " c ";
310

    
311
        // various metadata settings
312
        // getMetaDataInThisThread();
313
        cleanWhereClause();
314
        loadSdoMetadata();
315
        oneRowMetadata();
316
        
317
        IProjection viewProj = CRSFactory.getCRS("EPSG:" + destProj);
318
        IProjection tableProj = CRSFactory.getCRS("EPSG:" + epsgSRID);
319
        ICoordTrans reprojecter = viewProj.getCT(tableProj);
320

    
321
        workingAreaInViewsCS = lyrDef.getWorkingArea();
322
        if (workingAreaInViewsCS != null) {
323
                workingAreaInTablesCS = reprojecter.convert(workingAreaInViewsCS);
324
        }
325
        workingAreaInTablesCSStruct = shapeToStruct(workingAreaInTablesCS,
326
                FShape.NULL, tableHasSrid, false, true);
327

    
328
        cancelIDLoad = false;
329
        idLoader = new IdLoaderThread(this);
330
        idLoader.start();
331
    }
332

    
333
        /**
334
     * Utility method to load IDs in a different thred, so that gvsig's gui
335
     * does not get blocked.
336
     *
337
     */
338
    public void getMetaDataInThisThread() {
339
        getMetadata();
340
    }
341

    
342
    private void getMetadata() {
343
        setIdRowTable();
344
        
345
        if (!hasRealiableExtent) {
346
                full_Extent = getEstimatedGeodeticExtent(
347
                                getTableName(), geoColName, conn, 20, 1.5);
348
        }
349

    
350

    
351
        if (cancelIDLoad) {
352
            return;
353
        }
354
    }
355

    
356
    private boolean needsCollectionLayer() {
357
        try {
358
            // SELECT DISTINCT(C.GEOM.SDO_GTYPE) FROM COMUICV C
359
            // String qry = "select distinct(c."  + geoColName + ".SDO_GTYPE) from " + getTableName() + " c";
360
            String qry = "select c." + geoColName + ".SDO_ELEM_INFO from " +
361
                getTableName() + " c";
362

    
363
            // SDO_ELEM_INFO
364
            Statement _st = conn.createStatement();
365
            ResultSet _rs = _st.executeQuery(qry);
366

    
367
            ArrayList types = new ArrayList();
368
            int aux = 0;
369

    
370
            ARRAY info_aux;
371
            int[] info_aux_int;
372
            int size;
373

    
374
            while (_rs.next()) {
375
                // aux = _rs.getInt(1);
376
                info_aux = (ARRAY) _rs.getObject(1);
377
                info_aux_int = info_aux.getIntArray();
378
                size = info_aux_int.length / 3;
379

    
380
                for (int i = 0; i < size; i++) {
381
                    aux = info_aux_int[(3 * i) + 1];
382
                }
383

    
384
                types.add(new Integer(aux % 1000));
385

    
386
                if ((aux % 1000) != 3) {
387
                    System.err.println("x");
388
                }
389
            }
390

    
391
            _rs.close();
392
            _st.close();
393

    
394
            boolean resp = hasSeveralGeometryTypes(types, false);
395

    
396
            return resp;
397
        }
398
        catch (Exception se) {
399
            System.err.println("Error while getting SDO metadata: " +
400
                se.getMessage());
401
        }
402

    
403
        return false;
404
    }
405

    
406
    private boolean hasSeveralGeometryTypes(ArrayList tt, boolean are_dims) {
407
        if (tt.size() == 0) {
408
            return false;
409
        }
410

    
411
        HashMap m = new HashMap();
412

    
413
        for (int i = 0; i < tt.size(); i++) {
414
            Integer integ = (Integer) tt.get(i);
415
            int val = integ.intValue();
416

    
417
            if ((val == 4) && (!are_dims)) {
418
                return true;
419
            }
420

    
421
            m.put("" + (val % 4), "a type");
422
        }
423

    
424
        Iterator iter = m.keySet().iterator();
425
        iter.next();
426

    
427
        return iter.hasNext();
428
    }
429

    
430
    private String getOracleSridFromCurrentRecord(ResultSet _rs)
431
        throws SQLException {
432
        Object obj = _rs.getObject("SRID");
433

    
434
        if (obj == null) {
435
            logger.warn("No SRID found for this table.");
436
            tableHasSrid = false;
437

    
438
            return ASSUMED_ORACLE_SRID;
439
        }
440

    
441
        return obj.toString();
442
    }
443

    
444
    private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
445
        throws SQLException {
446
        ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
447

    
448
        if (dim_info_array == null) {
449
            // no full extent found:
450
            return null;
451
        }
452
        else {
453
            Datum[] da = dim_info_array.getOracleArray();
454

    
455
            STRUCT sx = (STRUCT) da[0];
456
            STRUCT sy = (STRUCT) da[1];
457

    
458
            try {
459
                double minx = Double.parseDouble(sx.getAttributes()[1].toString());
460
                double maxx = Double.parseDouble(sx.getAttributes()[2].toString());
461
                double miny = Double.parseDouble(sy.getAttributes()[1].toString());
462
                double maxy = Double.parseDouble(sy.getAttributes()[2].toString());
463

    
464
                if (minx > maxx) {
465
                    double aux = minx;
466
                    minx = maxx;
467
                    maxx = aux;
468
                }
469

    
470
                if (miny > maxy) {
471
                    double aux = miny;
472
                    miny = maxy;
473
                    maxy = aux;
474
                }
475

    
476
                return getRectangle(minx, maxx, miny, maxy);
477

    
478
                // fullExtentJTS = shapeToGeometry(fullExtent);
479
            }
480
            catch (Exception ex) {
481
                System.err.println(
482
                    "Error while getting full extent from metadata table.");
483

    
484
                return null;
485

    
486
                // fullExtentJTS = null;
487
            }
488
        }
489
    }
490

    
491
    private void loadSdoMetadata() {
492
        try {
493
            Statement _st = conn.createStatement();
494
            String qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
495
                " where TABLE_NAME = " + "'" + getTableName() + "'";
496
            ResultSet _rs = _st.executeQuery(qry);
497

    
498
            if (_rs.next()) {
499
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
500

    
501
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
502

    
503
                try {
504
                                        epsgSRID = oracleSridToEpsgSrid(oracleSRID);
505
                                } catch (Exception e) {
506
                                        logger.error("Unknown oracle SRID: " + oracleSRID);
507
                                        tableHasSrid = false;
508
                                }
509
                full_Extent = getFullExtentFromCurrentRecord(_rs);
510
                
511
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS); 
512
                
513
                if (!hasRealiableExtent) {
514
                        full_Extent = getFastEstimatedGeodeticExtent(
515
                                        getTableName(), geoColName, conn, 20, 10);
516
                }
517

    
518
                _rs.close();
519
                _st.close();
520
            }
521
            else {
522
                throw new SQLException("Empty resultset from this query: " +
523
                    qry);
524
            }
525
        }
526
        catch (SQLException se) {
527
            System.err.println("Error while getting SDO metadata: " +
528
                se.getMessage());
529
        }
530
    }
531

    
532
    /**
533
     * Utility method to find out if a coordinate system is geodetic or not.
534
     *
535
     * @param oracleSRID2 the coordinate system's oracle code
536
     * @param thas whether the table has a coordinate system set.
537
     * if not, the method returns false.
538
     * @return whether the coordinate system is geodetic or not.
539
     */
540
    public static boolean getIsGCS(String oracleSRID2, boolean thas) {
541

    
542
        if (!thas) return false;
543
        int ora_cs = 0;
544

    
545
        try {
546
            ora_cs = Integer.parseInt(oracleSRID2);
547
        }
548
        catch (Exception ex) {
549
            return false;
550
        }
551

    
552
        if (((ora_cs >= 8000) && (ora_cs <= 8999)) || (ora_cs == 524288)) {
553
            return true;
554
        } else {
555
                return false;
556
        }
557
    }
558

    
559
    private Rectangle2D getRectangle(double minx, double maxx, double miny,
560
        double maxy) {
561
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
562
                maxy - miny);
563

    
564
        return resp;
565
    }
566

    
567
    private void oneRowMetadata() {
568
        try {
569
            String _sql = "select " + getStandardSelectExpression() + ", c." +
570
                geoColName + " from " + getTableName() + " c ";
571

    
572
            st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
573
                    ResultSet.CONCUR_READ_ONLY);
574

    
575
            ResultSet _rs = st.executeQuery(_sql + " where (rownum = 1)");
576

    
577
            if (_rs.next()) {
578
                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
579
                shapeType = getShapeTypeOfStruct(sample_geo);
580
            }
581
            else {
582
                shapeType = FShape.MULTI;
583
            }
584

    
585
            // -----------------------
586
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
587
            metaData = _rs.getMetaData();
588

    
589
            // geoColInd = _rs.findColumn(geoColName);
590
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
591

    
592
            DatabaseMetaData dbmd = conn.getMetaData();
593
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
594

    
595
            int cnt = metaData.getColumnCount();
596
            fieldNames = new String[cnt];
597

    
598
            for (int i = 0; i < cnt; i++) {
599
                fieldNames[i] = metaData.getColumnName(i + 1);
600
            }
601

    
602
            getIdFieldNames();
603

    
604
            adjustLyrDef();
605

    
606
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan 
607
        }
608
        catch (SQLException se) {
609
            logger.error("While getting metadata. " + se.getMessage());
610
        }
611
    }
612

    
613
    private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
614
        int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue() % 10;
615

    
616
        switch (code) {
617
        case 1:
618
            return FShape.POINT;
619

    
620
        case 2:
621
            return FShape.LINE;
622

    
623
        case 3:
624
            return FShape.POLYGON;
625

    
626
        case 5:
627
            return FShape.MULTIPOINT;
628

    
629
        case 6:
630
            return FShape.LINE;
631

    
632
        case 7:
633
            return FShape.POLYGON;
634
        }
635

    
636
        logger.error("Unknown geometry type: " + code);
637

    
638
        return FShape.NULL;
639
    }
640

    
641
    private String getIdFieldNames() {
642
        try {
643
            idFieldNames = "";
644

    
645
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
646
                idFieldNames = idFieldNames +
647
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
648
            }
649
        }
650
        catch (SQLException se) {
651
        }
652

    
653
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
654

    
655
        return idFieldNames;
656
    }
657

    
658
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
659
        int[] _res = new int[1];
660
        _res[0] = 1;
661

    
662
        return _res;
663
    }
664

    
665
    public String getSqlTotal() {
666
        // TODO Auto-generated method stub
667
        return "";
668
    }
669

    
670
    public String getCompleteWhere() {
671
        // TODO Auto-generated method stub
672
        return "";
673
    }
674

    
675
    /**
676
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
677
     * and uses directly that sentence to query the table).
678
     */
679
    public IFeatureIterator getFeatureIterator(String sql)
680
        throws DriverException {
681
        if (isNotAvailableYet) {
682
            return null;
683
        }
684

    
685
        singleCachedFeatureRowNum = -1;
686

    
687
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
688

    
689
        ResultSet localrs = (ResultSet) rs_st[0];
690
        Statement _st = (Statement) rs_st[1];
691

    
692
        return new OracleSpatialFeatureIterator(this, localrs, _st,
693
            oneBasedGeoColInd, use_geotools);
694
    }
695

    
696
    /**
697
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
698
     */
699
    public String getConnectionStringBeginning() {
700
        // oracle
701
        return CONN_STR_BEGIN;
702
    }
703

    
704
    public void open() throws DriverException {
705
    }
706

    
707
    /**
708
     * Gets Oracle's default port: 1521
709
     */
710
    public int getDefaultPort() {
711
        // oracle port
712
        return 1521;
713
    }
714

    
715
    /**
716
     * Gets the feature iterator for a given rectangle (the view's bounding box)
717
     * and a SRS.
718
     */
719
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
720
        throws DriverException {
721
        if (isNotAvailableYet) {
722
            return null;
723
        } 
724

    
725
        singleCachedFeatureRowNum = -1;
726

    
727
        STRUCT local_st = shapeToStruct(r, FShape.NULL, true, false, true);
728

    
729
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
730

    
731
        ResultSet localrs = (ResultSet) rs_st[0];
732
        Statement _st = (Statement) rs_st[1];
733

    
734
        return new OracleSpatialFeatureIterator(this, localrs, _st,
735
            oneBasedGeoColInd, use_geotools);
736
    }
737

    
738
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
739
        if (workingAreaInTablesCS == null) return r;
740
        return doIntersect(r, workingAreaInTablesCS);
741
    }
742

    
743
    /**
744
     * This method reverts to the one without the fields specification.
745
     * The fields have been selected from the start.
746
     */
747
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
748
        String[] alphaNumericFieldsNeeded) throws DriverException {
749
        if (isNotAvailableYet) {
750
            return null;
751

    
752
            // return emptyIt;
753
        }
754

    
755
        singleCachedFeatureRowNum = -1;
756

    
757
        return getFeatureIterator(r, strEPSG);
758
    }
759

    
760
    public String getGeometryField(String fieldName) {
761
        return fieldName;
762

    
763
        // return "ASBINARY(" + fieldName + ")";
764
    }
765

    
766
    public DriverAttributes getDriverAttributes() {
767
        return drvAtts;
768
    }
769

    
770
    /**
771
     * Gets the requested geometry. Always performs a new query in this case.
772
     * This should be a rare way to get the geometries. The standard way is by using
773
     * the iterators.
774
     */
775
    public IGeometry getShape(int _ind) throws IOException {
776
        if (isNotAvailableYet) {
777
            return nullGeom;
778
        }
779

    
780
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
781

    
782
        String _sql = "select " + geoColName + " from " + getTableName() +
783
            " where rowid = ?";
784

    
785
        try {
786
            java.sql.PreparedStatement ps = conn.prepareStatement(_sql);
787
            ps.setObject(1, r_id);
788

    
789
            // Statement stmnt = conn.createStatement();
790
            ps.execute();
791

    
792
            ResultSet _res = ps.getResultSet();
793

    
794
            if (_res.next()) {
795
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
796
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
797
                _res.close();
798
                ps.close();
799

    
800
                return theGeom;
801
            }
802
            else {
803
                logger.error("Unable to get shape: " + _ind +
804
                    " (probably due to edition)");
805

    
806
                return nullGeom;
807
            }
808
        }
809
        catch (SQLException se) {
810
            throw new IOException("SQLException: " + se.getMessage());
811
        }
812
    }
813

    
814
    public boolean isWritable() {
815
        return true;
816
    }
817

    
818
    public String getName() {
819
        return NAME;
820
    }
821

    
822
    public int[] getPrimaryKeys()
823
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
824
        return pkOneBasedIndexes;
825
    }
826

    
827
    public void write(DataWare dataWare)
828
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
829
    }
830

    
831
    private void setIdRowTable() {
832
        hashRelate = new Hashtable();
833

    
834
        java.sql.PreparedStatement ps = null;
835

    
836
        try {
837
            String _sql = getIdAndElemInfoFullResulltSetQuery();
838

    
839
            logger.debug("SQL para leer ids: " + _sql);
840
            Statement st = null;
841

    
842
            
843
            st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
844
                        ResultSet.CONCUR_READ_ONLY);
845
            
846
            st.setFetchSize(FETCH_SIZE);
847
            logger.info("FETCH_SIZE = " + FETCH_SIZE);
848
            
849
            ResultSet _r = null;
850
            _r = st.executeQuery(_sql);
851

    
852
            ROWID ri = null;
853

    
854
            int row = 0;
855
            String gid;
856
            Value aux = null;
857

    
858
            // ----------------------------------- types init
859
            ArrayList types = new ArrayList();
860
            int types_aux = 0;
861

    
862
            ARRAY info_aux;
863
            int[] info_aux_int;
864
            int size;
865

    
866
            // ----------------------------------- types init
867
            logger.debug("Beginning of result set:");
868

    
869
            while (_r.next()) {
870
                // ---------------------------------------
871
                ri = (ROWID) _r.getObject(1);
872
                gid = ri.stringValue();
873
                aux = ValueFactory.createValue(gid);
874

    
875
                Integer intobj = new Integer(row);
876
                hashRelate.put(aux, intobj);
877
                rowToId.put(intobj, ri);
878

    
879
                if ((row % 5000) == 0) {
880
                    // ------------------------------------------- cancel load
881
                    if (cancelIDLoad) {
882
                        hashRelate.clear();
883
                        rowToId.clear();
884

    
885
                        return;
886
                    }
887

    
888
                    // -------------------------------------------
889
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
890
                    logger.info("IDs read: " + fmt);
891
                }
892

    
893
                row++;
894

    
895
                // --------------------------------------- types
896
                info_aux = (ARRAY) _r.getObject(2);
897

    
898
                if (info_aux == null) {
899
                    // logger.debug("NULL info array found in record: " + row);
900
                }
901
                else {
902
                    info_aux_int = info_aux.getIntArray();
903
                    size = info_aux_int.length / 3;
904

    
905
                    for (int i = 0; i < size; i++) {
906
                        types_aux = info_aux_int[(3 * i) + 1];
907
                        types.add(new Integer(types_aux % 1000));
908
                    }
909
                }
910

    
911
                // --------------------------------------- types end
912
            }
913

    
914
            _r.close();
915
//            ps.close();
916
            st.close();
917
            numReg = row;
918

    
919
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
920

    
921
            if (needsCollectionLayer) {
922
                shapeType = FShape.MULTI;
923
            }
924
        }
925
        catch (SQLException e) {
926
            System.err.println("While setting id-row hashmap: " +
927
                e.getMessage());
928
        }
929
    }
930

    
931
    public int getFieldCount()
932
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
933
        try {
934
            return metaData.getColumnCount();
935
        }
936
        catch (SQLException e) {
937
            System.err.println("While getting field count: " + e.getMessage());
938
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e.getMessage());
939
        }
940
    }
941

    
942
    public String[] getFieldNames() {
943
        return fieldNames;
944
    }
945

    
946
    public String getTotalFields() {
947
        String strAux = "";
948

    
949
        for (int i = 0; i < fieldNames.length; i++) {
950
            if (i == 0) {
951
                strAux = fieldNames[i];
952
            }
953
            else {
954
                strAux = strAux + ", " + fieldNames[i];
955
            }
956
        }
957

    
958
        return strAux;
959
    }
960

    
961
    public int getFieldType(int idField)
962
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
963
        int i = 0;
964

    
965
        try {
966
            i = idField + 1; // idField viene basado en 0
967

    
968
            int __type = metaData.getColumnType(i);
969

    
970
            // we must add this entry because we did not remove the 'geometry' column
971
            if (__type == Types.STRUCT) {
972
                return Types.VARCHAR; // .STRUCT;
973
                                      // ----------------------------------------------------------------------
974
            }
975

    
976
            if (__type == Types.VARCHAR) {
977
                return Types.VARCHAR;
978
            }
979

    
980
            if (__type == Types.FLOAT) {
981
                return Types.FLOAT;
982
            }
983

    
984
            if (__type == Types.DOUBLE) {
985
                return Types.DOUBLE;
986
            }
987

    
988
            if (__type == Types.INTEGER) {
989
                return Types.INTEGER;
990
            }
991

    
992
            if (__type == Types.SMALLINT) {
993
                return Types.SMALLINT;
994
            }
995

    
996
            if (__type == Types.TINYINT) {
997
                return Types.TINYINT;
998
            }
999

    
1000
            if (__type == Types.BIGINT) {
1001
                return Types.BIGINT;
1002
            }
1003

    
1004
            if (__type == Types.BIT) {
1005
                return Types.BIT;
1006
            }
1007

    
1008
            if (__type == Types.DATE) {
1009
                return Types.DATE;
1010
            }
1011

    
1012
            if (__type == Types.DECIMAL) {
1013
                return Types.DOUBLE;
1014
            }
1015

    
1016
            if (__type == Types.NUMERIC) {
1017
                return Types.DOUBLE;
1018
            }
1019

    
1020
            if (__type == Types.DATE) {
1021
                return Types.DATE;
1022
            }
1023

    
1024
            if (__type == Types.TIME) {
1025
                return Types.TIME;
1026
            }
1027

    
1028
            if (__type == Types.TIMESTAMP) {
1029
                return Types.TIMESTAMP;
1030
            }
1031
        }
1032
        catch (SQLException e) {
1033
            System.err.println("i = " + i);
1034
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e);
1035
        }
1036

    
1037
        return -1;
1038
    }
1039

    
1040
    public Value[] getAttributes(ResultSet rs) {
1041
        Value[] res = null;
1042

    
1043
        try {
1044
            int fcount = rs.getMetaData().getColumnCount();
1045
            res = new Value[fcount];
1046

    
1047
            for (int i = 0; i < fcount; i++) {
1048
                Object obj = rs.getObject(i + 1);
1049
                String objToString = null;
1050
                int _type = -1;
1051

    
1052
                if (obj instanceof String) {
1053
                    objToString = (String) obj;
1054
                    _type = Types.VARCHAR;
1055
                }
1056
                else {
1057
                    if (obj instanceof ROWID) {
1058
                        objToString = ((ROWID) obj).stringValue();
1059
                        _type = Types.VARCHAR;
1060
                    }
1061
                    else {
1062
                        if (obj instanceof STRUCT) {
1063
                            objToString = "STRUCT";
1064
                            _type = Types.VARCHAR;
1065
                        }
1066
                        else {
1067
                            objToString = (obj == null) ? "NULL" : obj.toString();
1068
                            _type = getFieldType(i);
1069
                        }
1070
                    }
1071
                }
1072

    
1073
                // /*
1074
                if (_type == -1) {
1075
                    obj = null;
1076
                }
1077

    
1078
                // */
1079
                if (obj == null) {
1080
                    res[i] = ValueFactory.createNullValue();
1081
                }
1082
                else {
1083
                    if (_type == Types.DATE) {
1084
                        objToString = objToString.replace('-', '/');
1085
                    }
1086

    
1087
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1088
                }
1089
            }
1090
        }
1091
        catch (SQLException se) {
1092
            System.err.println("Error while getting attributes: " +
1093
                se.getMessage());
1094

    
1095
            return null;
1096
        }
1097
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1098
            System.err.println("Error while getting attributes: " +
1099
                e.getMessage());
1100

    
1101
            return null;
1102
        }
1103
        catch (ParseException e) {
1104
            System.err.println("Error while getting attributes: " +
1105
                e.getMessage());
1106

    
1107
            return null;
1108
        }
1109

    
1110
        return res;
1111
    }
1112
    
1113
    public Value[] getAttributesUsingMainMetadata(ResultSet rs) {
1114
        Value[] res = null;
1115

    
1116
        try {
1117
            int fcount = metaData.getColumnCount();
1118
            res = new Value[fcount];
1119

    
1120
            for (int i = 0; i < fcount; i++) {
1121
                Object obj = rs.getObject(i + 1);
1122
                String objToString = null;
1123
                int _type = -1;
1124

    
1125
                if (obj instanceof String) {
1126
                    objToString = (String) obj;
1127
                    _type = Types.VARCHAR;
1128
                }
1129
                else {
1130
                    if (obj instanceof ROWID) {
1131
                        objToString = ((ROWID) obj).stringValue();
1132
                        _type = Types.VARCHAR;
1133
                    }
1134
                    else {
1135
                        if (obj instanceof STRUCT) {
1136
                            objToString = "STRUCT";
1137
                            _type = Types.VARCHAR;
1138
                        }
1139
                        else {
1140
                            objToString = (obj == null) ? "NULL" : obj.toString();
1141
                            _type = getFieldType(i);
1142
                        }
1143
                    }
1144
                }
1145

    
1146
                // /*
1147
                if (_type == -1) {
1148
                    obj = null;
1149
                }
1150

    
1151
                // */
1152
                if (obj == null) {
1153
                    res[i] = ValueFactory.createNullValue();
1154
                }
1155
                else {
1156
                    if (_type == Types.DATE) {
1157
                        objToString = objToString.replace('-', '/');
1158
                    }
1159

    
1160
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1161
                }
1162
            }
1163
        }
1164
        catch (SQLException se) {
1165
            System.err.println("Error while getting attributes: " +
1166
                se.getMessage());
1167

    
1168
            return null;
1169
        }
1170
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1171
            System.err.println("Error while getting attributes: " +
1172
                e.getMessage());
1173

    
1174
            return null;
1175
        }
1176
        catch (ParseException e) {
1177
            System.err.println("Error while getting attributes: " +
1178
                e.getMessage());
1179

    
1180
            return null;
1181
        }
1182

    
1183
        return res;
1184
    }
1185
    
1186

    
1187
    public String getFieldName(int fieldId)
1188
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1189
        return fieldNames[fieldId];
1190
    }
1191

    
1192
    public int getFieldWidth(int fieldId) {
1193
        int i = -1;
1194

    
1195
        try {
1196
            int aux = fieldId + 1; // fieldId viene basado en 0
1197
            i = metaData.getColumnDisplaySize(aux);
1198
        }
1199
        catch (SQLException e) {
1200
            System.err.println("While getting field width: " + e.getMessage());
1201
        }
1202

    
1203
        if (i < 0) {
1204
            i = 255;
1205
        }
1206

    
1207
        return i;
1208
    }
1209

    
1210
    public Value getFieldValue(long rowIndex, int field_Id)
1211
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1212
        if (isNotAvailableYet) {
1213
            return nullVal;
1214
        }
1215

    
1216
        if ((singleCachedFeature != null) &&
1217
                (rowIndex == singleCachedFeatureRowNum)) {
1218
            return singleCachedFeature.getAttributes()[field_Id];
1219
        }
1220

    
1221
        // return ValueFactory.createNullValue();
1222
        ResultSet _r = null;
1223
        java.sql.PreparedStatement ps = null;
1224

    
1225
        try {
1226
            String rnq = getSearchId();
1227
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1228

    
1229
            ps = conn.prepareStatement(rnq);
1230
            ps.setObject(1, _id);
1231

    
1232
            ps.execute();
1233
            _r = ps.getResultSet();
1234
            _r.next();
1235
        }
1236
        catch (SQLException se) {
1237
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(se.getMessage());
1238
        }
1239

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

    
1243
        try {
1244
            ROWID ri = (ROWID) _r.getObject(1);
1245
            atts = getAttributesUsingMainMetadata(_r);
1246

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

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

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

    
1271
    public static void showMemory() {
1272
        Runtime r = Runtime.getRuntime();
1273
        long mem = r.totalMemory() - r.freeMemory();
1274
        System.err.println("Memoria total: " + mem);
1275
    }
1276

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

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

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

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

    
1304
        return _igeom;
1305
    }
1306

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

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

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

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

    
1323
            break;
1324

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

    
1329
            break;
1330

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

    
1335
            break;
1336

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

    
1341
            break;
1342
        }
1343

    
1344
        return ig;
1345
    }
1346

    
1347
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim,
1348
        int __srid) {
1349
        NUMBER main_type = new NUMBER((dim * 1000) +
1350
                OracleSpatialUtils.getStructType(the_data));
1351
        NUMBER _srid = new NUMBER(__srid);
1352

    
1353
        Datum[] all_info_array = null;
1354
        Object[] elems_info_aray = null;
1355
        Datum[] all_ords = null;
1356

    
1357
        try {
1358
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1359
            elems_info_aray = groupByElement(all_info_array);
1360
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1361
        }
1362
        catch (SQLException e) {
1363
            logger.error("Unexpected error: " + e.getMessage());
1364
        }
1365

    
1366
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1367
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1368

    
1369
        for (int i = 0; i < elems_info_aray.length; i++) {
1370
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1371
        }
1372

    
1373
        // _elems_info_aray, ords_of_groups
1374
        int no_of_elems = ords_of_groups.length;
1375
        IGeometry[] geoms = new IGeometry[no_of_elems];
1376

    
1377
        for (int i = 0; i < no_of_elems; i++) {
1378
            Datum[] item_info_array = null;
1379
            Datum[] item_ords = null;
1380
            NUMBER gtype = null;
1381

    
1382
            try {
1383
                item_info_array = (Datum[]) _elems_info_aray[i];
1384
                item_ords = (Datum[]) ords_of_groups[i];
1385

    
1386
                gtype = new NUMBER((dim * 1000) +
1387
                        (item_info_array[1].intValue() % 1000));
1388
            }
1389
            catch (SQLException se) {
1390
                logger.error("Unexpected error: " + se.getMessage());
1391
            }
1392

    
1393
            // if it's the first geometry, the type is the collection's main type (no?)
1394
            if (i == 0) {
1395
                gtype = main_type;
1396
            }
1397

    
1398
            STRUCT itemst = null;
1399

    
1400
            if (tableHasSrid) {
1401
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1402
                        item_info_array, item_ords, conn);
1403
            }
1404
            else {
1405
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1406
                        item_info_array, item_ords, conn);
1407
            }
1408

    
1409
            geoms[i] = getFMapGeometry(itemst, true);
1410
        }
1411

    
1412
        return new FGeometryCollection(geoms);
1413
    }
1414

    
1415
    /**
1416
     * Utility method to transform a struct into a IGeometry.
1417
     *
1418
     * @param st the struct to be converted
1419
     * @param force_not_collection t5his parameter is currently ignored
1420
     * @return the IGeometry
1421
     */
1422
    public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1423
        Datum[] the_data = null;
1424

    
1425
        try {
1426
            the_data = st.getOracleAttributes();
1427

    
1428
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1429
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1430

    
1431
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1432

    
1433
            if (dim < 2) {
1434
                dim = 2;
1435
            }
1436

    
1437
            IGeometry ig = null;
1438

    
1439
            if (isActuallyACollection(the_data)) {
1440
                jgtype = FShape.MULTI;
1441
            }
1442

    
1443
            switch (jgtype) {
1444
            case FShape.MULTI:
1445

    
1446
                int srid = ((NUMBER) the_data[1]).intValue();
1447
                ig = getFMapGeometryCollection(the_data, dim, srid);
1448

    
1449
                break;
1450

    
1451
            case FShape.POINT:
1452
                ig = getFMapGeometryPoint(the_data, dim);
1453

    
1454
                break;
1455

    
1456
            case FShape.LINE:
1457
                ig = getFMapGeometryMultiLineString(the_data, dim);
1458

    
1459
                break;
1460

    
1461
            case FShape.POLYGON:
1462
                ig = getFMapGeometryMultipolygon(the_data, dim);
1463

    
1464
                break;
1465
            }
1466

    
1467
            return ig;
1468
        }
1469
        catch (SQLException e) {
1470
            logger.error(e);
1471
        }
1472

    
1473
        return null;
1474
    }
1475

    
1476
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1477
        int size = input.length / n;
1478
        double[] resp = new double[size];
1479

    
1480
        for (int i = 0; i < size; i++) {
1481
            resp[i] = input[(i * n) + ind];
1482
        }
1483

    
1484
        return resp;
1485
    }
1486

    
1487
    private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1488
        int size = input.length / n;
1489
        double[] resp = new double[size];
1490

    
1491
        for (int i = 0; i < size; i++) {
1492
            resp[i] = input[(i * n) + ind];
1493
        }
1494

    
1495
        return resp;
1496
    }
1497

    
1498
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1499
        IGeometry ig = null;
1500

    
1501
        if (jg.isCircle()) {
1502
            ig = getCircleFromJGeometry(jg);
1503
        }
1504
        else {
1505
            Shape shape = jg.createShape();
1506
            GeneralPathX gpx = new GeneralPathX(shape);
1507

    
1508
            if (dim == 2) {
1509
                ig = ShapeFactory.createPolygon2D(gpx);
1510
            }
1511
            else {
1512
                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1513
                ig = ShapeFactory.createPolygon3D(gpx, z);
1514
            }
1515
        }
1516

    
1517
        return ig;
1518
    }
1519

    
1520
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1521
        IGeometry ig = null;
1522

    
1523
        if (OracleSpatialUtils.isCircle(the_data)) {
1524
            ig = getCircleFromStruct(the_data);
1525
        }
1526
        else {
1527
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1528

    
1529
            if (dim == 2) {
1530
                ig = ShapeFactory.createPolygon2D(gpx);
1531
            }
1532
            else {
1533
                double[] ords = null;
1534

    
1535
                try {
1536
                    ords = ((ARRAY) the_data[4]).getDoubleArray();
1537
                }
1538
                catch (SQLException se) {
1539
                    logger.error("While getting ordinates: " + se.getMessage(),
1540
                        se);
1541
                }
1542

    
1543
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1544
                ig = ShapeFactory.createPolygon3D(gpx, z);
1545
            }
1546
        }
1547

    
1548
        return ig;
1549
    }
1550

    
1551
    private IGeometry getCircleFromJGeometry(JGeometry jg) {
1552
        double[] threep = jg.getOrdinatesArray();
1553
        Point2D[] three = new Point2D.Double[3];
1554
        three[0] = new Point2D.Double(threep[0], threep[1]);
1555
        three[1] = new Point2D.Double(threep[2], threep[3]);
1556
        three[2] = new Point2D.Double(threep[4], threep[5]);
1557

    
1558
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1559

    
1560
        Point2D cent = (Point2D) cent_rad[0];
1561
        double radius = ((Double) cent_rad[1]).doubleValue();
1562

    
1563
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1564

    
1565
        return circ;
1566
    }
1567

    
1568
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1569
        double[] threep = null;
1570

    
1571
        try {
1572
            threep = ((ARRAY) the_data[4]).getDoubleArray();
1573
        }
1574
        catch (SQLException se) {
1575
            logger.error("While getting ords from struct: " + se.getMessage(),
1576
                se);
1577

    
1578
            return new FNullGeometry();
1579
        }
1580

    
1581
        Point2D[] three = new Point2D.Double[3];
1582
        three[0] = new Point2D.Double(threep[0], threep[1]);
1583
        three[1] = new Point2D.Double(threep[2], threep[3]);
1584
        three[2] = new Point2D.Double(threep[4], threep[5]);
1585

    
1586
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1587

    
1588
        Point2D cent = (Point2D) cent_rad[0];
1589
        double radius = ((Double) cent_rad[1]).doubleValue();
1590

    
1591
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1592

    
1593
        return circ;
1594
    }
1595

    
1596
    private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1597
        Shape shape = jg.createShape();
1598
        GeneralPathX gpx = new GeneralPathX(shape);
1599
        IGeometry ig = null;
1600

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

    
1609
        return ig;
1610
    }
1611

    
1612
    private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1613
        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1614
        IGeometry ig = null;
1615
        double[] ords = null;
1616

    
1617
        if (dim == 2) {
1618
            ig = ShapeFactory.createPolyline2D(gpx);
1619
        }
1620
        else {
1621
            ords = OracleSpatialUtils.getOrds(the_data);
1622

    
1623
            double[] z = getIndBigDecimalModule(ords, 2, dim);
1624
            ig = ShapeFactory.createPolyline3D(gpx, z);
1625
        }
1626

    
1627
        return ig;
1628
    }
1629

    
1630
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1631
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1632

    
1633
            return getFMapGeometrySdoPoint(jg_point, dim);
1634
        }
1635

    
1636
        IGeometry ig = null;
1637
        int total_size = jg_point.getOrdinatesArray().length;
1638
        int no_po = total_size / dim;
1639
        double[] x = new double[no_po];
1640
        double[] y = new double[no_po];
1641
        double[] z = new double[no_po];
1642

    
1643
        for (int i = 0; i < no_po; i++) {
1644
            x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1645
            y[i] = jg_point.getOrdinatesArray()[(i * dim) + 1];
1646

    
1647
            if (dim >= 3) {
1648
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1649
            }
1650
        }
1651

    
1652
        if (dim == 2) {
1653
            if (no_po == 1) {
1654
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1655
            }
1656
            else {
1657
                ig = ShapeFactory.createMultipoint2D(x, y);
1658
            }
1659
        }
1660
        else {
1661
            if (no_po == 1) {
1662
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1663
            }
1664
            else {
1665
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1666
            }
1667
        }
1668

    
1669
        return ig;
1670
    }
1671

    
1672
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1673
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1674

    
1675
        if (ords == null) { // sdo_point
1676

    
1677
            return getFMapGeometrySdoPoint(the_data, dim);
1678
        }
1679

    
1680
        IGeometry ig = null;
1681
        int total_size = ords.length;
1682
        int no_po = total_size / dim;
1683
        double[] x = new double[no_po];
1684
        double[] y = new double[no_po];
1685
        double[] z = new double[no_po];
1686

    
1687
        for (int i = 0; i < no_po; i++) {
1688
            x[i] = ords[i * dim]; // pp[i].getX();
1689
            y[i] = ords[(i * dim) + 1];
1690

    
1691
            if (dim >= 3) {
1692
                z[i] = ords[(i * dim) + 2];
1693
            }
1694
        }
1695

    
1696
        if (dim == 2) {
1697
            if (no_po == 1) {
1698
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1699
            }
1700
            else {
1701
                ig = ShapeFactory.createMultipoint2D(x, y);
1702
            }
1703
        }
1704
        else {
1705
            if (no_po == 1) {
1706
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1707
            }
1708
            else {
1709
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1710
            }
1711
        }
1712

    
1713
        return ig;
1714
    }
1715

    
1716
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1717
        double[] p = jgp.getPoint();
1718
        IGeometry ig = null;
1719

    
1720
        if (d == 2) {
1721
            ig = ShapeFactory.createPoint2D(p[0], p[1]);
1722
        }
1723
        else {
1724
            ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1725
        }
1726

    
1727
        return ig;
1728
    }
1729

    
1730
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1731
        double x = 0;
1732
        double y = 0;
1733
        double z = 0;
1734

    
1735
        try {
1736
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1737
            x = ((NUMBER) aux[0]).doubleValue();
1738
            y = ((NUMBER) aux[1]).doubleValue();
1739

    
1740
            if (d > 2) {
1741
                z = ((NUMBER) aux[2]).doubleValue();
1742
            }
1743
        }
1744
        catch (SQLException se) {
1745
            logger.error("While getting sdo point ordinates: " +
1746
                se.getMessage(), se);
1747
        }
1748

    
1749
        IGeometry ig = null;
1750

    
1751
        if (d == 2) {
1752
            ig = ShapeFactory.createPoint2D(x, y);
1753
        }
1754
        else {
1755
            ig = ShapeFactory.createPoint3D(x, y, z);
1756
        }
1757

    
1758
        return ig;
1759
    }
1760

    
1761
    private boolean isActuallyACollection(JGeometry jg) {
1762
        int[] info = jg.getElemInfo();
1763

    
1764
        if (info == null) {
1765
            return false; // sdo_point
1766
        }
1767

    
1768
        int size = info.length / 3;
1769

    
1770
        if (size == 1) {
1771
            return false;
1772
        }
1773

    
1774
        if (size == 2) {
1775
            return ((info[1] % 1000) != (info[4] % 1000));
1776
        }
1777

    
1778
        int second = info[4] % 1000;
1779

    
1780
        for (int i = 2; i < size; i++) {
1781
            if ((info[(i * 3) + 1] % 1000) != second) {
1782
                return true;
1783
            }
1784
        }
1785

    
1786
        return false;
1787
    }
1788

    
1789
    private boolean isActuallyACollection(Datum[] the_data) {
1790
        int[] info = null;
1791

    
1792
        try {
1793
            ARRAY aux = (ARRAY) the_data[3];
1794

    
1795
            if (aux == null) {
1796
                return false;
1797
            }
1798

    
1799
            info = aux.getIntArray();
1800
        }
1801
        catch (SQLException se) {
1802
            logger.error("While checking collection: " + se.getMessage());
1803

    
1804
            return false;
1805
        }
1806

    
1807
        if (info == null) {
1808
            return false; // sdo_point
1809
        }
1810

    
1811
        int size = info.length / 3;
1812

    
1813
        if (size == 1) {
1814
            return false;
1815
        }
1816

    
1817
        if (size == 2) {
1818
            return ((info[1] % 1000) != (info[4] % 1000));
1819
        }
1820

    
1821
        int second = info[4] % 1000;
1822

    
1823
        for (int i = 2; i < size; i++) {
1824
            if ((info[(i * 3) + 1] % 1000) != second) {
1825
                return true;
1826
            }
1827
        }
1828

    
1829
        return false;
1830
    }
1831

    
1832
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1833
        int main_type = jg.getType();
1834

    
1835
        int[] all_info_array = jg.getElemInfo();
1836
        Object[] elems_info_aray = groupByElement(all_info_array);
1837
        double[] all_ords = jg.getOrdinatesArray();
1838
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1839
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1840

    
1841
        for (int i = 0; i < elems_info_aray.length; i++) {
1842
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1843
        }
1844

    
1845
        // _elems_info_aray, ords_of_groups
1846
        int no_of_elems = ords_of_groups.length;
1847
        IGeometry[] geoms = new IGeometry[no_of_elems];
1848

    
1849
        for (int i = 0; i < no_of_elems; i++) {
1850
            int[] item_info_array = (int[]) _elems_info_aray[i];
1851
            double[] item_ords = (double[]) ords_of_groups[i];
1852
            int gtype = (dim * 1000) + (item_info_array[1] % 1000);
1853

    
1854
            // if it's the first geometry, the type is the collection's main type (no?)
1855
            if (i == 0) {
1856
                gtype = main_type;
1857
            }
1858

    
1859
            JGeometry itemjg = null;
1860

    
1861
            if (tableHasSrid) {
1862
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1863
            }
1864
            else {
1865
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1866
            }
1867

    
1868
            geoms[i] = getFMapGeometry(itemjg, true);
1869
        }
1870

    
1871
        return new FGeometryCollection(geoms);
1872
    }
1873

    
1874
    private Datum[] updateIndexes(Datum[] info) {
1875
        int size = info.length / 3;
1876
        NUMBER[] resp = new NUMBER[3 * size];
1877

    
1878
        try {
1879
            int rest = info[0].intValue() - 1;
1880

    
1881
            for (int i = 0; i < size; i++) {
1882
                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1883
                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
1884
                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
1885
            }
1886
        }
1887
        catch (SQLException se) {
1888
            logger.error("Unexpected error: " + se.getMessage());
1889
        }
1890

    
1891
        return resp;
1892
    }
1893

    
1894
    private int[] updateIndexes(int[] info) {
1895
        int size = info.length / 3;
1896
        int[] resp = new int[3 * size];
1897
        int rest = info[0] - 1;
1898

    
1899
        for (int i = 0; i < size; i++) {
1900
            resp[3 * i] = info[3 * i] - rest;
1901
            resp[(3 * i) + 1] = info[(3 * i) + 1];
1902
            resp[(3 * i) + 2] = info[(3 * i) + 2];
1903
        }
1904

    
1905
        return resp;
1906
    }
1907

    
1908
    private int[] appendIntArrays(int[] head, int[] tail) {
1909
        int[] resp = new int[head.length + tail.length];
1910
        int hsize = head.length;
1911

    
1912
        for (int i = 0; i < hsize; i++) {
1913
            resp[i] = head[i];
1914
        }
1915

    
1916
        for (int i = 0; i < tail.length; i++) {
1917
            resp[hsize + i] = tail[i];
1918
        }
1919

    
1920
        return resp;
1921
    }
1922

    
1923
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
1924
        Datum[] resp = new Datum[head.length + tail.length];
1925
        int hsize = head.length;
1926

    
1927
        for (int i = 0; i < hsize; i++) {
1928
            resp[i] = head[i];
1929
        }
1930

    
1931
        for (int i = 0; i < tail.length; i++) {
1932
            resp[hsize + i] = tail[i];
1933
        }
1934

    
1935
        return resp;
1936
    }
1937

    
1938
    private int[] getNthGroupOfThree(int[] list, int n) {
1939
        int[] resp = new int[3];
1940
        resp[0] = list[3 * n];
1941
        resp[1] = list[(3 * n) + 1];
1942
        resp[2] = list[(3 * n) + 2];
1943

    
1944
        return resp;
1945
    }
1946

    
1947
    private Datum[] getNthGroupOfThree(Datum[] list, int n) {
1948
        Datum[] resp = new Datum[3];
1949
        resp[0] = list[3 * n];
1950
        resp[1] = list[(3 * n) + 1];
1951
        resp[2] = list[(3 * n) + 2];
1952

    
1953
        return resp;
1954
    }
1955

    
1956
    private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
1957
        Datum[] resp = new Datum[last_inc - first_inc + 1];
1958

    
1959
        for (int i = first_inc; i <= last_inc; i++) {
1960
            resp[i - first_inc] = all[i];
1961
        }
1962

    
1963
        return resp;
1964
    }
1965

    
1966
    private double[] getSubSet(double[] all, int first_inc, int last_inc) {
1967
        double[] resp = new double[last_inc - first_inc + 1];
1968

    
1969
        for (int i = first_inc; i <= last_inc; i++) {
1970
            resp[i - first_inc] = all[i];
1971
        }
1972

    
1973
        return resp;
1974
    }
1975

    
1976
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) {
1977
        Object[] resp = new Object[groups.length];
1978

    
1979
        if (resp.length == 1) {
1980
            resp[0] = all;
1981

    
1982
            return resp;
1983
        }
1984

    
1985
        int ind = 0;
1986
        int[] aux = (int[]) groups[1];
1987
        int _end = aux[0] - 2;
1988
        Datum[] ord_aux = getSubSet(all, 0, _end);
1989

    
1990
        int _start = _end + 1;
1991
        resp[ind] = ord_aux;
1992
        ind++;
1993

    
1994
        for (int i = 2; i < groups.length; i++) {
1995
            aux = (int[]) groups[i];
1996
            _end = aux[0] - 2;
1997
            ord_aux = getSubSet(all, _start, _end);
1998
            resp[ind] = ord_aux;
1999
            ind++;
2000
            _start = _end + 1;
2001
        }
2002

    
2003
        // last
2004
        _end = all.length - 1;
2005
        ord_aux = getSubSet(all, _start, _end);
2006
        resp[groups.length - 1] = ord_aux;
2007

    
2008
        return resp;
2009
    }
2010

    
2011
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2012
        Object[] resp = new Object[groups.length];
2013

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

    
2017
            return resp;
2018
        }
2019

    
2020
        int ind = 0;
2021
        int[] aux = (int[]) groups[1];
2022
        int _end = aux[0] - 2;
2023
        double[] ord_aux = getSubSet(all, 0, _end);
2024

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

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

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

    
2043
        return resp;
2044
    }
2045

    
2046
    private Object[] groupByElement(int[] all_elem) {
2047
        ArrayList resp = new ArrayList();
2048

    
2049
        int size = all_elem.length / 3;
2050

    
2051
        int[] aux = getNthGroupOfThree(all_elem, 0);
2052

    
2053
        int[] newaux;
2054
        int i = 1;
2055

    
2056
        while (i < size) {
2057
            newaux = getNthGroupOfThree(all_elem, i);
2058

    
2059
            if (newaux[0] == aux[0]) {
2060
                // aux[2] says how many components
2061
                for (int j = 0; j < aux[2]; j++) {
2062
                    aux = appendIntArrays(aux,
2063
                            getNthGroupOfThree(all_elem, j + i));
2064
                }
2065

    
2066
                resp.add(aux);
2067
                i = i + aux[2];
2068
                aux = getNthGroupOfThree(all_elem, i);
2069
            }
2070
            else {
2071
                if (newaux[1] == 2003) {
2072
                    aux = appendIntArrays(aux, newaux);
2073
                }
2074
                else {
2075
                    resp.add(aux);
2076
                    aux = getNthGroupOfThree(all_elem, i);
2077
                }
2078
            }
2079

    
2080
            i++;
2081
        }
2082

    
2083
        resp.add(aux);
2084

    
2085
        return resp.toArray();
2086
    }
2087

    
2088
    private Object[] groupByElement(Datum[] all_elem) {
2089
        ArrayList resp = new ArrayList();
2090

    
2091
        int size = all_elem.length / 3;
2092

    
2093
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2094

    
2095
        Datum[] newaux;
2096
        int i = 1;
2097

    
2098
        try {
2099
            while (i < size) {
2100
                newaux = getNthGroupOfThree(all_elem, i);
2101

    
2102
                if (newaux[0] == aux[0]) {
2103
                    // aux[2] says how many components
2104
                    for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
2105
                        aux = appendDatArrays(aux,
2106
                                getNthGroupOfThree(all_elem, j + i));
2107
                    }
2108

    
2109
                    resp.add(aux);
2110
                    i = i + ((NUMBER) aux[2]).intValue();
2111
                    aux = getNthGroupOfThree(all_elem, i);
2112
                }
2113
                else {
2114
                    if (((NUMBER) newaux[1]).intValue() == 2003) {
2115
                        aux = appendDatArrays(aux, newaux);
2116
                    }
2117
                    else {
2118
                        resp.add(aux);
2119
                        aux = getNthGroupOfThree(all_elem, i);
2120
                    }
2121
                }
2122

    
2123
                i++;
2124
            }
2125
        }
2126
        catch (SQLException se) {
2127
            logger.error("Unexpected error: " + se.getMessage());
2128
        }
2129

    
2130
        resp.add(aux);
2131

    
2132
        return resp.toArray();
2133
    }
2134

    
2135
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2136
        Point2D p = _jgeom.getJavaPoint();
2137
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2138

    
2139
        return ig;
2140
    }
2141

    
2142
    private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2143
        Point2D[] pp = _jgeom.getJavaPoints();
2144
        int l = pp.length;
2145
        double[] x = new double[l];
2146
        double[] y = new double[l];
2147

    
2148
        for (int i = 0; i < l; i++) {
2149
            x[i] = pp[i].getX();
2150
            y[i] = pp[i].getY();
2151
        }
2152

    
2153
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2154

    
2155
        return ig;
2156
    }
2157

    
2158
    private IGeometry getJGeometryOther(JGeometry _jgeom) {
2159
        int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2160
        Shape shape = _jgeom.createShape();
2161
        GeneralPathX gpx = new GeneralPathX(shape);
2162
        IGeometry ig = null;
2163

    
2164
        switch (type) {
2165
        case FShape.LINE:
2166

    
2167
            FPolyline2D fpl = new FPolyline2D(gpx);
2168
            ig = ShapeFactory.createPolyline2D(gpx);
2169

    
2170
            break;
2171

    
2172
        case FShape.POLYGON:
2173

    
2174
            FPolygon2D fpg = new FPolygon2D(gpx);
2175
            ig = ShapeFactory.createPolygon2D(gpx);
2176

    
2177
            break;
2178
        }
2179

    
2180
        return ig;
2181
    }
2182

    
2183
//    private IGeometry getGeotoolsIGeometry(oracle.sql.STRUCT _struct) {
2184
//        Geometry geo_jts = null;
2185
//
2186
//        try {
2187
//            geo_jts = geotools_conv.asGeometry(_struct);
2188
//        }
2189
//        catch (SQLException e) {
2190
//            System.err.println("While using geotools converter: " +
2191
//                e.getMessage());
2192
//        }
2193
//
2194
//        IGeometry ig = FConverter.jts_to_igeometry(geo_jts);
2195
//
2196
//        return ig;
2197
//    }
2198

    
2199
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
2200
        /*
2201
         * Tipos en Oracle Spatial usando JGeometry
2202
         *
2203
         * GTYPE_COLLECTION collection geometry type
2204
         * GTYPE_CURVE curve geoemtry type
2205
         * GTYPE_MULTICURVE multi-curve geometry type
2206
         * GTYPE_MULTIPOINT multi-point geometry type
2207
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
2208
         * GTYPE_POINT point geometry type
2209
         * GTYPE_POLYGON  polygon geometry type
2210
         *
2211
         * Tipos gvSIG FShape
2212
         *
2213
         * NULL = 0;
2214
         * POINT = 1;
2215
         * LINE = 2;
2216
         * POLYGON = 4;
2217
         * TEXT = 8;
2218
         * MULTI = 16;
2219
         * MULTIPOINT = 32;
2220
         * CIRCLE = 64;
2221
         * ARC = 128;
2222
         * ELLIPSE=256;
2223
         * Z=512
2224
         */
2225
        switch (type) {
2226
        case JGeometry.GTYPE_POLYGON:
2227
        case JGeometry.GTYPE_MULTIPOLYGON:
2228
            return FShape.POLYGON;
2229

    
2230
        case JGeometry.GTYPE_CURVE:
2231
        case JGeometry.GTYPE_MULTICURVE:
2232
            return FShape.LINE;
2233
        }
2234

    
2235
        System.err.println("Unhandled Oracle Spatial geometry type: " + type +
2236
            " (conversion returned FShape.NULL)");
2237

    
2238
        return FShape.NULL;
2239
    }
2240

    
2241
    private void cleanWhereClause() {
2242
        emptyWhereClause = false;
2243

    
2244
        String aux = getWhereClauseWithoutWhere();
2245

    
2246
        for (int i = 0; i < aux.length(); i++)
2247
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
2248
                return;
2249
            }
2250

    
2251
        getLyrDef().setWhereClause("");
2252
        emptyWhereClause = true;
2253
    }
2254
    
2255
    private String getValidViewConstructor(
2256
                    STRUCT _st,
2257
                    String ora_srid,
2258
                    boolean _hassrid,
2259
                    boolean _isgeocs) {
2260
            
2261
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
2262
            String resp = "";
2263
            if ((_hassrid) && (_isgeocs)) {
2264
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
2265
            } else {
2266
                    resp = sdo;
2267
            }
2268
             
2269
            return resp;
2270
    }
2271

    
2272
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2273
        String resp = "";
2274

    
2275
        if (isGeogCS) {
2276
            String vport = "sdo_filter(" + geoColName +
2277
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
2278
                "), 'querytype=window') = 'TRUE'";
2279

    
2280
                resp = "select " + getStandardSelectExpression() + ", c." +
2281
                    geoColName + " from " + getTableName() + " c where ";
2282
                if (idsLoadWhere.length() > 0) {
2283
                        resp = resp + " (" + idsLoadWhere + ") AND "; 
2284
                }
2285
                resp = resp + "(" + vport + ")";
2286
        }
2287
        else {
2288
                resp = "select " + getStandardSelectExpression() + ", c." +
2289
                    geoColName + " from " + getTableName() + " c where ";
2290
                if (idsLoadWhere.length() > 0) {
2291
                        resp = resp + " (" + idsLoadWhere + ") AND "; 
2292
                }
2293
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
2294
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
2295
        }
2296
        return resp;
2297
    }
2298

    
2299
    public void setWorkingArea(Rectangle2D rect) {
2300
    }
2301

    
2302
    private void setWAStructt() {
2303
    }
2304

    
2305
    private Geometry shapeToGeometry(Shape shp) {
2306
        if (shp == null) {
2307
            return null;
2308
        }
2309

    
2310
        int type = FShape.POLYGON;
2311

    
2312
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2313
            type = FShape.LINE;
2314
        }
2315

    
2316
        if (shp instanceof FPoint2D) {
2317
            type = FShape.POINT;
2318
        }
2319

    
2320
        if (shp instanceof FMultiPoint2D) {
2321
            type = FShape.MULTIPOINT;
2322
        }
2323

    
2324
        GeneralPathX wagp = new GeneralPathX(shp);
2325
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2326

    
2327
        return FConverter.java2d_to_jts(fwagp);
2328
    }
2329

    
2330
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2331
        Shape shape = _jg.createShape();
2332

    
2333
        return shape.getBounds2D();
2334
    }
2335

    
2336
    private void printStruct(STRUCT st) {
2337
        System.out.println("----------------------------------------------");
2338

    
2339
        try {
2340
            Object[] att = st.getAttributes();
2341
            int l = att.length;
2342

    
2343
            for (int i = 0; i < l; i++) {
2344
                System.out.println("ATT " + i + ": " + att[i].toString());
2345
            }
2346
        }
2347
        catch (Exception ex) {
2348
            System.out.println(
2349
                "- Error ---------------------------------------");
2350
        }
2351

    
2352
        System.out.println("----------------------------------------------");
2353
    }
2354

    
2355
    private static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
2356
        boolean isView, boolean _isGeogCS, String _oracleSRID, Connection __conn) {
2357
        Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2358
        Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2359

    
2360
        if ((_isGeogCS) && (isView)) {
2361
            c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2362
            c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2363
        }
2364

    
2365
        STRUCT resp = null;
2366

    
2367
        try {
2368
            // System.out.println("ABIERTA: " + (!conn.isClosed()));
2369
            // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2370
            // Object[] old_obj = resp.getAttributes();
2371
            int size = 5;
2372
            Object[] new_obj = new Object[size];
2373

    
2374
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2375
            new_obj[0] = new NUMBER(2003);
2376

    
2377
            if (hasSrid) {
2378
                new_obj[1] = new NUMBER(_oracleSRID);
2379
            }
2380
            else {
2381
                new_obj[1] = null;
2382
            }
2383

    
2384
            new_obj[2] = null;
2385

    
2386
            NUMBER[] elem_info = new NUMBER[3];
2387
            elem_info[0] = new NUMBER(1);
2388
            elem_info[1] = new NUMBER(1003);
2389
            elem_info[2] = new NUMBER(3);
2390
            new_obj[3] = elem_info;
2391

    
2392
            NUMBER[] ords = null;
2393
            ords = new NUMBER[4];
2394
            ords[0] = new NUMBER(c1.getX());
2395
            ords[1] = new NUMBER(c1.getY());
2396
            ords[2] = new NUMBER(c2.getX());
2397
            ords[3] = new NUMBER(c2.getY());
2398
            new_obj[4] = ords;
2399

    
2400
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2401
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2402
                    __conn);
2403

    
2404
            resp = new STRUCT(dsc, __conn, new_obj);
2405
        }
2406
        catch (Exception ex) {
2407
            logger.error("Error while creating rect struct: " +
2408
                ex.getMessage(), ex);
2409
        }
2410

    
2411
        return resp;
2412
    }
2413

    
2414
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2415
        boolean hasSrid) throws DriverException {
2416
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
2417
        String main_sel = "";
2418

    
2419
        if (fixsql == null) {
2420
            // main_sel = getMainSelect3(var_name);
2421
                String idswhere = getIdsQueryWhereClause(false);
2422
            main_sel = getMainSelect(sdo_intersect, idswhere);
2423
        }
2424
        else {
2425
            main_sel = fixsql;
2426
        }
2427

    
2428
        System.err.println("main sel = " + main_sel);
2429

    
2430
        ResultSet _rs = null;
2431
        Statement _stmnt = null;
2432
        Object[] _resp = new Object[2];
2433

    
2434
        try {
2435
            _stmnt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
2436
                    ResultSet.CONCUR_READ_ONLY);
2437
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2438
            _stmnt.setFetchSize(FETCH_SIZE);
2439

    
2440
            _rs = _stmnt.executeQuery(main_sel);
2441

    
2442
            // stmnt.close();
2443
        }
2444
        catch (SQLException se) {
2445
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
2446
                se);
2447
            throw new DriverException(se);
2448
        }
2449

    
2450
        // this method returns the statement too, so that it can be closed afterwards
2451
        _resp[0] = _rs;
2452
        _resp[1] = _stmnt;
2453

    
2454
        return _resp;
2455
    }
2456

    
2457
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2458
        String resp = "";
2459

    
2460
        try {
2461
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2462
            String mdsys_sdo_ordinate_array = "";
2463
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2464

    
2465
            for (int i = 0; i < vertices.length; i++) {
2466
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2467
                    vertices[i].doubleValue() + ", ";
2468
            }
2469

    
2470
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2471
                    mdsys_sdo_ordinate_array.length() - 2);
2472
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2473
                mdsys_sdo_ordinate_array + ")";
2474

    
2475
            String aux = "";
2476

    
2477
            if (hasSrid) {
2478
                aux = oracleSRID;
2479

    
2480
                if (_isGeogCS) {
2481
                    aux = "0";
2482
                }
2483
            }
2484
            else {
2485
                aux = "null";
2486
            }
2487

    
2488
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
2489
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
2490
                ")";
2491
        }
2492
        catch (Exception ex) {
2493
            System.err.println("Error while getting sdo contructor: " +
2494
                ex.getMessage());
2495
        }
2496

    
2497
        return resp;
2498
    }
2499
    
2500
    private String getIdsQueryWhereClause(boolean with_where) {
2501
                String resp = "";
2502
                
2503
                String _where = "";
2504
                if (with_where) _where = " where ";
2505

    
2506
                if (workingAreaInTablesCSStruct == null) {
2507
                        if (emptyWhereClause) {
2508
                                // return "select rowid from " + getTableName();
2509
                        } else {
2510
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
2511
                                                + ")";
2512
                        }
2513
                } else {
2514
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
2515
                                        oracleSRID, tableHasSrid, isGeogCS);
2516

    
2517
                        if (emptyWhereClause) {
2518
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
2519
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2520
                        } else {
2521
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
2522
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
2523
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2524
                        }
2525
                }
2526

    
2527
                // resp = resp + " order by rowid";
2528
                return resp;
2529
        }
2530

    
2531
    public String getIdAndElemInfoFullResulltSetQuery() {
2532
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
2533
            getTableName() + " c";
2534
        
2535
        resp = resp + getIdsQueryWhereClause(true);
2536
        return resp;
2537
    }
2538

    
2539
    private String getSearchId() {
2540
        if (emptyWhereClause) {
2541
            return "select " + getStandardSelectExpression() + ", c." +
2542
            geoColName + " from " + getTableName() + " c where rowid = ?";
2543
        }
2544
        else {
2545
            return "select " + getStandardSelectExpression() + ", c." +
2546
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
2547
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
2548
        }
2549
    }
2550

    
2551
    public int getShapeType() {
2552
        return shapeType;
2553
    }
2554

    
2555
    private String getWhereClauseWithoutWhere() {
2556
        String resp = "";
2557
        String old = getLyrDef().getWhereClause();
2558
        resp = old;
2559

    
2560
        if (old.length() <= 6) {
2561
            return old;
2562
        }
2563

    
2564
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2565
            resp = resp.substring(6, resp.length());
2566
        }
2567

    
2568
        return resp;
2569
    }
2570

    
2571
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2572
        if (r1.getMaxX() <= r2.getMinX()) {
2573
            return null;
2574
        }
2575

    
2576
        if (r2.getMaxX() <= r1.getMinX()) {
2577
            return null;
2578
        }
2579

    
2580
        if (r1.getMaxY() <= r2.getMinY()) {
2581
            return null;
2582
        }
2583

    
2584
        if (r2.getMaxY() <= r1.getMinY()) {
2585
            return null;
2586
        }
2587

    
2588
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2589
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2590
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2591
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2592

    
2593
        double w = maxx - minx;
2594
        double h = maxy - miny;
2595

    
2596
        return new Rectangle2D.Double(minx, miny, w, h);
2597
    }
2598

    
2599
    private static int maxSizeForFieldType(int _type) {
2600
        switch (_type) {
2601
        case Types.VARCHAR:
2602
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2603

    
2604
        case Types.LONGVARCHAR:
2605
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2606
        }
2607

    
2608
        return -1;
2609
    }
2610

    
2611
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2612
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2613

    
2614
        switch (fieldDesc.getFieldType()) {
2615
        case Types.SMALLINT:
2616
            aux = "NUMBER(5, 0)";
2617

    
2618
            break;
2619

    
2620
        case Types.INTEGER:
2621
            aux = "NUMBER(10, 0)";
2622

    
2623
            break;
2624

    
2625
        case Types.BIGINT:
2626
            aux = "NUMBER(38, 0)";
2627

    
2628
            break;
2629

    
2630
        case Types.BOOLEAN:
2631
            aux = "NUMBER(1, 0)";
2632

    
2633
            break;
2634

    
2635
        case Types.DECIMAL:
2636
            aux = "NUMBER";
2637

    
2638
            break;
2639

    
2640
        case Types.NUMERIC:
2641
            aux = "NUMBER";
2642

    
2643
            break;
2644

    
2645
        case Types.DOUBLE:
2646
            aux = "FLOAT";
2647

    
2648
            break;
2649

    
2650
        case Types.FLOAT:
2651
            aux = "FLOAT";
2652

    
2653
            break;
2654

    
2655
        case Types.CHAR:
2656
            aux = "CHAR(1 BYTE)";
2657

    
2658
            break;
2659

    
2660
        case Types.VARCHAR:
2661
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2662

    
2663
            break;
2664

    
2665
        case Types.LONGVARCHAR:
2666
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2667

    
2668
            break;
2669
        }
2670

    
2671
        return aux;
2672
    }
2673

    
2674
    // -----------------------------------------------------------
2675
    // -----------------------------------------------------------
2676
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2677
        return "DROP TABLE \"" + dbLayerDef.getTableName() +
2678
        "\" CASCADE CONSTRAINTS";
2679
    }
2680

    
2681
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2682
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2683

    
2684
        String type = "";
2685
        String name = "";
2686

    
2687
        String resp = "CREATE TABLE \"" + dbLayerDef.getTableName() + "\" ( ";
2688

    
2689
        for (int i = 0; i < flds.length; i++) {
2690
            name = flds[i].getFieldName();
2691

    
2692
            // -------------- FORBIDDEN FIELD NAMES -----------------
2693
            if (!isOracleAllowedFieldname(name)) {
2694
                continue;
2695
            }
2696

    
2697
            // ------------------------------------------------------
2698
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
2699
            }
2700
            else {
2701
                name = getValidOracleID(name, i);
2702
                resp = resp + "\"" + name + "\" ";
2703
                type = fieldTypeToSqlStringType(flds[i]);
2704
                resp = resp + type + ", ";
2705
            }
2706
        }
2707

    
2708
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2709
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2710
        resp = resp + ", ";
2711

    
2712
        String pk = "CONSTRAINT \"" + dbLayerDef.getTableName() +
2713
            "_PK\" PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD +
2714
            "\") ENABLE";
2715

    
2716
        resp = resp + pk + " )";
2717

    
2718
        return resp;
2719
    }
2720

    
2721
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2722
        String resp = "CREATE INDEX \"" + dbLayerDef.getTableName() +
2723
            "_SX\" ON \"" + dbLayerDef.getTableName() + "\" (\"" +
2724
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
2725
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2726

    
2727
        return resp;
2728
    }
2729

    
2730
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2731
        return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2732
        " WHERE TABLE_NAME = '" + dbLayerDef.getTableName() + "'";
2733
    }
2734

    
2735
    /**
2736
     * UTility method to get the SQL sentence needed to update the geographic metadata table
2737
     * with a new bounding box and SRS
2738
     *
2739
     * @param tName table name
2740
     * @param ora_srid new SRS
2741
     * @param bbox new bounding box
2742
     * @param dim geometries dimension
2743
     * @param withsrid False if the SRS is set to NULL. True otherwise.
2744
     * @return the SQL sentence to perform the update
2745
     */
2746
    public static String getMetadataUpdateSql(String tName, String ora_srid,
2747
        Rectangle2D bbox, int dim, boolean withsrid) {
2748
        String[] dim_name = new String[dim];
2749
        double tolerance = 0.5;
2750

    
2751
        if (ora_srid.compareTo(GEODETIC_SRID) == 0) {
2752
            dim_name[0] = "LONGITUDE";
2753
            dim_name[1] = "LATITUDE";
2754
        }
2755
        else {
2756
            dim_name[0] = "X";
2757
            dim_name[1] = "Y";
2758

    
2759
            if (dim > 2) {
2760
                dim_name[2] = "Z";
2761

    
2762
                if (dim > 3) {
2763
                    dim_name[3] = "T";
2764
                }
2765
            }
2766
        }
2767

    
2768
        String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " " +
2769
            " ( TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES (" + "'" +
2770
            tName + "', " + "'" + DEFAULT_GEO_FIELD + "', " +
2771
            "SDO_DIM_ARRAY( " + "SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2772
            bbox.getMinX() + ", " + bbox.getMaxX() + ", " + tolerance + " ), " +
2773
            "SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + bbox.getMinY() + ", " +
2774
            bbox.getMaxY() + ", " + tolerance + " ))";
2775

    
2776
        if (dim > 2) {
2777
            resp = resp.substring(0, resp.length() - 1) + ",";
2778
            resp = resp + "SDO_DIM_ELEMENT ('" + dim_name[2] +
2779
                "', 0.0, 100.0, " + tolerance + " ))";
2780

    
2781
            if (dim > 3) {
2782
                resp = resp.substring(0, resp.length() - 1) + ",";
2783
                resp = resp + "SDO_DIM_ELEMENT ('" + dim_name[3] +
2784
                    "', 0.0, 100.0, " + tolerance + " ))";
2785
            }
2786
        }
2787

    
2788
        if (withsrid) {
2789
            resp = resp + ", " + ora_srid + " )";
2790
        }
2791
        else {
2792
            resp = resp + ", NULL )";
2793
        }
2794

    
2795
        return resp;
2796
    }
2797

    
2798
    /**
2799
     * Gets the SQL sentence to perform an insertion.
2800
     *
2801
     * @param feat feature to be added
2802
     * @param dbLayerDef layer definition
2803
     * @param rowInd row index
2804
     * @param _geoColName geometry field name
2805
     * @return the SQL sentence to perform the insertion
2806
     */
2807
    public static String getRowInsertSql(IFeature feat,
2808
        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2809
        String name = "";
2810
        int ftype = -1;
2811
        String aux_orig = "";
2812
        String aux_limited = "";
2813
        String aux_quotes_ok = "";
2814

    
2815
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2816

    
2817
        String resp = "INSERT INTO \"" + dbLayerDef.getTableName() + "\" ( ";
2818

    
2819
        for (int i = 0; i < fieldsDescr.length; i++) {
2820
            name = fieldsDescr[i].getFieldName();
2821
            ftype = fieldsDescr[i].getFieldType();
2822

    
2823
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2824
            if (!isOracleAllowedFieldname(name)) continue;
2825
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2826
            // ------------------------------------------------------
2827
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2828
            }
2829
            else {
2830
                name = getValidOracleID(name, i);
2831
                resp = resp + "\"" + name + "\"" + " , ";
2832
            }
2833
        }
2834

    
2835
        resp = resp + _geoColName + " ) VALUES ( ";
2836

    
2837
        for (int i = 0; i < fieldsDescr.length; i++) {
2838
            name = fieldsDescr[i].getFieldName();
2839
            ftype = fieldsDescr[i].getFieldType();
2840

    
2841
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2842
            if (!isOracleAllowedFieldname(name)) continue;
2843
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2844
            // ------------------------------------------------------
2845
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2846

    
2847
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2848
            }
2849
            else {
2850
                if (name.compareToIgnoreCase(
2851
                            OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2852
                    resp = resp + rowInd + " , ";
2853
                }
2854
                else {
2855
                    Value attValue = feat.getAttribute(i);
2856

    
2857
                    if (attValue.toString() == null) {
2858
                        resp = resp + "NULL , ";
2859
                    }
2860
                    else {
2861
                        if (sur.length() > 0) {
2862
                            aux_orig = attValue.toString();
2863
                            aux_limited = cropStringValue(aux_orig, i,
2864
                                    fieldsDescr);
2865
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2866

    
2867
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2868
                        }
2869
                        else {
2870
                            String _aux = attValue.toString();
2871

    
2872
                            if (_aux.length() == 0) {
2873
                                _aux = "NULL";
2874
                            }
2875

    
2876
                            resp = resp + _aux + " , ";
2877
                        }
2878
                    }
2879
                }
2880
            }
2881
        }
2882

    
2883
        resp = resp + " ? )";
2884

    
2885
        return resp;
2886
    }
2887

    
2888
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
2889
            
2890
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
2891
                    return true;
2892
            }
2893
            
2894
            if ((ftype == Types.BINARY)
2895
                || (ftype == Types.ARRAY)
2896
                || (ftype == Types.BLOB)
2897
                || (ftype == Types.CLOB)
2898
                || (ftype == Types.STRUCT)
2899
            ) {
2900
                    return false;
2901
            }
2902
                return true;
2903
        }
2904

    
2905
        /**
2906
     * Gets the SQL sentence to perform an update.
2907
     *
2908
     * @param feat feature to be updated
2909
     * @param dbLayerDef layer definition
2910
     * @param rowInd row index
2911
     * @param geoFieldName geometry field name
2912
     * @return the SQL sentence to perform the update
2913
     */
2914
    public static String getRowUpdateSql(IFeature feat,
2915
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
2916
        String name = "";
2917
        String aux_orig = "";
2918
        String aux_limited = "";
2919
        String aux_quotes_ok = "";
2920

    
2921
        Value[] atts = feat.getAttributes();
2922
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
2923

    
2924
        String resp = "UPDATE \"" + dbLayerDef.getTableName() + "\" SET ";
2925

    
2926
        for (int i = 0; i < _fieldsDescr.length; i++) {
2927
            name = _fieldsDescr[i].getFieldName();
2928

    
2929
            // -------------- FORBIDDEN FIELD NAMES -----------------
2930
            if (!isOracleAllowedFieldname(name)) {
2931
                logger.info("Field: " + name + " will not be updated.");
2932
                continue;
2933
            }
2934

    
2935
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
2936
                        geoFieldName)) {
2937
                logger.info("Field: " + name + " will not be updated (it's a struct).");
2938
                continue;
2939
            }
2940

    
2941
            // ------------------------------------------------------
2942
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
2943
                // resp = resp + "\"" + name + "\"" + " = ?, ";
2944
            }
2945
            else {
2946
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
2947
                aux_orig = atts[i].toString();
2948
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
2949
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
2950
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
2951
                    sur + ", ";
2952
            }
2953
        }
2954

    
2955
        resp = resp + "\"" + geoFieldName + "\" = ?";
2956
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
2957

    
2958
        return resp;
2959
    }
2960

    
2961
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
2962
        String geoname) {
2963
        if (ftype == Types.STRUCT) {
2964
            if (fldname.compareToIgnoreCase(geoname) != 0) {
2965
                return true;
2966
            }
2967
        }
2968

    
2969
        return false;
2970
    }
2971

    
2972
    /**
2973
     * Gets the SQL sentence to perform a deletion.
2974
     *
2975
     * @param dbLayerDef layer definition
2976
     * @param id ROWID of the record to be deleted
2977
     * @return the SQL sentence to perform the deletion
2978
     */
2979
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
2980
        String resp = "DELETE FROM \"" + dbLayerDef.getTableName() + "\"";
2981
        resp = resp + " WHERE ROWID ='" + id + "'";
2982

    
2983
        return resp;
2984
    }
2985

    
2986
    private static String cropStringValue(String orig_val, int i,
2987
        FieldDescription[] _flds) {
2988
        if (orig_val == null) {
2989
            return "NULL";
2990
        }
2991

    
2992
        int tpe = _flds[i].getFieldType();
2993
        int max_size = maxSizeForFieldType(tpe);
2994

    
2995
        if (max_size == -1) {
2996
            return orig_val;
2997
        }
2998

    
2999
        int or_size = orig_val.length();
3000

    
3001
        if (or_size <= max_size) {
3002
            return orig_val;
3003
        }
3004

    
3005
        return orig_val.substring(0, max_size);
3006
    }
3007

    
3008
    private static String avoidQuoteProblem(String str) {
3009
        return str.replaceAll("'", "''");
3010
    }
3011

    
3012
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3013
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3014
            return "";
3015
        }
3016

    
3017
        return "'";
3018
    }
3019

    
3020
    /**
3021
     * Utility function to translate a SRS code from EPSG to Oracle.
3022
     * Uses a datasource based on a DBF file.
3023
     *
3024
     * @param epsg the EPSG code
3025
     * @return the Oracle code
3026
     */
3027
    public static String epsgSridToOracleSrid(String epsg) throws Exception {
3028
        String resp = "8307";
3029

    
3030
        // --------------------------------------------
3031
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3032
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3033
        DataSource ds = null;
3034

    
3035
        try {
3036
            ds = LayerFactory.getDataSourceFactory()
3037
                             .executeSQL(sql,
3038
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3039

    
3040
            if (ds.getRowCount() == 0) {
3041
                logger.error("EPSG code not found in table: " + epsg);
3042
                throw new Exception("Unknown EPSG: " + epsg);
3043
            }
3044

    
3045
            if (ds.getRowCount() > 1) {
3046
                logger.error("===============");
3047
                logger.error(
3048
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
3049
                    epsg);
3050

    
3051
                for (int i = 0; i < ds.getRowCount(); i++) {
3052
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3053

    
3054
                    if (i == 0) {
3055
                        resp = "" + aux;
3056
                    }
3057

    
3058
                    logger.error("" + aux);
3059
                }
3060

    
3061
                logger.error("===============");
3062

    
3063
                return resp;
3064
            }
3065

    
3066
            resp = "" +
3067
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3068
        }
3069
        catch (Exception pe) {
3070
            logger.error("Error with SQL statement. " + pe.getMessage());
3071
        }
3072

    
3073
        return resp;
3074
    }
3075

    
3076
    /**
3077
     * Utility function to translate a SRS code from Oracle to EPSG.
3078
     * Uses a datasource based on a DBF file.
3079
     *
3080
     * @param ora the Oracle code
3081
     * @return the EPSG code
3082
     */
3083
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3084
        String resp = "4326";
3085

    
3086
        // --------------------------------------------
3087
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3088
            " where ORACLE = " + ora + ";";
3089
        DataSource ds = null;
3090

    
3091
        try {
3092
            ds = LayerFactory.getDataSourceFactory()
3093
                             .executeSQL(sql,
3094
                    DataSourceFactory.AUTOMATIC_OPENING);
3095

    
3096
            if (ds.getRowCount() == 0) {
3097
                logger.error("Oracle Spatial code not found in table: " + ora);
3098
                throw new Exception("Unknown Oracle code: " + ora);
3099
            }
3100

    
3101
            if (ds.getRowCount() > 1) {
3102
                logger.error("===============");
3103
                logger.error(
3104
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3105
                    ora);
3106

    
3107
                for (int i = 0; i < ds.getRowCount(); i++) {
3108
                    String aux = "" +
3109
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3110

    
3111
                    if (i == 0) {
3112
                        resp = aux;
3113
                    }
3114

    
3115
                    logger.error("" + aux);
3116
                }
3117

    
3118
                logger.error("===============");
3119

    
3120
                return resp;
3121
            }
3122

    
3123
            resp = "" +
3124
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3125
        }
3126
        catch (Exception pe) {
3127
            logger.error("Error with SQL statement. " + pe.getMessage());
3128
        }
3129

    
3130
        return resp;
3131
    }
3132

    
3133
    /**
3134
     * This methos creates the datasource used to translate the SRS codes:
3135
     * EPSG <--> Oracle.
3136
     *
3137
     * It's called from several places, so checks that the datasource does not exist.
3138
     */
3139
    public static void createOracleEpsgTable() {
3140
        SourceInfo si = LayerFactory.getDataSourceFactory()
3141
                                    .getDriverInfo(ORACLE_EPSG_TABLE_NAME);
3142

    
3143
        if (si != null) { // already created, nothing done
3144
            return;
3145
        }
3146

    
3147
        // Create 'oracle codes - epsg codes' table
3148
        DBFDriver dbfdrv = new DBFDriver();
3149

    
3150
        // dbfdrv.setDataSourceFactory()
3151
        OFileDataSourceAdapter fdsa = new OFileDataSourceAdapter();
3152

    
3153
        fdsa.setDriver(dbfdrv);
3154

    
3155
        // ---------------------------------------------
3156
        FileSourceInfo fsi = new FileSourceInfo();
3157
        fsi.file = createFileString("dbf/" + ORACLE_EPSG_FILE_NAME);
3158
        fsi.spatial = false;
3159
        fsi.name = ORACLE_EPSG_TABLE_NAME;
3160
        fsi.driverName = dbfdrv.getName(); //"DBF Driver";
3161
                                           // ---------------------------------------------
3162

    
3163
        fdsa.setSourceInfo(fsi);
3164

    
3165
        SelectableDataSource sds = null;
3166
        EditableAdapter ea = new EditableAdapter();
3167
        ProjectTable pt = null;
3168

    
3169
        try {
3170
            sds = new SelectableDataSource(fdsa);
3171
            ea.setOriginalDataSource(sds);
3172
            pt = ProjectTableFactory.createTable(ORACLE_EPSG_TABLE_NAME, ea);
3173
        }
3174
        catch (Exception ex) {
3175
            System.err.println("While creating datasource: " + ex.getMessage());
3176
        }
3177

    
3178
        sds.setSourceInfo(fsi);
3179

    
3180
        DataSourceFactory dsf = LayerFactory.getDataSourceFactory();
3181
        dsf.addFileDataSource(fsi.driverName, fsi.name, fsi.file);
3182
        sds.setDataSourceFactory(dsf);
3183
    }
3184

    
3185
    private static String createFileString(String path) {
3186
        try {
3187
            File f = new File(
3188
                    "./gvSIG/extensiones/" + EXTENSION_DIR_NAME + "/" +
3189
                    path);
3190

    
3191
            return f.getCanonicalPath();
3192
        }
3193
        catch (Exception ex) {
3194
            return "./gvSIG/extensiones/" + EXTENSION_DIR_NAME + "/" +
3195
            path;
3196
        }
3197
    }
3198

    
3199
    /**
3200
     * Utility method to get a valid Oracle identifier (in terms of length)
3201
     *
3202
     * @param str Proposed string
3203
     * @param ind field index of the given field name (used by the method to
3204
     * improve the renaming)
3205
     * @return an acceptable oracle identifier.
3206
     */
3207
    public static String getValidOracleID(String str, int ind) {
3208
        if (str.length() <= MAX_ID_LENGTH) {
3209
            return str;
3210
        }
3211

    
3212
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3213
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3214
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3215
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3216
        resp = resp + "_" + (ind % 1000);
3217

    
3218
        return resp;
3219
    }
3220

    
3221
    private static ArrayList ensureSensibleShell(ArrayList cc) {
3222
        if (sameCoordinate((Coordinate) cc.get(0),
3223
                    (Coordinate) cc.get(cc.size() - 1))) {
3224
            if (cc.size() == 2) {
3225
                ArrayList resp = new ArrayList();
3226
                resp.add(cc.get(0));
3227

    
3228
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3229
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3230
                resp.add(newcoo);
3231

    
3232
                newcoo = new Coordinate((Coordinate) cc.get(0));
3233
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3234
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
3235
                resp.add(newcoo);
3236

    
3237
                resp.add(cc.get(0));
3238

    
3239
                return resp;
3240
            }
3241

    
3242
            if (cc.size() == 3) {
3243
                cc.remove(1);
3244

    
3245
                return ensureSensibleShell(cc);
3246
            }
3247

    
3248
            return cc;
3249
        }
3250
        else {
3251
            cc.add(cc.get(0));
3252

    
3253
            return cc;
3254
        }
3255
    }
3256

    
3257
    private static ArrayList ensureSensibleHole(ArrayList cc) {
3258
        if (sameCoordinate((Coordinate) cc.get(0),
3259
                    (Coordinate) cc.get(cc.size() - 1))) {
3260
            if (cc.size() == 2) {
3261
                ArrayList resp = new ArrayList();
3262
                resp.add(cc.get(0));
3263

    
3264
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3265
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3266
                resp.add(newcoo);
3267

    
3268
                newcoo = new Coordinate((Coordinate) cc.get(0));
3269
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3270
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3271
                resp.add(newcoo);
3272

    
3273
                resp.add(cc.get(0));
3274

    
3275
                return resp;
3276
            }
3277

    
3278
            if (cc.size() == 3) {
3279
                cc.remove(1);
3280

    
3281
                return ensureSensibleHole(cc);
3282
            }
3283

    
3284
            return cc;
3285
        }
3286
        else {
3287
            cc.add(cc.get(0));
3288

    
3289
            return cc;
3290
        }
3291
    }
3292

    
3293
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
3294
        if (cc.size() == 2) {
3295
            if (sameCoordinate((Coordinate) cc.get(0),
3296
                        (Coordinate) cc.get(cc.size() - 1))) {
3297
                ArrayList resp = new ArrayList();
3298
                resp.add(cc.get(0));
3299

    
3300
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3301
                newc.x = newc.x + IRRELEVANT_DISTANCE;
3302
                resp.add(newc);
3303

    
3304
                return resp;
3305
            }
3306
        }
3307

    
3308
        return cc;
3309
    }
3310

    
3311
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3312
        if (c1.x != c2.x) {
3313
            return false;
3314
        }
3315

    
3316
        if (c1.y != c2.y) {
3317
            return false;
3318
        }
3319

    
3320
        return true;
3321
    }
3322

    
3323
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3324
        if (cc.size() == 2) {
3325
            return null;
3326
        }
3327

    
3328
        if (cc.size() == 3) {
3329
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3330
                return null;
3331
            }
3332

    
3333
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3334
                return null;
3335
            }
3336

    
3337
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3338
                return null;
3339
            }
3340

    
3341
            cc.add(cc.get(0));
3342

    
3343
            return cc;
3344
        }
3345

    
3346
        if (!sameCoordinate((Coordinate) cc.get(0),
3347
                    (Coordinate) cc.get(cc.size() - 1))) {
3348
            cc.add(cc.get(0));
3349
        }
3350

    
3351
        return cc;
3352
    }
3353

    
3354
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3355
        Coordinate[] p = new Coordinate[4];
3356
        p[0] = c;
3357

    
3358
        Coordinate nc = new Coordinate(c);
3359
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3360

    
3361
        Coordinate nc2 = new Coordinate(nc);
3362
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3363
        p[1] = nc;
3364
        p[2] = nc2;
3365
        p[3] = new Coordinate(c);
3366

    
3367
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3368
        LinearRing ls = new LinearRing(cs, geomFactory);
3369
        Polygon po = new Polygon(ls, null, geomFactory);
3370
        Polygon[] pos = new Polygon[1];
3371
        pos[0] = po;
3372

    
3373
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3374

    
3375
        return mpo;
3376
    }
3377

    
3378
    public String getSourceProjection() {
3379
        // TODO Auto-generated method stub
3380
        if (tableHasSrid) {
3381
            return epsgSRID;
3382
        }
3383

    
3384
        return destProj;
3385
    }
3386

    
3387
    public String getDestProjection() {
3388
        return destProj;
3389
    }
3390

    
3391
    public void setDestProjection(String toEPSG) {
3392
        destProj = toEPSG;
3393
        try {
3394
                        destProjOracle = epsgSridToOracleSrid(destProj);
3395
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3396
                        
3397
                } catch (Exception e) {
3398
                        logger.error("Unknown EPSG code: " + destProj);
3399
                        destProjOracle = oracleSRID;
3400
                        isDestGeogCS = false;
3401
                }
3402
        
3403
    }
3404
    
3405
    public String getDestProjectionOracleCode() {
3406
            return destProjOracle;
3407
    }
3408
    
3409
    public boolean getIsDestProjectionGeog() {
3410
            return isDestGeogCS;
3411
    }
3412
    
3413
    public String getTableProjectionOracleCode() {
3414
            return oracleSRID;
3415
    }
3416

    
3417
    public boolean canReproject(String toEPSGdestinyProjection) {
3418
        return false;
3419
    }
3420

    
3421
    /**
3422
     * Utility function. Says whether a given field name can be a user field name
3423
     * or not (for example, "ROWID" is not a valid one because it's a system
3424
     * reserved word).
3425
     *
3426
     * @param str proposed firld name
3427
     * @return whether it is valid or not for Oracle databases
3428
     */
3429
    private static boolean isOracleAllowedFieldname(String str) {
3430
        if (str.compareToIgnoreCase("rowid") == 0) {
3431
            return false;
3432
        }
3433

    
3434
        if (str.compareToIgnoreCase("rownum") == 0) {
3435
            return false;
3436
        }
3437

    
3438
        return true;
3439
    }
3440

    
3441
    public Hashtable getHashRelate() {
3442
        return hashRelate;
3443
    }
3444

    
3445
    public void setHashRelate(Hashtable m) {
3446
        hashRelate = m;
3447
    }
3448

    
3449
    public void setNumReg(int n) {
3450
        numReg = n;
3451
    }
3452

    
3453
    private int[] getRandomSample(int maxn_one_based, int n) {
3454
        int[] resp = new int[n];
3455

    
3456
        if (maxn_one_based <= n) {
3457
            resp = new int[maxn_one_based];
3458

    
3459
            for (int i = 0; i < maxn_one_based; i++) {
3460
                resp[i] = i;
3461
            }
3462
        }
3463
        else {
3464
            Random rnd = new Random();
3465

    
3466
            for (int i = 0; i < n; i++) {
3467
                resp[i] = rnd.nextInt(maxn_one_based);
3468
            }
3469
        }
3470

    
3471
        return resp;
3472
    }
3473

    
3474
    private String getRowIdRestrictionCondition(int nrecords) {
3475
        int[] zero_based_rows = getRandomSample(nrecords,
3476
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3477
        String resp = "(";
3478
        Object aux = "";
3479
        ROWID riaux = null;
3480

    
3481
        for (int i = 0; i < zero_based_rows.length; i++) {
3482
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3483
            riaux = (ROWID) aux;
3484
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3485
        }
3486

    
3487
        resp = resp.substring(0, resp.length() - 4);
3488
        resp = resp + ")";
3489

    
3490
        return resp;
3491
    }
3492

    
3493
    private Rectangle2D getBoundingFromSample(int n_max) {
3494
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3495
            " WHERE " + getRowIdRestrictionCondition(n_max);
3496
        STRUCT auxstr = null;
3497
        IGeometry theGeom = null;
3498
        Rectangle2D resp = null;
3499

    
3500
        try {
3501
            Statement st = conn.createStatement();
3502
            ResultSet rs = st.executeQuery(_qry);
3503

    
3504
            if (rs.next()) {
3505
                auxstr = (STRUCT) rs.getObject(1);
3506

    
3507
                if (auxstr != null) {
3508
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3509

    
3510
                    if (resp == null) {
3511
                        resp = theGeom.getBounds2D();
3512
                    }
3513
                    else {
3514
                        resp.add(theGeom.getBounds2D());
3515
                    }
3516
                }
3517

    
3518
                while (rs.next()) {
3519
                    auxstr = (STRUCT) rs.getObject(1);
3520

    
3521
                    if (auxstr != null) {
3522
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3523

    
3524
                        if (resp == null) {
3525
                            resp = theGeom.getBounds2D();
3526
                        }
3527
                        else {
3528
                            resp.add(theGeom.getBounds2D());
3529
                        }
3530
                    }
3531
                }
3532

    
3533
                rs.close();
3534
                st.close();
3535
            }
3536
            else {
3537
                throw new SQLException("Empty resultset from this query: " +
3538
                    _qry);
3539
            }
3540
        }
3541
        catch (SQLException se) {
3542
            System.err.println("Error while getting sample full extent: " +
3543
                se.getMessage());
3544
        }
3545

    
3546
        if (resp == null) {
3547
            logger.warn(
3548
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3549

    
3550
            return new Rectangle2D.Double(-180, -90, 360, 180);
3551
        }
3552

    
3553
        return resp;
3554
    }
3555

    
3556
    /**
3557
     * Does what it says, puts the LinearRing in counter clock wise
3558
     * order.
3559
     * @param ls The ring to set.
3560
     * @param gf a GeometryFactory object
3561
     * @return A new ring in CCW order.
3562
     *
3563
     */
3564
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3565
        Coordinate[] cc = ls.getCoordinates();
3566

    
3567
        if (CGAlgorithms.isCCW(cc)) {
3568
            return gf.createLinearRing(cc);
3569
        }
3570
        else {
3571
            if (ls instanceof LinearRing) {
3572
                return reverseRing((LinearRing) ls, gf);
3573
            }
3574
            else {
3575
                return reverseLineString(ls, gf);
3576
            }
3577
        }
3578
    }
3579

    
3580
    /**
3581
     * Does what it says, reverses the order of the Coordinates in the ring.
3582
     * @param lr The ring to reverse.
3583
     * @return A new ring with the reversed Coordinates.
3584
     *
3585
     */
3586
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3587
        int numPoints = lr.getNumPoints() - 1;
3588
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3589

    
3590
        for (int t = numPoints; t >= 0; t--) {
3591
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3592
        }
3593

    
3594
        return gf.createLinearRing(newCoords);
3595
    }
3596

    
3597
    /**
3598
     * Does what it says, reverses the order of the Coordinates in the linestring.
3599
     * @param ls The ls to reverse.
3600
     * @param gf a GeometryFactory object 
3601
     * @return A new ls with the reversed Coordinates.
3602
     *
3603
     */
3604
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3605
        int numPoints = ls.getNumPoints() - 1;
3606
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3607

    
3608
        for (int t = numPoints; t >= 0; t--) {
3609
            newCoords[t] = ls.getCoordinateN(numPoints - t);
3610
        }
3611

    
3612
        return gf.createLinearRing(newCoords);
3613
    }
3614

    
3615
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3616
        if (ge instanceof MultiPolygon) {
3617
            MultiPolygon mp = (MultiPolygon) ge;
3618
            int size = ge.getNumGeometries();
3619
            Polygon[] pols = new Polygon[size];
3620

    
3621
            for (int i = 0; i < size; i++)
3622
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3623
                        gf);
3624

    
3625
            return new MultiPolygon(pols, gf);
3626
        }
3627
        else {
3628
            if (ge instanceof Polygon) {
3629
                Polygon p = (Polygon) ge;
3630
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3631
                int nholes = p.getNumInteriorRing();
3632

    
3633
                if (nholes > 0) {
3634
                    LinearRing[] holes = new LinearRing[nholes];
3635

    
3636
                    for (int i = 0; i < nholes; i++) {
3637
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3638
                    }
3639

    
3640
                    return gf.createPolygon(exterior, holes);
3641
                }
3642
                else {
3643
                    return gf.createPolygon(exterior, null);
3644
                }
3645
            }
3646
            else {
3647
                return ge;
3648
            }
3649
        }
3650
    }
3651

    
3652
    /**
3653
     * Converts from IGeometry to STRUCT
3654
     *
3655
     * @param ig the geometry to convert
3656
     * @param _forced_type forced type to use
3657
     * @param _conn connection
3658
     * @param _o_srid  SRS (oracle code)
3659
     * @param withSrid whether this STRUCT has a non-NULL SRS
3660
     * @param agu_bien whether or not to check the correctness of the holes
3661
     * @param _isGeoCS whether the SRS is geodetic or not
3662
     * @return the generated STRUCT
3663
     */
3664
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
3665
        Connection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
3666
        boolean _isGeoCS) {
3667
        if (ig instanceof FGeometryCollection) {
3668
            FGeometryCollection coll = (FGeometryCollection) ig;
3669

    
3670
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3671
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3672

    
3673
            // logger.error("Collections no soportadas por ahora.");
3674
            // return null;
3675
        }
3676
        else {
3677
            Shape shp = ig.getInternalShape();
3678

    
3679
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3680
                agu_bien, false, _isGeoCS);
3681
        }
3682
    }
3683

    
3684
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3685
        boolean agu_bien, boolean isView) {
3686
            
3687
            if (shp == null) return null; 
3688
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3689
            agu_bien, isView, isGeogCS);
3690
    }
3691

    
3692
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3693
        Connection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3694
        boolean isView, boolean _isGeoCS) {
3695
        int _srid = -1;
3696

    
3697
        if (o_srid.length() > 0) {
3698
            _srid = Integer.parseInt(o_srid);
3699
        }
3700

    
3701
        if (shp == null) {
3702
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3703

    
3704
            return null;
3705
        }
3706

    
3707
        if (shp instanceof Rectangle2D) {
3708
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3709
                _isGeoCS, o_srid, _conn);
3710
        }
3711

    
3712
        try {
3713
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3714
                    _srid, agu_bien, hasSrid);
3715

    
3716
            return the_struct;
3717
        }
3718
        catch (SQLException ex) {
3719
            logger.error("While creating STRUCT: " + ex.getMessage());
3720

    
3721
            return null;
3722
        }
3723
    }
3724

    
3725
    // -------------------------- not ready yet ----------------
3726
    public int getRowIndexByFID(IFeature _fid) {
3727
        if (isNotAvailableYet) {
3728
            return -1;
3729
        }
3730
        else {
3731
            return super.getRowIndexByFID(_fid);
3732
        }
3733
    }
3734

    
3735
    public int getShapeCount() throws IOException {
3736
        if (isNotAvailableYet) {
3737
            return 0;
3738
        }
3739
        else {
3740
            return numReg;
3741
        }
3742
    }
3743

    
3744
    public void setNotAvailableYet(boolean nav) {
3745
        isNotAvailableYet = nav;
3746
    }
3747

    
3748
    // -------------------------------------------------------
3749
    // -------------------------------------------------------
3750
    public String[] getTableNames(Connection conn, String catalog)
3751
        throws SQLException {
3752
        DatabaseMetaData dbmd = conn.getMetaData();
3753
        String[] types = { "TABLE", "VIEW" };
3754

    
3755
        ResultSet rs = null;
3756
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3757
                    ORACLE_GEOMETADATA_VIEW, types), conn);
3758

    
3759
        TreeMap ret = new TreeMap();
3760

    
3761
        while (rs.next()) {
3762
            ret.put(rs.getString("TABLE_NAME"), rs.getString("TABLE_NAME"));
3763
        }
3764

    
3765
        return (String[]) ret.keySet().toArray(new String[0]);
3766
    }
3767

    
3768
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3769
        throws SQLException {
3770
        String tablename = "";
3771
        
3772
        
3773

    
3774
        if (res.next()) {
3775
            tablename = res.getString("TABLE_NAME");
3776
            
3777
            // debug 
3778
            // writeMetaTableToLog(con, tablename);
3779

    
3780
            Statement __st = con.createStatement();
3781

    
3782
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3783
                "union (select VIEW_NAME from USER_VIEWS)) " +
3784
                "intersect (select TABLE_NAME from " + tablename + ")";
3785
            ResultSet rs = __st.executeQuery(sql);
3786

    
3787
            return rs;
3788
        }
3789
        else {
3790
            logger.error("Error while getting geometry tables.");
3791

    
3792
            return null;
3793
        }
3794
    }
3795

    
3796
    private void writeMetaTableToLog(Connection con, String tname) {
3797
            
3798
            logger.debug("======================================================");
3799
            logger.debug("=     USER_SDO_GEOM_METADATA     =====================");
3800
            logger.debug("======================================================");
3801

    
3802
            try {
3803
            Statement _stmt = con.createStatement();
3804
            String sql = "SELECT * FROM " + tname;
3805
            ResultSet res = _stmt.executeQuery(sql);
3806
            while (res.next()) {
3807
                    logger.debug("======================================================");
3808
                    logger.debug("TABLE_NAME: " + res.getString("TABLE_NAME"));
3809
                    logger.debug("COLUMN_NAME: " + res.getString("COLUMN_NAME"));
3810
                    logger.debug("SRID: " + res.getString("SRID"));
3811
                    
3812
                    ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3813
                    String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3814
                    logger.debug("DIMINFO: " + dinfo);
3815
                    logger.debug("======================================================");
3816
                    
3817
            }
3818
            } catch (Throwable th) {
3819
                    
3820
            }
3821
            
3822
            
3823
            
3824
            
3825
            
3826
                // TODO Auto-generated method stub
3827
                
3828
        }
3829

    
3830
        /**
3831
     * Gets the field names that can act as row id (always ROWID)
3832
     */
3833
    public String[] getIdFieldsCandidates(Connection conn, String table_name)
3834
        throws SQLException {
3835
        String[] resp = { "ROWID" };
3836

    
3837
        return resp;
3838
    }
3839

    
3840
    /**
3841
     * Gets the field names that can act as geometry fields
3842
     * (queries the user's geographic metadata).
3843
     */
3844
    public String[] getGeometryFieldsCandidates(Connection conn,
3845
        String table_name) throws SQLException {
3846
        Statement _st = conn.createStatement();
3847
        String qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3848
            " where TABLE_NAME = " + "'" + table_name + "'";
3849
        ResultSet _rs = _st.executeQuery(qry);
3850

    
3851
        ArrayList aux = new ArrayList();
3852

    
3853
        while (_rs.next()) {
3854
            String _geo = _rs.getString("COLUMN_NAME");
3855
            aux.add(_geo);
3856
        }
3857

    
3858
        _rs.close();
3859
        _st.close();
3860

    
3861
        return (String[]) aux.toArray(new String[0]);
3862
    }
3863

    
3864
    /**
3865
     * Utility method to check if a given table is empty.
3866
     */
3867
    public boolean isEmptyTable(Connection conn, String tableName) {
3868
        boolean res = true;
3869

    
3870
        try {
3871
            Statement st = conn.createStatement();
3872
            ResultSet rs = null;
3873
            rs = st.executeQuery("select * from " + tableName +
3874
                    " where rownum = 1");
3875
            res = !rs.next();
3876
            rs.close();
3877
            st.close();
3878
        }
3879
        catch (Exception ex) {
3880
            res = true;
3881
        }
3882

    
3883
        return res;
3884
    }
3885

    
3886
    /**
3887
     * Gets all the fields from a table name.
3888
     */
3889
    public String[] getAllFields(Connection conn, String table_name)
3890
        throws SQLException {
3891
        Statement st = conn.createStatement();
3892
        ResultSet rs = st.executeQuery("select * from " + table_name +
3893
                " where rownum = 1");
3894
        ResultSetMetaData rsmd = rs.getMetaData();
3895
        String[] ret = new String[rsmd.getColumnCount()];
3896

    
3897
        for (int i = 0; i < ret.length; i++) {
3898
            ret[i] = rsmd.getColumnName(i + 1);
3899
        }
3900

    
3901
        rs.close();
3902
        st.close();
3903

    
3904
        return ret;
3905
    }
3906

    
3907
    /**
3908
     * Gets all field type names from a table.
3909
     */
3910
    public String[] getAllFieldTypeNames(Connection conn, String table_name)
3911
        throws SQLException {
3912
        Statement st = conn.createStatement();
3913
        ResultSet rs = st.executeQuery("select * from " + table_name +
3914
                " where rownum = 1");
3915
        ResultSetMetaData rsmd = rs.getMetaData();
3916
        String[] ret = new String[rsmd.getColumnCount()];
3917

    
3918
        for (int i = 0; i < ret.length; i++) {
3919
            ret[i] = rsmd.getColumnTypeName(i + 1);
3920
        }
3921

    
3922
        rs.close();
3923
        st.close();
3924

    
3925
        close();
3926

    
3927
        return ret;
3928
    }
3929

    
3930
    /**
3931
     * Gets Oracle's specific connection string for the given parameters.
3932
     */
3933
    public String getConnectionString(String host, String port, String dbname,
3934
        String user, String pw) {
3935
        String _pw = pw;
3936

    
3937
        if (_pw == null) {
3938
            _pw = "null";
3939
        }
3940

    
3941
        String fullstr = CONN_STR_BEGIN;
3942
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
3943
        fullstr = fullstr + "@" + host.toLowerCase();
3944
        fullstr = fullstr + ":" + port;
3945
        fullstr = fullstr + ":" + dbname.toLowerCase();
3946

    
3947
        return fullstr;
3948
    }
3949

    
3950
    /**
3951
     * Gets the Pracle geometries writer associated with this driver.
3952
     */
3953
    public IWriter getWriter() {
3954
        // on(VectorialEditableDBAdapter.java:290)
3955
        if (writer == null) {
3956
            writer = new OracleSpatialWriter(getRowCount());
3957
            writer.setDriver(this);
3958
            writer.setLyrShapeType(getShapeType());
3959
            writer.setGeoCS(isGeogCS());
3960
            writer.setGeoColName(geoColName);
3961
            writer.setSRID(oracleSRID);
3962

    
3963
            try {
3964
                writer.initialize(getLyrDef());
3965
            }
3966
            catch (EditionException e) {
3967
                logger.error("While initializing OS Writer: " + e.getMessage(),
3968
                    e);
3969
            }
3970

    
3971
            writer.setStoreWithSrid(tableHasSrid);
3972
        }
3973

    
3974
        return writer;
3975
    }
3976

    
3977
    /**
3978
     * Tells whether the SRS is geodetic or not
3979
     * @return whether the SRS is geodetic or not
3980
     */
3981
    public boolean isGeogCS() {
3982
        return isGeogCS;
3983
    }
3984

    
3985
    /**
3986
     * Adds a row id to the inner set od IDs.
3987
     * @param id
3988
     */
3989
    public void addRow(String id) {
3990
        Value aux = ValueFactory.createValue(id);
3991
        Integer intobj = new Integer(numReg);
3992
        hashRelate.put(aux, intobj);
3993
        rowToId.put(intobj, id);
3994

    
3995
        numReg++;
3996
    }
3997

    
3998
    /**
3999
     * Removes a row id to the inner set od IDs.
4000
     * @param id
4001
     */
4002
    public void deleteRow(String id) {
4003
        Value aux = ValueFactory.createValue(id);
4004
        Integer intobj = (Integer) hashRelate.get(aux);
4005
        hashRelate.remove(aux);
4006
        rowToId.remove(intobj);
4007

    
4008
        numReg--;
4009
    }
4010

    
4011
    private String getStandardSelectExpression() {
4012
        if (standardSelectExpressionFalse == null) {
4013
            standardSelectExpressionFalse = "";
4014

    
4015
            String[] flds = getLyrDef().getFieldNames();
4016
            int size = flds.length;
4017

    
4018
            for (int i = 0; i < size; i++) {
4019
                if (i > 0) {
4020
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4021
                        "c.\"" + flds[i] + "\", ";
4022
                }
4023
                else {
4024
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4025
                        flds[i] + ", ";
4026
                }
4027
            }
4028

    
4029
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4030
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4031
                    standardSelectExpressionFalse.length() - 2);
4032
        }
4033

    
4034
        return standardSelectExpressionFalse;
4035
    }
4036

    
4037
    /**
4038
     * Allows the method to decide what to do with the geometry field name
4039
     * (remove/add it from the user selected fields).
4040
     *
4041
     * @param flds
4042
     * @param geof
4043
     * @return the possibly modified field names
4044
     */
4045
    public String[] manageGeometryField(String[] flds, String geof) {
4046
        return addEndIfNotContained(flds, geof);
4047
    }
4048

    
4049
    /**
4050
     * Allows the method to decide what to do with the ID field name
4051
     * (remove/add it from the user selected fields).
4052
     *
4053
     * @param flds
4054
     * @param idf
4055
     * @return the possibly modified field names
4056
     */
4057
    public String[] manageIdField(String[] flds, String idf) {
4058
        return addStartIfNotContained(flds, idf);
4059
    }
4060

    
4061
    private String[] addEndIfNotContained(String[] arr, String item) {
4062
        if (contains(arr, item)) {
4063
            return arr;
4064
        }
4065
        else {
4066
            int size = arr.length;
4067
            String[] resp = new String[size + 1];
4068

    
4069
            for (int i = 0; i < size; i++) {
4070
                resp[i] = arr[i];
4071
            }
4072

    
4073
            resp[size] = item;
4074

    
4075
            return resp;
4076
        }
4077
    }
4078

    
4079
    private String[] addStartIfNotContained(String[] arr, String item) {
4080
        if (contains(arr, item)) {
4081
            return arr;
4082
        }
4083
        else {
4084
            int size = arr.length;
4085
            String[] resp = new String[size + 1];
4086

    
4087
            for (int i = 1; i <= size; i++) {
4088
                resp[i] = arr[i];
4089
            }
4090

    
4091
            resp[0] = item;
4092

    
4093
            return resp;
4094
        }
4095
    }
4096

    
4097
    private boolean contains(String[] arr, String item) {
4098
        for (int i = 0; i < arr.length; i++) {
4099
            if (arr[i].compareTo(item) == 0) {
4100
                return true;
4101
            }
4102
        }
4103

    
4104
        return false;
4105
    }
4106

    
4107
    /**
4108
     * This method is called when the user removes the layer from the view.
4109
     * If the IDs were being loaded, the driver will check this field and will
4110
     * let the thread 'die' quietly.
4111
     *
4112
     */
4113
    public void remove() {
4114
        cancelIDLoad = true;
4115
    }
4116
    
4117
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4118
            if (!isgeodetic) return true;
4119
            if (ext.getMinX() > -179.99) return true; 
4120
            if (ext.getMinY() > -89.99) return true; 
4121
            if (ext.getWidth() < 359.99) return true; 
4122
            if (ext.getHeight() < 179.99) return true; 
4123
            return false;
4124
    }
4125
    
4126
    private Rectangle2D getFastEstimatedGeodeticExtent(
4127
                    String tname, String gfield, Connection c, int sample_size, double enlargement) {
4128

    
4129
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4130
            Rectangle2D resp_aux = null;
4131
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4132
            ResultSet _rs = null;
4133

    
4134
            try {
4135
                        PreparedStatement _st = c.prepareStatement(qry);
4136
                        _rs = _st.executeQuery();
4137
                        while (_rs.next()) {
4138
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4139
                                IGeometry ig = getGeometryUsing(aux, false);
4140
                                
4141
                                if (ig == null) continue;
4142
                                
4143
                                if (resp_aux == null) {
4144
                                        resp_aux = ig.getBounds2D();
4145
                                } else {
4146
                                        resp_aux.add(ig.getBounds2D());
4147
                                }
4148
                                
4149
                        }
4150
                } catch (Exception ex) {
4151
                        logger.error("While getting random sample: " + ex.getMessage());
4152
                        return world;
4153
                }
4154
                
4155
                if (resp_aux == null) return world;
4156
                double w = resp_aux.getWidth();
4157
                double h = resp_aux.getHeight();
4158
                double x = resp_aux.getMinX();
4159
                double y = resp_aux.getMinY();
4160
                
4161
                // enlarge 10 times:
4162
                double newx = x - (0.5 * (enlargement - 1)) * w;
4163
                double newy = y - (0.5 * (enlargement - 1)) * w;
4164
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4165
                                enlargement * w,
4166
                                enlargement * h);
4167
                
4168
                
4169
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4170
                
4171
                logger.debug("FAST BB:");
4172
                logger.debug(" min x:" + resp_aux.getMinX());
4173
                logger.debug(" min y:" + resp_aux.getMinY());
4174
                logger.debug("     w:" + resp_aux.getWidth());
4175
                logger.debug("     h:" + resp_aux.getHeight());
4176
                return resp_aux;
4177
    }
4178
    
4179
    private Rectangle2D getEstimatedGeodeticExtent(
4180
                    String tname, String gfield, Connection c, int sample_size, double enlargement) {
4181
            
4182
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4183
            
4184
            ArrayList ids = new ArrayList();
4185
            int _rnd_index = 0;
4186
            ROWID _id = null;
4187
            Random rnd = new Random(System.currentTimeMillis());
4188
            
4189
            for (int i=0; i<sample_size; i++) {
4190
                    _rnd_index = rnd.nextInt(numReg);
4191
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
4192
                    ids.add(_id.stringValue());
4193
            }
4194
            
4195
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
4196
            for (int i=0; i<ids.size(); i++) {
4197
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR "; 
4198
            }
4199
            qry = qry.substring(0, qry.length() - 4) + ")";
4200
            
4201
            Rectangle2D resp_aux = null;
4202
            ResultSet _rs = null;
4203

    
4204
            try {
4205
                        PreparedStatement _st = c.prepareStatement(qry);
4206
                        _rs = _st.executeQuery();
4207
                        while (_rs.next()) {
4208
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4209
                                IGeometry ig = getGeometryUsing(aux, false);
4210
                                
4211
                                if (ig == null) continue;
4212
                                
4213
                                if (resp_aux == null) {
4214
                                        resp_aux = ig.getBounds2D();
4215
                                } else {
4216
                                        resp_aux.add(ig.getBounds2D());
4217
                                }
4218
                                
4219
                        }
4220
                } catch (Exception ex) {
4221
                        logger.error("While getting random sample: " + ex.getMessage());
4222
                        return world;
4223
                }
4224
                
4225
                if (resp_aux == null) return world;
4226
                double w = resp_aux.getWidth();
4227
                double h = resp_aux.getHeight();
4228
                double x = resp_aux.getMinX();
4229
                double y = resp_aux.getMinY();
4230
                
4231
                // enlarge 10 times:
4232
                double newx = x - (0.5 * (enlargement - 1)) * w;
4233
                double newy = y - (0.5 * (enlargement - 1)) * w;
4234
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4235
                                enlargement * w,
4236
                                enlargement * h);
4237
                
4238
                
4239
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4240
                return resp_aux;
4241
    }
4242
    
4243
    
4244
    
4245
}