Statistics
| Revision:

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

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 = "ALL_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
        setDestProjection(lyrDef.getSRID_EPSG());
318
        
319
        IProjection viewProj = CRSFactory.getCRS("EPSG:" + destProj);
320
        IProjection tableProj = CRSFactory.getCRS("EPSG:" + epsgSRID);
321
        ICoordTrans reprojecter = viewProj.getCT(tableProj);
322

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

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

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

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

    
352

    
353
        if (cancelIDLoad) {
354
            return;
355
        }
356
    }
357

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

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

    
369
            ArrayList types = new ArrayList();
370
            int aux = 0;
371

    
372
            ARRAY info_aux;
373
            int[] info_aux_int;
374
            int size;
375

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

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

    
386
                types.add(new Integer(aux % 1000));
387

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

    
393
            _rs.close();
394
            _st.close();
395

    
396
            boolean resp = hasSeveralGeometryTypes(types, false);
397

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

    
405
        return false;
406
    }
407

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

    
413
        HashMap m = new HashMap();
414

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

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

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

    
426
        Iterator iter = m.keySet().iterator();
427
        iter.next();
428

    
429
        return iter.hasNext();
430
    }
431

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

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

    
440
            return ASSUMED_ORACLE_SRID;
441
        }
442

    
443
        return obj.toString();
444
    }
445

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

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

    
457
            STRUCT sx = (STRUCT) da[0];
458
            STRUCT sy = (STRUCT) da[1];
459

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

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

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

    
478
                return getRectangle(minx, maxx, miny, maxy);
479

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

    
486
                return null;
487

    
488
                // fullExtentJTS = null;
489
            }
490
        }
491
    }
492

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

    
500
            if (_rs.next()) {
501
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
502

    
503
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
504

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

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

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

    
544
        if (!thas) return false;
545
        int ora_cs = 0;
546

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

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

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

    
566
        return resp;
567
    }
568

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

    
574
            st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
575
                    ResultSet.CONCUR_READ_ONLY);
576

    
577
            ResultSet _rs = st.executeQuery(_sql + " where (rownum = 1)");
578

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

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

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

    
594
            DatabaseMetaData dbmd = conn.getMetaData();
595
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
596

    
597
            int cnt = metaData.getColumnCount();
598
            fieldNames = new String[cnt];
599

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

    
604
            getIdFieldNames();
605

    
606
            adjustLyrDef();
607

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

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

    
618
        switch (code) {
619
        case 1:
620
            return FShape.POINT;
621

    
622
        case 2:
623
            return FShape.LINE;
624

    
625
        case 3:
626
            return FShape.POLYGON;
627

    
628
        case 5:
629
            return FShape.MULTIPOINT;
630

    
631
        case 6:
632
            return FShape.LINE;
633

    
634
        case 7:
635
            return FShape.POLYGON;
636
        }
637

    
638
        logger.error("Unknown geometry type: " + code);
639

    
640
        return FShape.NULL;
641
    }
642

    
643
    private String getIdFieldNames() {
644
        try {
645
            idFieldNames = "";
646

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

    
655
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
656

    
657
        return idFieldNames;
658
    }
659

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

    
664
        return _res;
665
    }
666

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

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

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

    
687
        singleCachedFeatureRowNum = -1;
688

    
689
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
690

    
691
        ResultSet localrs = (ResultSet) rs_st[0];
692
        Statement _st = (Statement) rs_st[1];
693

    
694
        return new OracleSpatialFeatureIterator(this, localrs, _st,
695
            oneBasedGeoColInd, use_geotools);
696
    }
697

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

    
706
    public void open() throws DriverException {
707
    }
708

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

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

    
727
        singleCachedFeatureRowNum = -1;
728

    
729
        STRUCT local_st = shapeToStruct(r, FShape.NULL, true, false, true);
730

    
731
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
732

    
733
        ResultSet localrs = (ResultSet) rs_st[0];
734
        Statement _st = (Statement) rs_st[1];
735

    
736
        return new OracleSpatialFeatureIterator(this, localrs, _st,
737
            oneBasedGeoColInd, use_geotools);
738
    }
739

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

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

    
754
            // return emptyIt;
755
        }
756

    
757
        singleCachedFeatureRowNum = -1;
758

    
759
        return getFeatureIterator(r, strEPSG);
760
    }
761

    
762
    public String getGeometryField(String fieldName) {
763
        return fieldName;
764

    
765
        // return "ASBINARY(" + fieldName + ")";
766
    }
767

    
768
    public DriverAttributes getDriverAttributes() {
769
        return drvAtts;
770
    }
771

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

    
782
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
783

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

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

    
791
            // Statement stmnt = conn.createStatement();
792
            ps.execute();
793

    
794
            ResultSet _res = ps.getResultSet();
795

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

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

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

    
816
    public boolean isWritable() {
817
        return true;
818
    }
819

    
820
    public String getName() {
821
        return NAME;
822
    }
823

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

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

    
833
    private void setIdRowTable() {
834
        hashRelate = new Hashtable();
835

    
836
        java.sql.PreparedStatement ps = null;
837

    
838
        try {
839
            String _sql = getIdAndElemInfoFullResulltSetQuery();
840

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

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

    
854
            ROWID ri = null;
855

    
856
            int row = 0;
857
            String gid;
858
            Value aux = null;
859

    
860
            // ----------------------------------- types init
861
            ArrayList types = new ArrayList();
862
            int types_aux = 0;
863

    
864
            ARRAY info_aux;
865
            int[] info_aux_int;
866
            int size;
867

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

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

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

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

    
887
                        return;
888
                    }
889

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

    
895
                row++;
896

    
897
                // --------------------------------------- types
898
                info_aux = (ARRAY) _r.getObject(2);
899

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

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

    
913
                // --------------------------------------- types end
914
            }
915

    
916
            _r.close();
917
//            ps.close();
918
            st.close();
919
            numReg = row;
920

    
921
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
922

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

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

    
944
    public String[] getFieldNames() {
945
        return fieldNames;
946
    }
947

    
948
    public String getTotalFields() {
949
        String strAux = "";
950

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

    
960
        return strAux;
961
    }
962

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

    
967
        try {
968
            i = idField + 1; // idField viene basado en 0
969

    
970
            int __type = metaData.getColumnType(i);
971

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

    
978
            if (__type == Types.VARCHAR) {
979
                return Types.VARCHAR;
980
            }
981

    
982
            if (__type == Types.FLOAT) {
983
                return Types.FLOAT;
984
            }
985

    
986
            if (__type == Types.DOUBLE) {
987
                return Types.DOUBLE;
988
            }
989

    
990
            if (__type == Types.INTEGER) {
991
                return Types.INTEGER;
992
            }
993

    
994
            if (__type == Types.SMALLINT) {
995
                return Types.SMALLINT;
996
            }
997

    
998
            if (__type == Types.TINYINT) {
999
                return Types.TINYINT;
1000
            }
1001

    
1002
            if (__type == Types.BIGINT) {
1003
                return Types.BIGINT;
1004
            }
1005

    
1006
            if (__type == Types.BIT) {
1007
                return Types.BIT;
1008
            }
1009

    
1010
            if (__type == Types.DATE) {
1011
                return Types.DATE;
1012
            }
1013

    
1014
            if (__type == Types.DECIMAL) {
1015
                return Types.DOUBLE;
1016
            }
1017

    
1018
            if (__type == Types.NUMERIC) {
1019
                return Types.DOUBLE;
1020
            }
1021

    
1022
            if (__type == Types.DATE) {
1023
                return Types.DATE;
1024
            }
1025

    
1026
            if (__type == Types.TIME) {
1027
                return Types.TIME;
1028
            }
1029

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

    
1039
        return -1;
1040
    }
1041

    
1042
    public Value[] getAttributes(ResultSet rs) {
1043
        Value[] res = null;
1044

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

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

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

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

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

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

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

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

    
1109
            return null;
1110
        }
1111

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

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

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

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

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

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

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

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

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

    
1182
            return null;
1183
        }
1184

    
1185
        return res;
1186
    }
1187
    
1188

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

    
1194
    public int getFieldWidth(int fieldId) {
1195
        int i = -1;
1196

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

    
1205
        if (i < 0) {
1206
            i = 255;
1207
        }
1208

    
1209
        return i;
1210
    }
1211

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

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

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

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

    
1231
            ps = conn.prepareStatement(rnq);
1232
            ps.setObject(1, _id);
1233

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

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

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

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

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

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

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

    
1279
    public Rectangle2D getFullExtent() {
1280
            return full_Extent;
1281
    }
1282

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

    
1295
        if (theStruct == null) {
1296
            return nullGeom;
1297
        }
1298

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

    
1306
        return _igeom;
1307
    }
1308

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

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

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

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

    
1325
            break;
1326

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

    
1331
            break;
1332

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

    
1337
            break;
1338

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

    
1343
            break;
1344
        }
1345

    
1346
        return ig;
1347
    }
1348

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

    
1355
        Datum[] all_info_array = null;
1356
        Object[] elems_info_aray = null;
1357
        Datum[] all_ords = null;
1358

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

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

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

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

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

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

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

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

    
1400
            STRUCT itemst = null;
1401

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

    
1411
            geoms[i] = getFMapGeometry(itemst, true);
1412
        }
1413

    
1414
        return new FGeometryCollection(geoms);
1415
    }
1416

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

    
1427
        try {
1428
            the_data = st.getOracleAttributes();
1429

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

    
1433
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1434

    
1435
            if (dim < 2) {
1436
                dim = 2;
1437
            }
1438

    
1439
            IGeometry ig = null;
1440

    
1441
            if (isActuallyACollection(the_data)) {
1442
                jgtype = FShape.MULTI;
1443
            }
1444

    
1445
            switch (jgtype) {
1446
            case FShape.MULTI:
1447

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

    
1451
                break;
1452

    
1453
            case FShape.POINT:
1454
                ig = getFMapGeometryPoint(the_data, dim);
1455

    
1456
                break;
1457

    
1458
            case FShape.LINE:
1459
                ig = getFMapGeometryMultiLineString(the_data, dim);
1460

    
1461
                break;
1462

    
1463
            case FShape.POLYGON:
1464
                ig = getFMapGeometryMultipolygon(the_data, dim);
1465

    
1466
                break;
1467
            }
1468

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

    
1475
        return null;
1476
    }
1477

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

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

    
1486
        return resp;
1487
    }
1488

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

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

    
1497
        return resp;
1498
    }
1499

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

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

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

    
1519
        return ig;
1520
    }
1521

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

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

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

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

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

    
1550
        return ig;
1551
    }
1552

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

    
1560
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1561

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

    
1565
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1566

    
1567
        return circ;
1568
    }
1569

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

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

    
1580
            return new FNullGeometry();
1581
        }
1582

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

    
1588
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1589

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

    
1593
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1594

    
1595
        return circ;
1596
    }
1597

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

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

    
1611
        return ig;
1612
    }
1613

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

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

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

    
1629
        return ig;
1630
    }
1631

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

    
1635
            return getFMapGeometrySdoPoint(jg_point, dim);
1636
        }
1637

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

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

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

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

    
1671
        return ig;
1672
    }
1673

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

    
1677
        if (ords == null) { // sdo_point
1678

    
1679
            return getFMapGeometrySdoPoint(the_data, dim);
1680
        }
1681

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

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

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

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

    
1715
        return ig;
1716
    }
1717

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

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

    
1729
        return ig;
1730
    }
1731

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

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

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

    
1751
        IGeometry ig = null;
1752

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

    
1760
        return ig;
1761
    }
1762

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

    
1766
        if (info == null) {
1767
            return false; // sdo_point
1768
        }
1769

    
1770
        int size = info.length / 3;
1771

    
1772
        if (size == 1) {
1773
            return false;
1774
        }
1775

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

    
1780
        int second = info[4] % 1000;
1781

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

    
1788
        return false;
1789
    }
1790

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

    
1794
        try {
1795
            ARRAY aux = (ARRAY) the_data[3];
1796

    
1797
            if (aux == null) {
1798
                return false;
1799
            }
1800

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

    
1806
            return false;
1807
        }
1808

    
1809
        if (info == null) {
1810
            return false; // sdo_point
1811
        }
1812

    
1813
        int size = info.length / 3;
1814

    
1815
        if (size == 1) {
1816
            return false;
1817
        }
1818

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

    
1823
        int second = info[4] % 1000;
1824

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

    
1831
        return false;
1832
    }
1833

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

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

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

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

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

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

    
1861
            JGeometry itemjg = null;
1862

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

    
1870
            geoms[i] = getFMapGeometry(itemjg, true);
1871
        }
1872

    
1873
        return new FGeometryCollection(geoms);
1874
    }
1875

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

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

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

    
1893
        return resp;
1894
    }
1895

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

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

    
1907
        return resp;
1908
    }
1909

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

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

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

    
1922
        return resp;
1923
    }
1924

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

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

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

    
1937
        return resp;
1938
    }
1939

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

    
1946
        return resp;
1947
    }
1948

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

    
1955
        return resp;
1956
    }
1957

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

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

    
1965
        return resp;
1966
    }
1967

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

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

    
1975
        return resp;
1976
    }
1977

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

    
1981
        if (resp.length == 1) {
1982
            resp[0] = all;
1983

    
1984
            return resp;
1985
        }
1986

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

    
1992
        int _start = _end + 1;
1993
        resp[ind] = ord_aux;
1994
        ind++;
1995

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

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

    
2010
        return resp;
2011
    }
2012

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

    
2016
        if (resp.length == 1) {
2017
            resp[0] = all;
2018

    
2019
            return resp;
2020
        }
2021

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

    
2027
        int _start = _end + 1;
2028
        resp[ind] = ord_aux;
2029
        ind++;
2030

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

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

    
2045
        return resp;
2046
    }
2047

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

    
2051
        int size = all_elem.length / 3;
2052

    
2053
        int[] aux = getNthGroupOfThree(all_elem, 0);
2054

    
2055
        int[] newaux;
2056
        int i = 1;
2057

    
2058
        while (i < size) {
2059
            newaux = getNthGroupOfThree(all_elem, i);
2060

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

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

    
2082
            i++;
2083
        }
2084

    
2085
        resp.add(aux);
2086

    
2087
        return resp.toArray();
2088
    }
2089

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

    
2093
        int size = all_elem.length / 3;
2094

    
2095
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2096

    
2097
        Datum[] newaux;
2098
        int i = 1;
2099

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

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

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

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

    
2132
        resp.add(aux);
2133

    
2134
        return resp.toArray();
2135
    }
2136

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

    
2141
        return ig;
2142
    }
2143

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

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

    
2155
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2156

    
2157
        return ig;
2158
    }
2159

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

    
2166
        switch (type) {
2167
        case FShape.LINE:
2168

    
2169
            FPolyline2D fpl = new FPolyline2D(gpx);
2170
            ig = ShapeFactory.createPolyline2D(gpx);
2171

    
2172
            break;
2173

    
2174
        case FShape.POLYGON:
2175

    
2176
            FPolygon2D fpg = new FPolygon2D(gpx);
2177
            ig = ShapeFactory.createPolygon2D(gpx);
2178

    
2179
            break;
2180
        }
2181

    
2182
        return ig;
2183
    }
2184

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

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

    
2232
        case JGeometry.GTYPE_CURVE:
2233
        case JGeometry.GTYPE_MULTICURVE:
2234
            return FShape.LINE;
2235
        }
2236

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

    
2240
        return FShape.NULL;
2241
    }
2242

    
2243
    private void cleanWhereClause() {
2244
        emptyWhereClause = false;
2245

    
2246
        String aux = getWhereClauseWithoutWhere();
2247

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

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

    
2274
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2275
        String resp = "";
2276

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

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

    
2301
    public void setWorkingArea(Rectangle2D rect) {
2302
    }
2303

    
2304
    private void setWAStructt() {
2305
    }
2306

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

    
2312
        int type = FShape.POLYGON;
2313

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

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

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

    
2326
        GeneralPathX wagp = new GeneralPathX(shp);
2327
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2328

    
2329
        return FConverter.java2d_to_jts(fwagp);
2330
    }
2331

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

    
2335
        return shape.getBounds2D();
2336
    }
2337

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

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

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

    
2354
        System.out.println("----------------------------------------------");
2355
    }
2356

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

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

    
2367
        STRUCT resp = null;
2368

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

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

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

    
2386
            new_obj[2] = null;
2387

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

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

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

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

    
2413
        return resp;
2414
    }
2415

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

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

    
2430
        System.err.println("main sel = " + main_sel);
2431

    
2432
        ResultSet _rs = null;
2433
        Statement _stmnt = null;
2434
        Object[] _resp = new Object[2];
2435

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

    
2442
            _rs = _stmnt.executeQuery(main_sel);
2443

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

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

    
2456
        return _resp;
2457
    }
2458

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

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

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

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

    
2477
            String aux = "";
2478

    
2479
            if (hasSrid) {
2480
                aux = oracleSRID;
2481

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

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

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

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

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

    
2529
                // resp = resp + " order by rowid";
2530
                return resp;
2531
        }
2532

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

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

    
2553
    public int getShapeType() {
2554
        return shapeType;
2555
    }
2556

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

    
2562
        if (old.length() <= 6) {
2563
            return old;
2564
        }
2565

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

    
2570
        return resp;
2571
    }
2572

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

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

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

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

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

    
2595
        double w = maxx - minx;
2596
        double h = maxy - miny;
2597

    
2598
        return new Rectangle2D.Double(minx, miny, w, h);
2599
    }
2600

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

    
2606
        case Types.LONGVARCHAR:
2607
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2608
        }
2609

    
2610
        return -1;
2611
    }
2612

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

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

    
2620
            break;
2621

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

    
2625
            break;
2626

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

    
2630
            break;
2631

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

    
2635
            break;
2636

    
2637
        case Types.DECIMAL:
2638
            aux = "NUMBER";
2639

    
2640
            break;
2641

    
2642
        case Types.NUMERIC:
2643
            aux = "NUMBER";
2644

    
2645
            break;
2646

    
2647
        case Types.DOUBLE:
2648
            aux = "FLOAT";
2649

    
2650
            break;
2651

    
2652
        case Types.FLOAT:
2653
            aux = "FLOAT";
2654

    
2655
            break;
2656

    
2657
        case Types.CHAR:
2658
            aux = "CHAR(1 BYTE)";
2659

    
2660
            break;
2661

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

    
2665
            break;
2666

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

    
2670
            break;
2671
        }
2672

    
2673
        return aux;
2674
    }
2675

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

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

    
2686
        String type = "";
2687
        String name = "";
2688

    
2689
        String resp = "CREATE TABLE \"" + dbLayerDef.getTableName() + "\" ( ";
2690

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

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

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

    
2710
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2711
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2712
        resp = resp + ", ";
2713

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

    
2718
        resp = resp + pk + " )";
2719

    
2720
        return resp;
2721
    }
2722

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

    
2729
        return resp;
2730
    }
2731

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

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

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

    
2761
            if (dim > 2) {
2762
                dim_name[2] = "Z";
2763

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

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

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

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

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

    
2797
        return resp;
2798
    }
2799

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

    
2817
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2818

    
2819
        String resp = "INSERT INTO \"" + dbLayerDef.getTableName() + "\" ( ";
2820

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

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

    
2837
        resp = resp + _geoColName + " ) VALUES ( ";
2838

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

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

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

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

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

    
2874
                            if (_aux.length() == 0) {
2875
                                _aux = "NULL";
2876
                            }
2877

    
2878
                            resp = resp + _aux + " , ";
2879
                        }
2880
                    }
2881
                }
2882
            }
2883
        }
2884

    
2885
        resp = resp + " ? )";
2886

    
2887
        return resp;
2888
    }
2889

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

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

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

    
2926
        String resp = "UPDATE \"" + dbLayerDef.getTableName() + "\" SET ";
2927

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

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

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

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

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

    
2960
        return resp;
2961
    }
2962

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

    
2971
        return false;
2972
    }
2973

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

    
2985
        return resp;
2986
    }
2987

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

    
2994
        int tpe = _flds[i].getFieldType();
2995
        int max_size = maxSizeForFieldType(tpe);
2996

    
2997
        if (max_size == -1) {
2998
            return orig_val;
2999
        }
3000

    
3001
        int or_size = orig_val.length();
3002

    
3003
        if (or_size <= max_size) {
3004
            return orig_val;
3005
        }
3006

    
3007
        return orig_val.substring(0, max_size);
3008
    }
3009

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

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

    
3019
        return "'";
3020
    }
3021

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

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

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

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

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

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

    
3056
                    if (i == 0) {
3057
                        resp = "" + aux;
3058
                    }
3059

    
3060
                    logger.error("" + aux);
3061
                }
3062

    
3063
                logger.error("===============");
3064

    
3065
                return resp;
3066
            }
3067

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

    
3075
        return resp;
3076
    }
3077

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

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

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

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

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

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

    
3113
                    if (i == 0) {
3114
                        resp = aux;
3115
                    }
3116

    
3117
                    logger.error("" + aux);
3118
                }
3119

    
3120
                logger.error("===============");
3121

    
3122
                return resp;
3123
            }
3124

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

    
3132
        return resp;
3133
    }
3134

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

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

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

    
3152
        // dbfdrv.setDataSourceFactory()
3153
        OFileDataSourceAdapter fdsa = new OFileDataSourceAdapter();
3154

    
3155
        fdsa.setDriver(dbfdrv);
3156

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

    
3165
        fdsa.setSourceInfo(fsi);
3166

    
3167
        SelectableDataSource sds = null;
3168
        EditableAdapter ea = new EditableAdapter();
3169
        ProjectTable pt = null;
3170

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

    
3180
        sds.setSourceInfo(fsi);
3181

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

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

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

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

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

    
3220
        return resp;
3221
    }
3222

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

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

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

    
3239
                resp.add(cc.get(0));
3240

    
3241
                return resp;
3242
            }
3243

    
3244
            if (cc.size() == 3) {
3245
                cc.remove(1);
3246

    
3247
                return ensureSensibleShell(cc);
3248
            }
3249

    
3250
            return cc;
3251
        }
3252
        else {
3253
            cc.add(cc.get(0));
3254

    
3255
            return cc;
3256
        }
3257
    }
3258

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

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

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

    
3275
                resp.add(cc.get(0));
3276

    
3277
                return resp;
3278
            }
3279

    
3280
            if (cc.size() == 3) {
3281
                cc.remove(1);
3282

    
3283
                return ensureSensibleHole(cc);
3284
            }
3285

    
3286
            return cc;
3287
        }
3288
        else {
3289
            cc.add(cc.get(0));
3290

    
3291
            return cc;
3292
        }
3293
    }
3294

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

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

    
3306
                return resp;
3307
            }
3308
        }
3309

    
3310
        return cc;
3311
    }
3312

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

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

    
3322
        return true;
3323
    }
3324

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

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

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

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

    
3343
            cc.add(cc.get(0));
3344

    
3345
            return cc;
3346
        }
3347

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

    
3353
        return cc;
3354
    }
3355

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

    
3360
        Coordinate nc = new Coordinate(c);
3361
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3362

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

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

    
3375
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3376

    
3377
        return mpo;
3378
    }
3379

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

    
3386
        return destProj;
3387
    }
3388

    
3389
    public String getDestProjection() {
3390
        return destProj;
3391
    }
3392

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

    
3419
    public boolean canReproject(String toEPSGdestinyProjection) {
3420
        return false;
3421
    }
3422

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

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

    
3440
        return true;
3441
    }
3442

    
3443
    public Hashtable getHashRelate() {
3444
        return hashRelate;
3445
    }
3446

    
3447
    public void setHashRelate(Hashtable m) {
3448
        hashRelate = m;
3449
    }
3450

    
3451
    public void setNumReg(int n) {
3452
        numReg = n;
3453
    }
3454

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

    
3458
        if (maxn_one_based <= n) {
3459
            resp = new int[maxn_one_based];
3460

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

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

    
3473
        return resp;
3474
    }
3475

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

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

    
3489
        resp = resp.substring(0, resp.length() - 4);
3490
        resp = resp + ")";
3491

    
3492
        return resp;
3493
    }
3494

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

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

    
3506
            if (rs.next()) {
3507
                auxstr = (STRUCT) rs.getObject(1);
3508

    
3509
                if (auxstr != null) {
3510
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3511

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

    
3520
                while (rs.next()) {
3521
                    auxstr = (STRUCT) rs.getObject(1);
3522

    
3523
                    if (auxstr != null) {
3524
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3525

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

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

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

    
3552
            return new Rectangle2D.Double(-180, -90, 360, 180);
3553
        }
3554

    
3555
        return resp;
3556
    }
3557

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

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

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

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

    
3596
        return gf.createLinearRing(newCoords);
3597
    }
3598

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

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

    
3614
        return gf.createLinearRing(newCoords);
3615
    }
3616

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

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

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

    
3635
                if (nholes > 0) {
3636
                    LinearRing[] holes = new LinearRing[nholes];
3637

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

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

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

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

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

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

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

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

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

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

    
3706
            return null;
3707
        }
3708

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

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

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

    
3723
            return null;
3724
        }
3725
    }
3726

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

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

    
3746
    public void setNotAvailableYet(boolean nav) {
3747
        isNotAvailableYet = nav;
3748
    }
3749

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

    
3757
        ResultSet rs = null;
3758
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3759
                    ORACLE_GEOMETADATA_VIEW, types), conn);
3760
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3761
//                          ORACLE_GEOMETADATA_VIEW, types);
3762
        TreeMap ret = new TreeMap();
3763

    
3764
        while (rs.next()) {
3765
            ret.put(rs.getString("TABLE_NAME"), rs.getString("TABLE_NAME"));
3766
        }
3767

    
3768
        return (String[]) ret.keySet().toArray(new String[0]);
3769
    }
3770

    
3771
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3772
        throws SQLException {
3773
        String tablename = "";
3774
        
3775
        
3776

    
3777
        if (res.next()) {
3778
            tablename = res.getString("TABLE_NAME");
3779
            
3780
            // debug 
3781
            // writeMetaTableToLog(con, tablename);
3782

    
3783
            Statement __st = con.createStatement();
3784

    
3785
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3786
                "union (select VIEW_NAME from USER_VIEWS)) " +
3787
                "intersect (select TABLE_NAME from " + tablename + ")";
3788
            sql = "SELECT TABLE_NAME FROM " + tablename + "";
3789
            ResultSet rs = __st.executeQuery(sql);
3790

    
3791
            return rs;
3792
        }
3793
        else {
3794
            logger.error("Error while getting geometry tables.");
3795

    
3796
            return null;
3797
        }
3798
    }
3799

    
3800
    private void writeMetaTableToLog(Connection con, String tname) {
3801
            
3802
            logger.debug("======================================================");
3803
            logger.debug("=     USER_SDO_GEOM_METADATA     =====================");
3804
            logger.debug("======================================================");
3805

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

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

    
3841
        return resp;
3842
    }
3843

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

    
3855
        ArrayList aux = new ArrayList();
3856

    
3857
        while (_rs.next()) {
3858
            String _geo = _rs.getString("COLUMN_NAME");
3859
            aux.add(_geo);
3860
        }
3861

    
3862
        _rs.close();
3863
        _st.close();
3864

    
3865
        return (String[]) aux.toArray(new String[0]);
3866
    }
3867

    
3868
    /**
3869
     * Utility method to check if a given table is empty.
3870
     */
3871
    public boolean isEmptyTable(Connection conn, String tableName) {
3872
        boolean res = true;
3873

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

    
3887
        return res;
3888
    }
3889

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

    
3901
        for (int i = 0; i < ret.length; i++) {
3902
            ret[i] = rsmd.getColumnName(i + 1);
3903
        }
3904

    
3905
        rs.close();
3906
        st.close();
3907

    
3908
        return ret;
3909
    }
3910

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

    
3922
        for (int i = 0; i < ret.length; i++) {
3923
            ret[i] = rsmd.getColumnTypeName(i + 1);
3924
        }
3925

    
3926
        rs.close();
3927
        st.close();
3928

    
3929
        close();
3930

    
3931
        return ret;
3932
    }
3933

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

    
3941
        if (_pw == null) {
3942
            _pw = "null";
3943
        }
3944

    
3945
        String fullstr = CONN_STR_BEGIN;
3946
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
3947
        fullstr = fullstr + "@" + host.toLowerCase();
3948
        fullstr = fullstr + ":" + port;
3949
        fullstr = fullstr + ":" + dbname.toLowerCase();
3950

    
3951
        return fullstr;
3952
    }
3953

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

    
3967
            try {
3968
                writer.initialize(getLyrDef());
3969
            }
3970
            catch (EditionException e) {
3971
                logger.error("While initializing OS Writer: " + e.getMessage(),
3972
                    e);
3973
            }
3974

    
3975
            writer.setStoreWithSrid(tableHasSrid);
3976
        }
3977

    
3978
        return writer;
3979
    }
3980

    
3981
    /**
3982
     * Tells whether the SRS is geodetic or not
3983
     * @return whether the SRS is geodetic or not
3984
     */
3985
    public boolean isGeogCS() {
3986
        return isGeogCS;
3987
    }
3988

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

    
3999
        numReg++;
4000
    }
4001

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

    
4012
        numReg--;
4013
    }
4014

    
4015
    private String getStandardSelectExpression() {
4016
        if (standardSelectExpressionFalse == null) {
4017
            standardSelectExpressionFalse = "";
4018

    
4019
            String[] flds = getLyrDef().getFieldNames();
4020
            int size = flds.length;
4021

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

    
4033
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4034
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4035
                    standardSelectExpressionFalse.length() - 2);
4036
        }
4037

    
4038
        return standardSelectExpressionFalse;
4039
    }
4040

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

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

    
4065
    private String[] addEndIfNotContained(String[] arr, String item) {
4066
        if (contains(arr, item)) {
4067
            return arr;
4068
        }
4069
        else {
4070
            int size = arr.length;
4071
            String[] resp = new String[size + 1];
4072

    
4073
            for (int i = 0; i < size; i++) {
4074
                resp[i] = arr[i];
4075
            }
4076

    
4077
            resp[size] = item;
4078

    
4079
            return resp;
4080
        }
4081
    }
4082

    
4083
    private String[] addStartIfNotContained(String[] arr, String item) {
4084
        if (contains(arr, item)) {
4085
            return arr;
4086
        }
4087
        else {
4088
            int size = arr.length;
4089
            String[] resp = new String[size + 1];
4090

    
4091
            for (int i = 1; i <= size; i++) {
4092
                resp[i] = arr[i];
4093
            }
4094

    
4095
            resp[0] = item;
4096

    
4097
            return resp;
4098
        }
4099
    }
4100

    
4101
    private boolean contains(String[] arr, String item) {
4102
        for (int i = 0; i < arr.length; i++) {
4103
            if (arr[i].compareTo(item) == 0) {
4104
                return true;
4105
            }
4106
        }
4107

    
4108
        return false;
4109
    }
4110

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

    
4133
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4134
            Rectangle2D resp_aux = null;
4135
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4136
            ResultSet _rs = null;
4137

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

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