Statistics
| Revision:

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

History | View | Annotate | Download (125 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[] tokens = getTableName().split("\\u002E", 2);
497
            String qry;
498
            if (tokens.length > 1)
499
            {
500
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
501
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" + 
502
                tokens[1] + "'";
503
            }
504
            else
505
            {
506
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
507
                " where TABLE_NAME = " + "'" + getTableName() + "'";
508

    
509
            }
510
//            String qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
511
//                " where TABLE_NAME = " + "'" + getTableName() + "'";
512
            ResultSet _rs = _st.executeQuery(qry);
513

    
514
            if (_rs.next()) {
515
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
516

    
517
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
518

    
519
                try {
520
                                        epsgSRID = oracleSridToEpsgSrid(oracleSRID);
521
                                } catch (Exception e) {
522
                                        logger.error("Unknown oracle SRID: " + oracleSRID);
523
                                        tableHasSrid = false;
524
                                }
525
                full_Extent = getFullExtentFromCurrentRecord(_rs);
526
                
527
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS); 
528
                
529
                if (!hasRealiableExtent) {
530
                        full_Extent = getFastEstimatedGeodeticExtent(
531
                                        getTableName(), geoColName, conn, 20, 10);
532
                }
533

    
534
                _rs.close();
535
                _st.close();
536
            }
537
            else {
538
                throw new SQLException("Empty resultset from this query: " +
539
                    qry);
540
            }
541
        }
542
        catch (SQLException se) {
543
            System.err.println("Error while getting SDO metadata: " +
544
                se.getMessage());
545
        }
546
    }
547

    
548
    /**
549
     * Utility method to find out if a coordinate system is geodetic or not.
550
     *
551
     * @param oracleSRID2 the coordinate system's oracle code
552
     * @param thas whether the table has a coordinate system set.
553
     * if not, the method returns false.
554
     * @return whether the coordinate system is geodetic or not.
555
     */
556
    public static boolean getIsGCS(String oracleSRID2, boolean thas) {
557

    
558
        if (!thas) return false;
559
        int ora_cs = 0;
560

    
561
        try {
562
            ora_cs = Integer.parseInt(oracleSRID2);
563
        }
564
        catch (Exception ex) {
565
            return false;
566
        }
567

    
568
        if (((ora_cs >= 8000) && (ora_cs <= 8999)) || (ora_cs == 524288)) {
569
            return true;
570
        } else {
571
                return false;
572
        }
573
    }
574

    
575
    private Rectangle2D getRectangle(double minx, double maxx, double miny,
576
        double maxy) {
577
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
578
                maxy - miny);
579

    
580
        return resp;
581
    }
582

    
583
    private void oneRowMetadata() {
584
        try {
585
            String _sql = "select " + getStandardSelectExpression() + ", c." +
586
                geoColName + " from " + getTableName() + " c ";
587

    
588
            st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
589
                    ResultSet.CONCUR_READ_ONLY);
590

    
591
            ResultSet _rs = st.executeQuery(_sql + " where (rownum = 1)");
592

    
593
            if (_rs.next()) {
594
                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
595
                shapeType = getShapeTypeOfStruct(sample_geo);
596
            }
597
            else {
598
                shapeType = FShape.MULTI;
599
            }
600

    
601
            // -----------------------
602
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
603
            metaData = _rs.getMetaData();
604

    
605
            // geoColInd = _rs.findColumn(geoColName);
606
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
607

    
608
            DatabaseMetaData dbmd = conn.getMetaData();
609
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
610

    
611
            int cnt = metaData.getColumnCount();
612
            fieldNames = new String[cnt];
613

    
614
            for (int i = 0; i < cnt; i++) {
615
                fieldNames[i] = metaData.getColumnName(i + 1);
616
            }
617

    
618
            getIdFieldNames();
619

    
620
            adjustLyrDef();
621

    
622
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan 
623
        }
624
        catch (SQLException se) {
625
            logger.error("While getting metadata. " + se.getMessage());
626
        }
627
    }
628

    
629
    private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
630
        int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue() % 10;
631

    
632
        switch (code) {
633
        case 1:
634
            return FShape.POINT;
635

    
636
        case 2:
637
            return FShape.LINE;
638

    
639
        case 3:
640
            return FShape.POLYGON;
641

    
642
        case 5:
643
            return FShape.MULTIPOINT;
644

    
645
        case 6:
646
            return FShape.LINE;
647

    
648
        case 7:
649
            return FShape.POLYGON;
650
        }
651

    
652
        logger.error("Unknown geometry type: " + code);
653

    
654
        return FShape.NULL;
655
    }
656

    
657
    private String getIdFieldNames() {
658
        try {
659
            idFieldNames = "";
660

    
661
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
662
                idFieldNames = idFieldNames +
663
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
664
            }
665
        }
666
        catch (SQLException se) {
667
        }
668

    
669
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
670

    
671
        return idFieldNames;
672
    }
673

    
674
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
675
        int[] _res = new int[1];
676
        _res[0] = 1;
677

    
678
        return _res;
679
    }
680

    
681
    public String getSqlTotal() {
682
        // TODO Auto-generated method stub
683
        return "";
684
    }
685

    
686
    public String getCompleteWhere() {
687
        // TODO Auto-generated method stub
688
        return "";
689
    }
690

    
691
    /**
692
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
693
     * and uses directly that sentence to query the table).
694
     */
695
    public IFeatureIterator getFeatureIterator(String sql)
696
        throws DriverException {
697
        if (isNotAvailableYet) {
698
            return null;
699
        }
700

    
701
        singleCachedFeatureRowNum = -1;
702

    
703
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
704

    
705
        ResultSet localrs = (ResultSet) rs_st[0];
706
        Statement _st = (Statement) rs_st[1];
707

    
708
        return new OracleSpatialFeatureIterator(this, localrs, _st,
709
            oneBasedGeoColInd, use_geotools);
710
    }
711

    
712
    /**
713
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
714
     */
715
    public String getConnectionStringBeginning() {
716
        // oracle
717
        return CONN_STR_BEGIN;
718
    }
719

    
720
    public void open() throws DriverException {
721
    }
722

    
723
    /**
724
     * Gets Oracle's default port: 1521
725
     */
726
    public int getDefaultPort() {
727
        // oracle port
728
        return 1521;
729
    }
730

    
731
    /**
732
     * Gets the feature iterator for a given rectangle (the view's bounding box)
733
     * and a SRS.
734
     */
735
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
736
        throws DriverException {
737
        if (isNotAvailableYet) {
738
            return null;
739
        } 
740

    
741
        singleCachedFeatureRowNum = -1;
742

    
743
        STRUCT local_st = shapeToStruct(r, FShape.NULL, true, false, true);
744

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

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

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

    
754
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
755
        if (workingAreaInTablesCS == null) return r;
756
        return doIntersect(r, workingAreaInTablesCS);
757
    }
758

    
759
    /**
760
     * This method reverts to the one without the fields specification.
761
     * The fields have been selected from the start.
762
     */
763
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
764
        String[] alphaNumericFieldsNeeded) throws DriverException {
765
        if (isNotAvailableYet) {
766
            return null;
767

    
768
            // return emptyIt;
769
        }
770

    
771
        singleCachedFeatureRowNum = -1;
772

    
773
        return getFeatureIterator(r, strEPSG);
774
    }
775

    
776
    public String getGeometryField(String fieldName) {
777
        return fieldName;
778

    
779
        // return "ASBINARY(" + fieldName + ")";
780
    }
781

    
782
    public DriverAttributes getDriverAttributes() {
783
        return drvAtts;
784
    }
785

    
786
    /**
787
     * Gets the requested geometry. Always performs a new query in this case.
788
     * This should be a rare way to get the geometries. The standard way is by using
789
     * the iterators.
790
     */
791
    public IGeometry getShape(int _ind) throws IOException {
792
        if (isNotAvailableYet) {
793
            return nullGeom;
794
        }
795

    
796
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
797

    
798
        String _sql = "select " + geoColName + " from " + getTableName() +
799
            " where rowid = ?";
800

    
801
        try {
802
            java.sql.PreparedStatement ps = conn.prepareStatement(_sql);
803
            ps.setObject(1, r_id);
804

    
805
            // Statement stmnt = conn.createStatement();
806
            ps.execute();
807

    
808
            ResultSet _res = ps.getResultSet();
809

    
810
            if (_res.next()) {
811
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
812
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
813
                _res.close();
814
                ps.close();
815

    
816
                return theGeom;
817
            }
818
            else {
819
                logger.error("Unable to get shape: " + _ind +
820
                    " (probably due to edition)");
821

    
822
                return nullGeom;
823
            }
824
        }
825
        catch (SQLException se) {
826
            throw new IOException("SQLException: " + se.getMessage());
827
        }
828
    }
829

    
830
    public boolean isWritable() {
831
        return true;
832
    }
833

    
834
    public String getName() {
835
        return NAME;
836
    }
837

    
838
    public int[] getPrimaryKeys()
839
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
840
        return pkOneBasedIndexes;
841
    }
842

    
843
    public void write(DataWare dataWare)
844
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
845
    }
846

    
847
    private void setIdRowTable() {
848
        hashRelate = new Hashtable();
849

    
850
        java.sql.PreparedStatement ps = null;
851

    
852
        try {
853
            String _sql = getIdAndElemInfoFullResulltSetQuery();
854

    
855
            logger.debug("SQL para leer ids: " + _sql);
856
            Statement st = null;
857

    
858
            
859
            st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
860
                        ResultSet.CONCUR_READ_ONLY);
861
            
862
            st.setFetchSize(FETCH_SIZE);
863
            logger.info("FETCH_SIZE = " + FETCH_SIZE);
864
            
865
            ResultSet _r = null;
866
            _r = st.executeQuery(_sql);
867

    
868
            ROWID ri = null;
869

    
870
            int row = 0;
871
            String gid;
872
            Value aux = null;
873

    
874
            // ----------------------------------- types init
875
            ArrayList types = new ArrayList();
876
            int types_aux = 0;
877

    
878
            ARRAY info_aux;
879
            int[] info_aux_int;
880
            int size;
881

    
882
            // ----------------------------------- types init
883
            logger.debug("Beginning of result set:");
884

    
885
            while (_r.next()) {
886
                // ---------------------------------------
887
                ri = (ROWID) _r.getObject(1);
888
                gid = ri.stringValue();
889
                aux = ValueFactory.createValue(gid);
890

    
891
                Integer intobj = new Integer(row);
892
                hashRelate.put(aux, intobj);
893
                rowToId.put(intobj, ri);
894

    
895
                if ((row % 5000) == 0) {
896
                    // ------------------------------------------- cancel load
897
                    if (cancelIDLoad) {
898
                        hashRelate.clear();
899
                        rowToId.clear();
900

    
901
                        return;
902
                    }
903

    
904
                    // -------------------------------------------
905
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
906
                    logger.info("IDs read: " + fmt);
907
                }
908

    
909
                row++;
910

    
911
                // --------------------------------------- types
912
                info_aux = (ARRAY) _r.getObject(2);
913

    
914
                if (info_aux == null) {
915
                    // logger.debug("NULL info array found in record: " + row);
916
                }
917
                else {
918
                    info_aux_int = info_aux.getIntArray();
919
                    size = info_aux_int.length / 3;
920

    
921
                    for (int i = 0; i < size; i++) {
922
                        types_aux = info_aux_int[(3 * i) + 1];
923
                        types.add(new Integer(types_aux % 1000));
924
                    }
925
                }
926

    
927
                // --------------------------------------- types end
928
            }
929

    
930
            _r.close();
931
//            ps.close();
932
            st.close();
933
            numReg = row;
934

    
935
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
936

    
937
            if (needsCollectionLayer) {
938
                shapeType = FShape.MULTI;
939
            }
940
        }
941
        catch (SQLException e) {
942
            System.err.println("While setting id-row hashmap: " +
943
                e.getMessage());
944
        }
945
    }
946

    
947
    public int getFieldCount()
948
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
949
        try {
950
            return metaData.getColumnCount();
951
        }
952
        catch (SQLException e) {
953
            System.err.println("While getting field count: " + e.getMessage());
954
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e.getMessage());
955
        }
956
    }
957

    
958
    public String[] getFieldNames() {
959
        return fieldNames;
960
    }
961

    
962
    public String getTotalFields() {
963
        String strAux = "";
964

    
965
        for (int i = 0; i < fieldNames.length; i++) {
966
            if (i == 0) {
967
                strAux = fieldNames[i];
968
            }
969
            else {
970
                strAux = strAux + ", " + fieldNames[i];
971
            }
972
        }
973

    
974
        return strAux;
975
    }
976

    
977
    public int getFieldType(int idField)
978
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
979
        int i = 0;
980

    
981
        try {
982
            i = idField + 1; // idField viene basado en 0
983

    
984
            int __type = metaData.getColumnType(i);
985

    
986
            // we must add this entry because we did not remove the 'geometry' column
987
            if (__type == Types.STRUCT) {
988
                return Types.VARCHAR; // .STRUCT;
989
                                      // ----------------------------------------------------------------------
990
            }
991

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

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

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

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

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

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

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

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

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

    
1028
            if (__type == Types.DECIMAL) {
1029
                return Types.DOUBLE;
1030
            }
1031

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

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

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

    
1044
            if (__type == Types.TIMESTAMP) {
1045
                return Types.TIMESTAMP;
1046
            }
1047
        }
1048
        catch (SQLException e) {
1049
            System.err.println("i = " + i);
1050
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e);
1051
        }
1052

    
1053
        return -1;
1054
    }
1055

    
1056
    public Value[] getAttributes(ResultSet rs) {
1057
        Value[] res = null;
1058

    
1059
        try {
1060
            int fcount = rs.getMetaData().getColumnCount();
1061
            res = new Value[fcount];
1062

    
1063
            for (int i = 0; i < fcount; i++) {
1064
                Object obj = rs.getObject(i + 1);
1065
                String objToString = null;
1066
                int _type = -1;
1067

    
1068
                if (obj instanceof String) {
1069
                    objToString = (String) obj;
1070
                    _type = Types.VARCHAR;
1071
                }
1072
                else {
1073
                    if (obj instanceof ROWID) {
1074
                        objToString = ((ROWID) obj).stringValue();
1075
                        _type = Types.VARCHAR;
1076
                    }
1077
                    else {
1078
                        if (obj instanceof STRUCT) {
1079
                            objToString = "STRUCT";
1080
                            _type = Types.VARCHAR;
1081
                        }
1082
                        else {
1083
                            objToString = (obj == null) ? "NULL" : obj.toString();
1084
                            _type = getFieldType(i);
1085
                        }
1086
                    }
1087
                }
1088

    
1089
                // /*
1090
                if (_type == -1) {
1091
                    obj = null;
1092
                }
1093

    
1094
                // */
1095
                if (obj == null) {
1096
                    res[i] = ValueFactory.createNullValue();
1097
                }
1098
                else {
1099
                    if (_type == Types.DATE) {
1100
                        objToString = objToString.replace('-', '/');
1101
                    }
1102

    
1103
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1104
                }
1105
            }
1106
        }
1107
        catch (SQLException se) {
1108
            System.err.println("Error while getting attributes: " +
1109
                se.getMessage());
1110

    
1111
            return null;
1112
        }
1113
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1114
            System.err.println("Error while getting attributes: " +
1115
                e.getMessage());
1116

    
1117
            return null;
1118
        }
1119
        catch (ParseException e) {
1120
            System.err.println("Error while getting attributes: " +
1121
                e.getMessage());
1122

    
1123
            return null;
1124
        }
1125

    
1126
        return res;
1127
    }
1128
    
1129
    public Value[] getAttributesUsingMainMetadata(ResultSet rs) {
1130
        Value[] res = null;
1131

    
1132
        try {
1133
            int fcount = metaData.getColumnCount();
1134
            res = new Value[fcount];
1135

    
1136
            for (int i = 0; i < fcount; i++) {
1137
                Object obj = rs.getObject(i + 1);
1138
                String objToString = null;
1139
                int _type = -1;
1140

    
1141
                if (obj instanceof String) {
1142
                    objToString = (String) obj;
1143
                    _type = Types.VARCHAR;
1144
                }
1145
                else {
1146
                    if (obj instanceof ROWID) {
1147
                        objToString = ((ROWID) obj).stringValue();
1148
                        _type = Types.VARCHAR;
1149
                    }
1150
                    else {
1151
                        if (obj instanceof STRUCT) {
1152
                            objToString = "STRUCT";
1153
                            _type = Types.VARCHAR;
1154
                        }
1155
                        else {
1156
                            objToString = (obj == null) ? "NULL" : obj.toString();
1157
                            _type = getFieldType(i);
1158
                        }
1159
                    }
1160
                }
1161

    
1162
                // /*
1163
                if (_type == -1) {
1164
                    obj = null;
1165
                }
1166

    
1167
                // */
1168
                if (obj == null) {
1169
                    res[i] = ValueFactory.createNullValue();
1170
                }
1171
                else {
1172
                    if (_type == Types.DATE) {
1173
                        objToString = objToString.replace('-', '/');
1174
                    }
1175

    
1176
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1177
                }
1178
            }
1179
        }
1180
        catch (SQLException se) {
1181
            System.err.println("Error while getting attributes: " +
1182
                se.getMessage());
1183

    
1184
            return null;
1185
        }
1186
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1187
            System.err.println("Error while getting attributes: " +
1188
                e.getMessage());
1189

    
1190
            return null;
1191
        }
1192
        catch (ParseException e) {
1193
            System.err.println("Error while getting attributes: " +
1194
                e.getMessage());
1195

    
1196
            return null;
1197
        }
1198

    
1199
        return res;
1200
    }
1201
    
1202

    
1203
    public String getFieldName(int fieldId)
1204
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1205
        return fieldNames[fieldId];
1206
    }
1207

    
1208
    public int getFieldWidth(int fieldId) {
1209
        int i = -1;
1210

    
1211
        try {
1212
            int aux = fieldId + 1; // fieldId viene basado en 0
1213
            i = metaData.getColumnDisplaySize(aux);
1214
        }
1215
        catch (SQLException e) {
1216
            System.err.println("While getting field width: " + e.getMessage());
1217
        }
1218

    
1219
        if (i < 0) {
1220
            i = 255;
1221
        }
1222

    
1223
        return i;
1224
    }
1225

    
1226
    public Value getFieldValue(long rowIndex, int field_Id)
1227
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1228
        if (isNotAvailableYet) {
1229
            return nullVal;
1230
        }
1231

    
1232
        if ((singleCachedFeature != null) &&
1233
                (rowIndex == singleCachedFeatureRowNum)) {
1234
            return singleCachedFeature.getAttributes()[field_Id];
1235
        }
1236

    
1237
        // return ValueFactory.createNullValue();
1238
        ResultSet _r = null;
1239
        java.sql.PreparedStatement ps = null;
1240

    
1241
        try {
1242
            String rnq = getSearchId();
1243
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1244

    
1245
            ps = conn.prepareStatement(rnq);
1246
            ps.setObject(1, _id);
1247

    
1248
            ps.execute();
1249
            _r = ps.getResultSet();
1250
            _r.next();
1251
        }
1252
        catch (SQLException se) {
1253
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(se.getMessage());
1254
        }
1255

    
1256
        IFeature ife = null;
1257
        Value[] atts = null;
1258

    
1259
        try {
1260
            ROWID ri = (ROWID) _r.getObject(1);
1261
            atts = getAttributesUsingMainMetadata(_r);
1262

    
1263
            String gid = ri.stringValue();
1264
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1265
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1266
            ife = new DefaultFeature(theGeom, atts, gid);
1267
            _r.close();
1268
            ps.close();
1269
        }
1270
        catch (SQLException se) {
1271
            logger.error("Error while doing next(): " + se.getMessage(), se);
1272
        }
1273

    
1274
        // -------------------------------
1275
        singleCachedFeature = ife;
1276
        singleCachedFeatureRowNum = rowIndex;
1277

    
1278
        // -------------------------------
1279
        if (atts == null) {
1280
            return ValueFactory.createNullValue();
1281
        }
1282
        else {
1283
            return atts[field_Id];
1284
        }
1285
    }
1286

    
1287
    public static void showMemory() {
1288
        Runtime r = Runtime.getRuntime();
1289
        long mem = r.totalMemory() - r.freeMemory();
1290
        System.err.println("Memoria total: " + mem);
1291
    }
1292

    
1293
    public Rectangle2D getFullExtent() {
1294
            return full_Extent;
1295
    }
1296

    
1297
    /**
1298
     * Utility method to get a geometry from a struct.
1299
     *
1300
     * @param theStruct the struct to be converted
1301
     * @param use_gtools switch to use geotools classes or not
1302
     * @return the geometry
1303
     * @throws SQLException
1304
     */
1305
    public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
1306
        throws SQLException {
1307
        IGeometry _igeom = null;
1308

    
1309
        if (theStruct == null) {
1310
            return nullGeom;
1311
        }
1312

    
1313
        if (use_gtools) { // geotools
1314
//            _igeom = getGeotoolsIGeometry(theStruct);
1315
        }
1316
        else { // jgeometry
1317
            _igeom = getFMapGeometry(theStruct, false);
1318
        }
1319

    
1320
        return _igeom;
1321
    }
1322

    
1323
    private IGeometry getFMapGeometry(JGeometry jg, boolean force_not_collection) {
1324
        int jgtype = jg.getType();
1325
        int dim = jg.getDimensions();
1326
        IGeometry ig = null;
1327

    
1328
        if ((jgtype != JGeometry.GTYPE_COLLECTION) &&
1329
                (isActuallyACollection(jg))) {
1330
            jgtype = JGeometry.GTYPE_COLLECTION;
1331
        }
1332

    
1333
        switch (jgtype) {
1334
        case JGeometry.GTYPE_COLLECTION:
1335

    
1336
            int srid = jg.getSRID();
1337
            ig = getFMapGeometryCollection(jg, dim, srid);
1338

    
1339
            break;
1340

    
1341
        case JGeometry.GTYPE_POINT:
1342
        case JGeometry.GTYPE_MULTIPOINT:
1343
            ig = getFMapGeometryPoint(jg, dim);
1344

    
1345
            break;
1346

    
1347
        case JGeometry.GTYPE_CURVE:
1348
        case JGeometry.GTYPE_MULTICURVE:
1349
            ig = getFMapGeometryMultiLineString(jg, dim);
1350

    
1351
            break;
1352

    
1353
        case JGeometry.GTYPE_POLYGON:
1354
        case JGeometry.GTYPE_MULTIPOLYGON:
1355
            ig = getFMapGeometryMultipolygon(jg, dim);
1356

    
1357
            break;
1358
        }
1359

    
1360
        return ig;
1361
    }
1362

    
1363
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim,
1364
        int __srid) {
1365
        NUMBER main_type = new NUMBER((dim * 1000) +
1366
                OracleSpatialUtils.getStructType(the_data));
1367
        NUMBER _srid = new NUMBER(__srid);
1368

    
1369
        Datum[] all_info_array = null;
1370
        Object[] elems_info_aray = null;
1371
        Datum[] all_ords = null;
1372

    
1373
        try {
1374
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1375
            elems_info_aray = groupByElement(all_info_array);
1376
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1377
        }
1378
        catch (SQLException e) {
1379
            logger.error("Unexpected error: " + e.getMessage());
1380
        }
1381

    
1382
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1383
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1384

    
1385
        for (int i = 0; i < elems_info_aray.length; i++) {
1386
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1387
        }
1388

    
1389
        // _elems_info_aray, ords_of_groups
1390
        int no_of_elems = ords_of_groups.length;
1391
        IGeometry[] geoms = new IGeometry[no_of_elems];
1392

    
1393
        for (int i = 0; i < no_of_elems; i++) {
1394
            Datum[] item_info_array = null;
1395
            Datum[] item_ords = null;
1396
            NUMBER gtype = null;
1397

    
1398
            try {
1399
                item_info_array = (Datum[]) _elems_info_aray[i];
1400
                item_ords = (Datum[]) ords_of_groups[i];
1401

    
1402
                gtype = new NUMBER((dim * 1000) +
1403
                        (item_info_array[1].intValue() % 1000));
1404
            }
1405
            catch (SQLException se) {
1406
                logger.error("Unexpected error: " + se.getMessage());
1407
            }
1408

    
1409
            // if it's the first geometry, the type is the collection's main type (no?)
1410
            if (i == 0) {
1411
                gtype = main_type;
1412
            }
1413

    
1414
            STRUCT itemst = null;
1415

    
1416
            if (tableHasSrid) {
1417
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1418
                        item_info_array, item_ords, conn);
1419
            }
1420
            else {
1421
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1422
                        item_info_array, item_ords, conn);
1423
            }
1424

    
1425
            geoms[i] = getFMapGeometry(itemst, true);
1426
        }
1427

    
1428
        return new FGeometryCollection(geoms);
1429
    }
1430

    
1431
    /**
1432
     * Utility method to transform a struct into a IGeometry.
1433
     *
1434
     * @param st the struct to be converted
1435
     * @param force_not_collection t5his parameter is currently ignored
1436
     * @return the IGeometry
1437
     */
1438
    public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1439
        Datum[] the_data = null;
1440

    
1441
        try {
1442
            the_data = st.getOracleAttributes();
1443

    
1444
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1445
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1446

    
1447
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1448

    
1449
            if (dim < 2) {
1450
                dim = 2;
1451
            }
1452

    
1453
            IGeometry ig = null;
1454

    
1455
            if (isActuallyACollection(the_data)) {
1456
                jgtype = FShape.MULTI;
1457
            }
1458

    
1459
            switch (jgtype) {
1460
            case FShape.MULTI:
1461

    
1462
                int srid = ((NUMBER) the_data[1]).intValue();
1463
                ig = getFMapGeometryCollection(the_data, dim, srid);
1464

    
1465
                break;
1466

    
1467
            case FShape.POINT:
1468
                ig = getFMapGeometryPoint(the_data, dim);
1469

    
1470
                break;
1471

    
1472
            case FShape.LINE:
1473
                ig = getFMapGeometryMultiLineString(the_data, dim);
1474

    
1475
                break;
1476

    
1477
            case FShape.POLYGON:
1478
                ig = getFMapGeometryMultipolygon(the_data, dim);
1479

    
1480
                break;
1481
            }
1482

    
1483
            return ig;
1484
        }
1485
        catch (SQLException e) {
1486
            logger.error(e);
1487
        }
1488

    
1489
        return null;
1490
    }
1491

    
1492
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1493
        int size = input.length / n;
1494
        double[] resp = new double[size];
1495

    
1496
        for (int i = 0; i < size; i++) {
1497
            resp[i] = input[(i * n) + ind];
1498
        }
1499

    
1500
        return resp;
1501
    }
1502

    
1503
    private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1504
        int size = input.length / n;
1505
        double[] resp = new double[size];
1506

    
1507
        for (int i = 0; i < size; i++) {
1508
            resp[i] = input[(i * n) + ind];
1509
        }
1510

    
1511
        return resp;
1512
    }
1513

    
1514
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1515
        IGeometry ig = null;
1516

    
1517
        if (jg.isCircle()) {
1518
            ig = getCircleFromJGeometry(jg);
1519
        }
1520
        else {
1521
            Shape shape = jg.createShape();
1522
            GeneralPathX gpx = new GeneralPathX(shape);
1523

    
1524
            if (dim == 2) {
1525
                ig = ShapeFactory.createPolygon2D(gpx);
1526
            }
1527
            else {
1528
                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1529
                ig = ShapeFactory.createPolygon3D(gpx, z);
1530
            }
1531
        }
1532

    
1533
        return ig;
1534
    }
1535

    
1536
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1537
        IGeometry ig = null;
1538

    
1539
        if (OracleSpatialUtils.isCircle(the_data)) {
1540
            ig = getCircleFromStruct(the_data);
1541
        }
1542
        else {
1543
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1544

    
1545
            if (dim == 2) {
1546
                ig = ShapeFactory.createPolygon2D(gpx);
1547
            }
1548
            else {
1549
                double[] ords = null;
1550

    
1551
                try {
1552
                    ords = ((ARRAY) the_data[4]).getDoubleArray();
1553
                }
1554
                catch (SQLException se) {
1555
                    logger.error("While getting ordinates: " + se.getMessage(),
1556
                        se);
1557
                }
1558

    
1559
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1560
                ig = ShapeFactory.createPolygon3D(gpx, z);
1561
            }
1562
        }
1563

    
1564
        return ig;
1565
    }
1566

    
1567
    private IGeometry getCircleFromJGeometry(JGeometry jg) {
1568
        double[] threep = jg.getOrdinatesArray();
1569
        Point2D[] three = new Point2D.Double[3];
1570
        three[0] = new Point2D.Double(threep[0], threep[1]);
1571
        three[1] = new Point2D.Double(threep[2], threep[3]);
1572
        three[2] = new Point2D.Double(threep[4], threep[5]);
1573

    
1574
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1575

    
1576
        Point2D cent = (Point2D) cent_rad[0];
1577
        double radius = ((Double) cent_rad[1]).doubleValue();
1578

    
1579
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1580

    
1581
        return circ;
1582
    }
1583

    
1584
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1585
        double[] threep = null;
1586

    
1587
        try {
1588
            threep = ((ARRAY) the_data[4]).getDoubleArray();
1589
        }
1590
        catch (SQLException se) {
1591
            logger.error("While getting ords from struct: " + se.getMessage(),
1592
                se);
1593

    
1594
            return new FNullGeometry();
1595
        }
1596

    
1597
        Point2D[] three = new Point2D.Double[3];
1598
        three[0] = new Point2D.Double(threep[0], threep[1]);
1599
        three[1] = new Point2D.Double(threep[2], threep[3]);
1600
        three[2] = new Point2D.Double(threep[4], threep[5]);
1601

    
1602
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1603

    
1604
        Point2D cent = (Point2D) cent_rad[0];
1605
        double radius = ((Double) cent_rad[1]).doubleValue();
1606

    
1607
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1608

    
1609
        return circ;
1610
    }
1611

    
1612
    private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1613
        Shape shape = jg.createShape();
1614
        GeneralPathX gpx = new GeneralPathX(shape);
1615
        IGeometry ig = null;
1616

    
1617
        if (dim == 2) {
1618
            ig = ShapeFactory.createPolyline2D(gpx);
1619
        }
1620
        else {
1621
            double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1622
            ig = ShapeFactory.createPolyline3D(gpx, z);
1623
        }
1624

    
1625
        return ig;
1626
    }
1627

    
1628
    private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1629
        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1630
        IGeometry ig = null;
1631
        double[] ords = null;
1632

    
1633
        if (dim == 2) {
1634
            ig = ShapeFactory.createPolyline2D(gpx);
1635
        }
1636
        else {
1637
            ords = OracleSpatialUtils.getOrds(the_data);
1638

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

    
1643
        return ig;
1644
    }
1645

    
1646
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1647
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1648

    
1649
            return getFMapGeometrySdoPoint(jg_point, dim);
1650
        }
1651

    
1652
        IGeometry ig = null;
1653
        int total_size = jg_point.getOrdinatesArray().length;
1654
        int no_po = total_size / dim;
1655
        double[] x = new double[no_po];
1656
        double[] y = new double[no_po];
1657
        double[] z = new double[no_po];
1658

    
1659
        for (int i = 0; i < no_po; i++) {
1660
            x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1661
            y[i] = jg_point.getOrdinatesArray()[(i * dim) + 1];
1662

    
1663
            if (dim >= 3) {
1664
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1665
            }
1666
        }
1667

    
1668
        if (dim == 2) {
1669
            if (no_po == 1) {
1670
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1671
            }
1672
            else {
1673
                ig = ShapeFactory.createMultipoint2D(x, y);
1674
            }
1675
        }
1676
        else {
1677
            if (no_po == 1) {
1678
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1679
            }
1680
            else {
1681
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1682
            }
1683
        }
1684

    
1685
        return ig;
1686
    }
1687

    
1688
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1689
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1690

    
1691
        if (ords == null) { // sdo_point
1692

    
1693
            return getFMapGeometrySdoPoint(the_data, dim);
1694
        }
1695

    
1696
        IGeometry ig = null;
1697
        int total_size = ords.length;
1698
        int no_po = total_size / dim;
1699
        double[] x = new double[no_po];
1700
        double[] y = new double[no_po];
1701
        double[] z = new double[no_po];
1702

    
1703
        for (int i = 0; i < no_po; i++) {
1704
            x[i] = ords[i * dim]; // pp[i].getX();
1705
            y[i] = ords[(i * dim) + 1];
1706

    
1707
            if (dim >= 3) {
1708
                z[i] = ords[(i * dim) + 2];
1709
            }
1710
        }
1711

    
1712
        if (dim == 2) {
1713
            if (no_po == 1) {
1714
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1715
            }
1716
            else {
1717
                ig = ShapeFactory.createMultipoint2D(x, y);
1718
            }
1719
        }
1720
        else {
1721
            if (no_po == 1) {
1722
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1723
            }
1724
            else {
1725
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1726
            }
1727
        }
1728

    
1729
        return ig;
1730
    }
1731

    
1732
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1733
        double[] p = jgp.getPoint();
1734
        IGeometry ig = null;
1735

    
1736
        if (d == 2) {
1737
            ig = ShapeFactory.createPoint2D(p[0], p[1]);
1738
        }
1739
        else {
1740
            ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1741
        }
1742

    
1743
        return ig;
1744
    }
1745

    
1746
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1747
        double x = 0;
1748
        double y = 0;
1749
        double z = 0;
1750

    
1751
        try {
1752
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1753
            x = ((NUMBER) aux[0]).doubleValue();
1754
            y = ((NUMBER) aux[1]).doubleValue();
1755

    
1756
            if (d > 2) {
1757
                z = ((NUMBER) aux[2]).doubleValue();
1758
            }
1759
        }
1760
        catch (SQLException se) {
1761
            logger.error("While getting sdo point ordinates: " +
1762
                se.getMessage(), se);
1763
        }
1764

    
1765
        IGeometry ig = null;
1766

    
1767
        if (d == 2) {
1768
            ig = ShapeFactory.createPoint2D(x, y);
1769
        }
1770
        else {
1771
            ig = ShapeFactory.createPoint3D(x, y, z);
1772
        }
1773

    
1774
        return ig;
1775
    }
1776

    
1777
    private boolean isActuallyACollection(JGeometry jg) {
1778
        int[] info = jg.getElemInfo();
1779

    
1780
        if (info == null) {
1781
            return false; // sdo_point
1782
        }
1783

    
1784
        int size = info.length / 3;
1785

    
1786
        if (size == 1) {
1787
            return false;
1788
        }
1789

    
1790
        if (size == 2) {
1791
            return ((info[1] % 1000) != (info[4] % 1000));
1792
        }
1793

    
1794
        int second = info[4] % 1000;
1795

    
1796
        for (int i = 2; i < size; i++) {
1797
            if ((info[(i * 3) + 1] % 1000) != second) {
1798
                return true;
1799
            }
1800
        }
1801

    
1802
        return false;
1803
    }
1804

    
1805
    private boolean isActuallyACollection(Datum[] the_data) {
1806
        int[] info = null;
1807

    
1808
        try {
1809
            ARRAY aux = (ARRAY) the_data[3];
1810

    
1811
            if (aux == null) {
1812
                return false;
1813
            }
1814

    
1815
            info = aux.getIntArray();
1816
        }
1817
        catch (SQLException se) {
1818
            logger.error("While checking collection: " + se.getMessage());
1819

    
1820
            return false;
1821
        }
1822

    
1823
        if (info == null) {
1824
            return false; // sdo_point
1825
        }
1826

    
1827
        int size = info.length / 3;
1828

    
1829
        if (size == 1) {
1830
            return false;
1831
        }
1832

    
1833
        if (size == 2) {
1834
            return ((info[1] % 1000) != (info[4] % 1000));
1835
        }
1836

    
1837
        int second = info[4] % 1000;
1838

    
1839
        for (int i = 2; i < size; i++) {
1840
            if ((info[(i * 3) + 1] % 1000) != second) {
1841
                return true;
1842
            }
1843
        }
1844

    
1845
        return false;
1846
    }
1847

    
1848
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1849
        int main_type = jg.getType();
1850

    
1851
        int[] all_info_array = jg.getElemInfo();
1852
        Object[] elems_info_aray = groupByElement(all_info_array);
1853
        double[] all_ords = jg.getOrdinatesArray();
1854
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1855
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1856

    
1857
        for (int i = 0; i < elems_info_aray.length; i++) {
1858
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1859
        }
1860

    
1861
        // _elems_info_aray, ords_of_groups
1862
        int no_of_elems = ords_of_groups.length;
1863
        IGeometry[] geoms = new IGeometry[no_of_elems];
1864

    
1865
        for (int i = 0; i < no_of_elems; i++) {
1866
            int[] item_info_array = (int[]) _elems_info_aray[i];
1867
            double[] item_ords = (double[]) ords_of_groups[i];
1868
            int gtype = (dim * 1000) + (item_info_array[1] % 1000);
1869

    
1870
            // if it's the first geometry, the type is the collection's main type (no?)
1871
            if (i == 0) {
1872
                gtype = main_type;
1873
            }
1874

    
1875
            JGeometry itemjg = null;
1876

    
1877
            if (tableHasSrid) {
1878
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1879
            }
1880
            else {
1881
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1882
            }
1883

    
1884
            geoms[i] = getFMapGeometry(itemjg, true);
1885
        }
1886

    
1887
        return new FGeometryCollection(geoms);
1888
    }
1889

    
1890
    private Datum[] updateIndexes(Datum[] info) {
1891
        int size = info.length / 3;
1892
        NUMBER[] resp = new NUMBER[3 * size];
1893

    
1894
        try {
1895
            int rest = info[0].intValue() - 1;
1896

    
1897
            for (int i = 0; i < size; i++) {
1898
                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1899
                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
1900
                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
1901
            }
1902
        }
1903
        catch (SQLException se) {
1904
            logger.error("Unexpected error: " + se.getMessage());
1905
        }
1906

    
1907
        return resp;
1908
    }
1909

    
1910
    private int[] updateIndexes(int[] info) {
1911
        int size = info.length / 3;
1912
        int[] resp = new int[3 * size];
1913
        int rest = info[0] - 1;
1914

    
1915
        for (int i = 0; i < size; i++) {
1916
            resp[3 * i] = info[3 * i] - rest;
1917
            resp[(3 * i) + 1] = info[(3 * i) + 1];
1918
            resp[(3 * i) + 2] = info[(3 * i) + 2];
1919
        }
1920

    
1921
        return resp;
1922
    }
1923

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

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

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

    
1936
        return resp;
1937
    }
1938

    
1939
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
1940
        Datum[] resp = new Datum[head.length + tail.length];
1941
        int hsize = head.length;
1942

    
1943
        for (int i = 0; i < hsize; i++) {
1944
            resp[i] = head[i];
1945
        }
1946

    
1947
        for (int i = 0; i < tail.length; i++) {
1948
            resp[hsize + i] = tail[i];
1949
        }
1950

    
1951
        return resp;
1952
    }
1953

    
1954
    private int[] getNthGroupOfThree(int[] list, int n) {
1955
        int[] resp = new int[3];
1956
        resp[0] = list[3 * n];
1957
        resp[1] = list[(3 * n) + 1];
1958
        resp[2] = list[(3 * n) + 2];
1959

    
1960
        return resp;
1961
    }
1962

    
1963
    private Datum[] getNthGroupOfThree(Datum[] list, int n) {
1964
        Datum[] resp = new Datum[3];
1965
        resp[0] = list[3 * n];
1966
        resp[1] = list[(3 * n) + 1];
1967
        resp[2] = list[(3 * n) + 2];
1968

    
1969
        return resp;
1970
    }
1971

    
1972
    private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
1973
        Datum[] resp = new Datum[last_inc - first_inc + 1];
1974

    
1975
        for (int i = first_inc; i <= last_inc; i++) {
1976
            resp[i - first_inc] = all[i];
1977
        }
1978

    
1979
        return resp;
1980
    }
1981

    
1982
    private double[] getSubSet(double[] all, int first_inc, int last_inc) {
1983
        double[] resp = new double[last_inc - first_inc + 1];
1984

    
1985
        for (int i = first_inc; i <= last_inc; i++) {
1986
            resp[i - first_inc] = all[i];
1987
        }
1988

    
1989
        return resp;
1990
    }
1991

    
1992
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) {
1993
        Object[] resp = new Object[groups.length];
1994

    
1995
        if (resp.length == 1) {
1996
            resp[0] = all;
1997

    
1998
            return resp;
1999
        }
2000

    
2001
        int ind = 0;
2002
        int[] aux = (int[]) groups[1];
2003
        int _end = aux[0] - 2;
2004
        Datum[] ord_aux = getSubSet(all, 0, _end);
2005

    
2006
        int _start = _end + 1;
2007
        resp[ind] = ord_aux;
2008
        ind++;
2009

    
2010
        for (int i = 2; i < groups.length; i++) {
2011
            aux = (int[]) groups[i];
2012
            _end = aux[0] - 2;
2013
            ord_aux = getSubSet(all, _start, _end);
2014
            resp[ind] = ord_aux;
2015
            ind++;
2016
            _start = _end + 1;
2017
        }
2018

    
2019
        // last
2020
        _end = all.length - 1;
2021
        ord_aux = getSubSet(all, _start, _end);
2022
        resp[groups.length - 1] = ord_aux;
2023

    
2024
        return resp;
2025
    }
2026

    
2027
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2028
        Object[] resp = new Object[groups.length];
2029

    
2030
        if (resp.length == 1) {
2031
            resp[0] = all;
2032

    
2033
            return resp;
2034
        }
2035

    
2036
        int ind = 0;
2037
        int[] aux = (int[]) groups[1];
2038
        int _end = aux[0] - 2;
2039
        double[] ord_aux = getSubSet(all, 0, _end);
2040

    
2041
        int _start = _end + 1;
2042
        resp[ind] = ord_aux;
2043
        ind++;
2044

    
2045
        for (int i = 2; i < groups.length; i++) {
2046
            aux = (int[]) groups[i];
2047
            _end = aux[0] - 2;
2048
            ord_aux = getSubSet(all, _start, _end);
2049
            resp[ind] = ord_aux;
2050
            ind++;
2051
            _start = _end + 1;
2052
        }
2053

    
2054
        // last
2055
        _end = all.length - 1;
2056
        ord_aux = getSubSet(all, _start, _end);
2057
        resp[groups.length - 1] = ord_aux;
2058

    
2059
        return resp;
2060
    }
2061

    
2062
    private Object[] groupByElement(int[] all_elem) {
2063
        ArrayList resp = new ArrayList();
2064

    
2065
        int size = all_elem.length / 3;
2066

    
2067
        int[] aux = getNthGroupOfThree(all_elem, 0);
2068

    
2069
        int[] newaux;
2070
        int i = 1;
2071

    
2072
        while (i < size) {
2073
            newaux = getNthGroupOfThree(all_elem, i);
2074

    
2075
            if (newaux[0] == aux[0]) {
2076
                // aux[2] says how many components
2077
                for (int j = 0; j < aux[2]; j++) {
2078
                    aux = appendIntArrays(aux,
2079
                            getNthGroupOfThree(all_elem, j + i));
2080
                }
2081

    
2082
                resp.add(aux);
2083
                i = i + aux[2];
2084
                aux = getNthGroupOfThree(all_elem, i);
2085
            }
2086
            else {
2087
                if (newaux[1] == 2003) {
2088
                    aux = appendIntArrays(aux, newaux);
2089
                }
2090
                else {
2091
                    resp.add(aux);
2092
                    aux = getNthGroupOfThree(all_elem, i);
2093
                }
2094
            }
2095

    
2096
            i++;
2097
        }
2098

    
2099
        resp.add(aux);
2100

    
2101
        return resp.toArray();
2102
    }
2103

    
2104
    private Object[] groupByElement(Datum[] all_elem) {
2105
        ArrayList resp = new ArrayList();
2106

    
2107
        int size = all_elem.length / 3;
2108

    
2109
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2110

    
2111
        Datum[] newaux;
2112
        int i = 1;
2113

    
2114
        try {
2115
            while (i < size) {
2116
                newaux = getNthGroupOfThree(all_elem, i);
2117

    
2118
                if (newaux[0] == aux[0]) {
2119
                    // aux[2] says how many components
2120
                    for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
2121
                        aux = appendDatArrays(aux,
2122
                                getNthGroupOfThree(all_elem, j + i));
2123
                    }
2124

    
2125
                    resp.add(aux);
2126
                    i = i + ((NUMBER) aux[2]).intValue();
2127
                    aux = getNthGroupOfThree(all_elem, i);
2128
                }
2129
                else {
2130
                    if (((NUMBER) newaux[1]).intValue() == 2003) {
2131
                        aux = appendDatArrays(aux, newaux);
2132
                    }
2133
                    else {
2134
                        resp.add(aux);
2135
                        aux = getNthGroupOfThree(all_elem, i);
2136
                    }
2137
                }
2138

    
2139
                i++;
2140
            }
2141
        }
2142
        catch (SQLException se) {
2143
            logger.error("Unexpected error: " + se.getMessage());
2144
        }
2145

    
2146
        resp.add(aux);
2147

    
2148
        return resp.toArray();
2149
    }
2150

    
2151
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2152
        Point2D p = _jgeom.getJavaPoint();
2153
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2154

    
2155
        return ig;
2156
    }
2157

    
2158
    private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2159
        Point2D[] pp = _jgeom.getJavaPoints();
2160
        int l = pp.length;
2161
        double[] x = new double[l];
2162
        double[] y = new double[l];
2163

    
2164
        for (int i = 0; i < l; i++) {
2165
            x[i] = pp[i].getX();
2166
            y[i] = pp[i].getY();
2167
        }
2168

    
2169
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2170

    
2171
        return ig;
2172
    }
2173

    
2174
    private IGeometry getJGeometryOther(JGeometry _jgeom) {
2175
        int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2176
        Shape shape = _jgeom.createShape();
2177
        GeneralPathX gpx = new GeneralPathX(shape);
2178
        IGeometry ig = null;
2179

    
2180
        switch (type) {
2181
        case FShape.LINE:
2182

    
2183
            FPolyline2D fpl = new FPolyline2D(gpx);
2184
            ig = ShapeFactory.createPolyline2D(gpx);
2185

    
2186
            break;
2187

    
2188
        case FShape.POLYGON:
2189

    
2190
            FPolygon2D fpg = new FPolygon2D(gpx);
2191
            ig = ShapeFactory.createPolygon2D(gpx);
2192

    
2193
            break;
2194
        }
2195

    
2196
        return ig;
2197
    }
2198

    
2199
//    private IGeometry getGeotoolsIGeometry(oracle.sql.STRUCT _struct) {
2200
//        Geometry geo_jts = null;
2201
//
2202
//        try {
2203
//            geo_jts = geotools_conv.asGeometry(_struct);
2204
//        }
2205
//        catch (SQLException e) {
2206
//            System.err.println("While using geotools converter: " +
2207
//                e.getMessage());
2208
//        }
2209
//
2210
//        IGeometry ig = FConverter.jts_to_igeometry(geo_jts);
2211
//
2212
//        return ig;
2213
//    }
2214

    
2215
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
2216
        /*
2217
         * Tipos en Oracle Spatial usando JGeometry
2218
         *
2219
         * GTYPE_COLLECTION collection geometry type
2220
         * GTYPE_CURVE curve geoemtry type
2221
         * GTYPE_MULTICURVE multi-curve geometry type
2222
         * GTYPE_MULTIPOINT multi-point geometry type
2223
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
2224
         * GTYPE_POINT point geometry type
2225
         * GTYPE_POLYGON  polygon geometry type
2226
         *
2227
         * Tipos gvSIG FShape
2228
         *
2229
         * NULL = 0;
2230
         * POINT = 1;
2231
         * LINE = 2;
2232
         * POLYGON = 4;
2233
         * TEXT = 8;
2234
         * MULTI = 16;
2235
         * MULTIPOINT = 32;
2236
         * CIRCLE = 64;
2237
         * ARC = 128;
2238
         * ELLIPSE=256;
2239
         * Z=512
2240
         */
2241
        switch (type) {
2242
        case JGeometry.GTYPE_POLYGON:
2243
        case JGeometry.GTYPE_MULTIPOLYGON:
2244
            return FShape.POLYGON;
2245

    
2246
        case JGeometry.GTYPE_CURVE:
2247
        case JGeometry.GTYPE_MULTICURVE:
2248
            return FShape.LINE;
2249
        }
2250

    
2251
        System.err.println("Unhandled Oracle Spatial geometry type: " + type +
2252
            " (conversion returned FShape.NULL)");
2253

    
2254
        return FShape.NULL;
2255
    }
2256

    
2257
    private void cleanWhereClause() {
2258
        emptyWhereClause = false;
2259

    
2260
        String aux = getWhereClauseWithoutWhere();
2261

    
2262
        for (int i = 0; i < aux.length(); i++)
2263
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
2264
                return;
2265
            }
2266

    
2267
        getLyrDef().setWhereClause("");
2268
        emptyWhereClause = true;
2269
    }
2270
    
2271
    private String getValidViewConstructor(
2272
                    STRUCT _st,
2273
                    String ora_srid,
2274
                    boolean _hassrid,
2275
                    boolean _isgeocs) {
2276
            
2277
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
2278
            String resp = "";
2279
            if ((_hassrid) && (_isgeocs)) {
2280
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
2281
            } else {
2282
                    resp = sdo;
2283
            }
2284
             
2285
            return resp;
2286
    }
2287

    
2288
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2289
        String resp = "";
2290

    
2291
        if (isGeogCS) {
2292
            String vport = "sdo_filter(" + geoColName +
2293
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
2294
                "), 'querytype=window') = 'TRUE'";
2295

    
2296
                resp = "select " + getStandardSelectExpression() + ", c." +
2297
                    geoColName + " from " + getTableName() + " c where ";
2298
                if (idsLoadWhere.length() > 0) {
2299
                        resp = resp + " (" + idsLoadWhere + ") AND "; 
2300
                }
2301
                resp = resp + "(" + vport + ")";
2302
        }
2303
        else {
2304
                resp = "select " + getStandardSelectExpression() + ", c." +
2305
                    geoColName + " from " + getTableName() + " c where ";
2306
                if (idsLoadWhere.length() > 0) {
2307
                        resp = resp + " (" + idsLoadWhere + ") AND "; 
2308
                }
2309
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
2310
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
2311
        }
2312
        return resp;
2313
    }
2314

    
2315
    public void setWorkingArea(Rectangle2D rect) {
2316
    }
2317

    
2318
    private void setWAStructt() {
2319
    }
2320

    
2321
    private Geometry shapeToGeometry(Shape shp) {
2322
        if (shp == null) {
2323
            return null;
2324
        }
2325

    
2326
        int type = FShape.POLYGON;
2327

    
2328
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2329
            type = FShape.LINE;
2330
        }
2331

    
2332
        if (shp instanceof FPoint2D) {
2333
            type = FShape.POINT;
2334
        }
2335

    
2336
        if (shp instanceof FMultiPoint2D) {
2337
            type = FShape.MULTIPOINT;
2338
        }
2339

    
2340
        GeneralPathX wagp = new GeneralPathX(shp);
2341
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2342

    
2343
        return FConverter.java2d_to_jts(fwagp);
2344
    }
2345

    
2346
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2347
        Shape shape = _jg.createShape();
2348

    
2349
        return shape.getBounds2D();
2350
    }
2351

    
2352
    private void printStruct(STRUCT st) {
2353
        System.out.println("----------------------------------------------");
2354

    
2355
        try {
2356
            Object[] att = st.getAttributes();
2357
            int l = att.length;
2358

    
2359
            for (int i = 0; i < l; i++) {
2360
                System.out.println("ATT " + i + ": " + att[i].toString());
2361
            }
2362
        }
2363
        catch (Exception ex) {
2364
            System.out.println(
2365
                "- Error ---------------------------------------");
2366
        }
2367

    
2368
        System.out.println("----------------------------------------------");
2369
    }
2370

    
2371
    private static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
2372
        boolean isView, boolean _isGeogCS, String _oracleSRID, Connection __conn) {
2373
        Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2374
        Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2375

    
2376
        if ((_isGeogCS) && (isView)) {
2377
            c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2378
            c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2379
        }
2380

    
2381
        STRUCT resp = null;
2382

    
2383
        try {
2384
            // System.out.println("ABIERTA: " + (!conn.isClosed()));
2385
            // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2386
            // Object[] old_obj = resp.getAttributes();
2387
            int size = 5;
2388
            Object[] new_obj = new Object[size];
2389

    
2390
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2391
            new_obj[0] = new NUMBER(2003);
2392

    
2393
            if (hasSrid) {
2394
                new_obj[1] = new NUMBER(_oracleSRID);
2395
            }
2396
            else {
2397
                new_obj[1] = null;
2398
            }
2399

    
2400
            new_obj[2] = null;
2401

    
2402
            NUMBER[] elem_info = new NUMBER[3];
2403
            elem_info[0] = new NUMBER(1);
2404
            elem_info[1] = new NUMBER(1003);
2405
            elem_info[2] = new NUMBER(3);
2406
            new_obj[3] = elem_info;
2407

    
2408
            NUMBER[] ords = null;
2409
            ords = new NUMBER[4];
2410
            ords[0] = new NUMBER(c1.getX());
2411
            ords[1] = new NUMBER(c1.getY());
2412
            ords[2] = new NUMBER(c2.getX());
2413
            ords[3] = new NUMBER(c2.getY());
2414
            new_obj[4] = ords;
2415

    
2416
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2417
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2418
                    __conn);
2419

    
2420
            resp = new STRUCT(dsc, __conn, new_obj);
2421
        }
2422
        catch (Exception ex) {
2423
            logger.error("Error while creating rect struct: " +
2424
                ex.getMessage(), ex);
2425
        }
2426

    
2427
        return resp;
2428
    }
2429

    
2430
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2431
        boolean hasSrid) throws DriverException {
2432
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
2433
        String main_sel = "";
2434

    
2435
        if (fixsql == null) {
2436
            // main_sel = getMainSelect3(var_name);
2437
                String idswhere = getIdsQueryWhereClause(false);
2438
            main_sel = getMainSelect(sdo_intersect, idswhere);
2439
        }
2440
        else {
2441
            main_sel = fixsql;
2442
        }
2443

    
2444
        System.err.println("main sel = " + main_sel);
2445

    
2446
        ResultSet _rs = null;
2447
        Statement _stmnt = null;
2448
        Object[] _resp = new Object[2];
2449

    
2450
        try {
2451
            _stmnt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
2452
                    ResultSet.CONCUR_READ_ONLY);
2453
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2454
            _stmnt.setFetchSize(FETCH_SIZE);
2455

    
2456
            _rs = _stmnt.executeQuery(main_sel);
2457

    
2458
            // stmnt.close();
2459
        }
2460
        catch (SQLException se) {
2461
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
2462
                se);
2463
            throw new DriverException(se);
2464
        }
2465

    
2466
        // this method returns the statement too, so that it can be closed afterwards
2467
        _resp[0] = _rs;
2468
        _resp[1] = _stmnt;
2469

    
2470
        return _resp;
2471
    }
2472

    
2473
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2474
        String resp = "";
2475

    
2476
        try {
2477
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2478
            String mdsys_sdo_ordinate_array = "";
2479
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2480

    
2481
            for (int i = 0; i < vertices.length; i++) {
2482
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2483
                    vertices[i].doubleValue() + ", ";
2484
            }
2485

    
2486
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2487
                    mdsys_sdo_ordinate_array.length() - 2);
2488
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2489
                mdsys_sdo_ordinate_array + ")";
2490

    
2491
            String aux = "";
2492

    
2493
            if (hasSrid) {
2494
                aux = oracleSRID;
2495

    
2496
                if (_isGeogCS) {
2497
                    aux = "0";
2498
                }
2499
            }
2500
            else {
2501
                aux = "null";
2502
            }
2503

    
2504
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
2505
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
2506
                ")";
2507
        }
2508
        catch (Exception ex) {
2509
            System.err.println("Error while getting sdo contructor: " +
2510
                ex.getMessage());
2511
        }
2512

    
2513
        return resp;
2514
    }
2515
    
2516
    private String getIdsQueryWhereClause(boolean with_where) {
2517
                String resp = "";
2518
                
2519
                String _where = "";
2520
                if (with_where) _where = " where ";
2521

    
2522
                if (workingAreaInTablesCSStruct == null) {
2523
                        if (emptyWhereClause) {
2524
                                // return "select rowid from " + getTableName();
2525
                        } else {
2526
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
2527
                                                + ")";
2528
                        }
2529
                } else {
2530
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
2531
                                        oracleSRID, tableHasSrid, isGeogCS);
2532

    
2533
                        if (emptyWhereClause) {
2534
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
2535
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2536
                        } else {
2537
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
2538
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
2539
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2540
                        }
2541
                }
2542

    
2543
                // resp = resp + " order by rowid";
2544
                return resp;
2545
        }
2546

    
2547
    public String getIdAndElemInfoFullResulltSetQuery() {
2548
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
2549
            getTableName() + " c";
2550
        
2551
        resp = resp + getIdsQueryWhereClause(true);
2552
        return resp;
2553
    }
2554

    
2555
    private String getSearchId() {
2556
        if (emptyWhereClause) {
2557
            return "select " + getStandardSelectExpression() + ", c." +
2558
            geoColName + " from " + getTableName() + " c where rowid = ?";
2559
        }
2560
        else {
2561
            return "select " + getStandardSelectExpression() + ", c." +
2562
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
2563
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
2564
        }
2565
    }
2566

    
2567
    public int getShapeType() {
2568
        return shapeType;
2569
    }
2570

    
2571
    private String getWhereClauseWithoutWhere() {
2572
        String resp = "";
2573
        String old = getLyrDef().getWhereClause();
2574
        resp = old;
2575

    
2576
        if (old.length() <= 6) {
2577
            return old;
2578
        }
2579

    
2580
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2581
            resp = resp.substring(6, resp.length());
2582
        }
2583

    
2584
        return resp;
2585
    }
2586

    
2587
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2588
        if (r1.getMaxX() <= r2.getMinX()) {
2589
            return null;
2590
        }
2591

    
2592
        if (r2.getMaxX() <= r1.getMinX()) {
2593
            return null;
2594
        }
2595

    
2596
        if (r1.getMaxY() <= r2.getMinY()) {
2597
            return null;
2598
        }
2599

    
2600
        if (r2.getMaxY() <= r1.getMinY()) {
2601
            return null;
2602
        }
2603

    
2604
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2605
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2606
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2607
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2608

    
2609
        double w = maxx - minx;
2610
        double h = maxy - miny;
2611

    
2612
        return new Rectangle2D.Double(minx, miny, w, h);
2613
    }
2614

    
2615
    private static int maxSizeForFieldType(int _type) {
2616
        switch (_type) {
2617
        case Types.VARCHAR:
2618
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2619

    
2620
        case Types.LONGVARCHAR:
2621
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2622
        }
2623

    
2624
        return -1;
2625
    }
2626

    
2627
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2628
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2629

    
2630
        switch (fieldDesc.getFieldType()) {
2631
        case Types.SMALLINT:
2632
            aux = "NUMBER(5, 0)";
2633

    
2634
            break;
2635

    
2636
        case Types.INTEGER:
2637
            aux = "NUMBER(10, 0)";
2638

    
2639
            break;
2640

    
2641
        case Types.BIGINT:
2642
            aux = "NUMBER(38, 0)";
2643

    
2644
            break;
2645

    
2646
        case Types.BOOLEAN:
2647
            aux = "NUMBER(1, 0)";
2648

    
2649
            break;
2650

    
2651
        case Types.DECIMAL:
2652
            aux = "NUMBER";
2653

    
2654
            break;
2655

    
2656
        case Types.NUMERIC:
2657
            aux = "NUMBER";
2658

    
2659
            break;
2660

    
2661
        case Types.DOUBLE:
2662
            aux = "FLOAT";
2663

    
2664
            break;
2665

    
2666
        case Types.FLOAT:
2667
            aux = "FLOAT";
2668

    
2669
            break;
2670

    
2671
        case Types.CHAR:
2672
            aux = "CHAR(1 BYTE)";
2673

    
2674
            break;
2675

    
2676
        case Types.VARCHAR:
2677
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2678

    
2679
            break;
2680

    
2681
        case Types.LONGVARCHAR:
2682
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2683

    
2684
            break;
2685
        }
2686

    
2687
        return aux;
2688
    }
2689

    
2690
    // -----------------------------------------------------------
2691
    // -----------------------------------------------------------
2692
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2693
        return "DROP TABLE \"" + dbLayerDef.getTableName() +
2694
        "\" CASCADE CONSTRAINTS";
2695
    }
2696

    
2697
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2698
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2699

    
2700
        String type = "";
2701
        String name = "";
2702

    
2703
        String resp = "CREATE TABLE \"" + dbLayerDef.getTableName() + "\" ( ";
2704

    
2705
        for (int i = 0; i < flds.length; i++) {
2706
            name = flds[i].getFieldName();
2707

    
2708
            // -------------- FORBIDDEN FIELD NAMES -----------------
2709
            if (!isOracleAllowedFieldname(name)) {
2710
                continue;
2711
            }
2712

    
2713
            // ------------------------------------------------------
2714
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
2715
            }
2716
            else {
2717
                name = getValidOracleID(name, i);
2718
                resp = resp + "\"" + name + "\" ";
2719
                type = fieldTypeToSqlStringType(flds[i]);
2720
                resp = resp + type + ", ";
2721
            }
2722
        }
2723

    
2724
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2725
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2726
        resp = resp + ", ";
2727

    
2728
        String pk = "CONSTRAINT \"" + dbLayerDef.getTableName() +
2729
            "_PK\" PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD +
2730
            "\") ENABLE";
2731

    
2732
        resp = resp + pk + " )";
2733

    
2734
        return resp;
2735
    }
2736

    
2737
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2738
        String resp = "CREATE INDEX \"" + dbLayerDef.getTableName() +
2739
            "_SX\" ON \"" + dbLayerDef.getTableName() + "\" (\"" +
2740
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
2741
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2742

    
2743
        return resp;
2744
    }
2745

    
2746
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2747
        return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2748
        " WHERE TABLE_NAME = '" + dbLayerDef.getTableName() + "'";
2749
    }
2750

    
2751
    /**
2752
     * UTility method to get the SQL sentence needed to update the geographic metadata table
2753
     * with a new bounding box and SRS
2754
     *
2755
     * @param tName table name
2756
     * @param ora_srid new SRS
2757
     * @param bbox new bounding box
2758
     * @param dim geometries dimension
2759
     * @param withsrid False if the SRS is set to NULL. True otherwise.
2760
     * @return the SQL sentence to perform the update
2761
     */
2762
    public static String getMetadataUpdateSql(String tName, String ora_srid,
2763
        Rectangle2D bbox, int dim, boolean withsrid) {
2764
        String[] dim_name = new String[dim];
2765
        double tolerance = 0.5;
2766

    
2767
        if (ora_srid.compareTo(GEODETIC_SRID) == 0) {
2768
            dim_name[0] = "LONGITUDE";
2769
            dim_name[1] = "LATITUDE";
2770
        }
2771
        else {
2772
            dim_name[0] = "X";
2773
            dim_name[1] = "Y";
2774

    
2775
            if (dim > 2) {
2776
                dim_name[2] = "Z";
2777

    
2778
                if (dim > 3) {
2779
                    dim_name[3] = "T";
2780
                }
2781
            }
2782
        }
2783

    
2784
        String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " " +
2785
            " ( TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES (" + "'" +
2786
            tName + "', " + "'" + DEFAULT_GEO_FIELD + "', " +
2787
            "SDO_DIM_ARRAY( " + "SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2788
            bbox.getMinX() + ", " + bbox.getMaxX() + ", " + tolerance + " ), " +
2789
            "SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + bbox.getMinY() + ", " +
2790
            bbox.getMaxY() + ", " + tolerance + " ))";
2791

    
2792
        if (dim > 2) {
2793
            resp = resp.substring(0, resp.length() - 1) + ",";
2794
            resp = resp + "SDO_DIM_ELEMENT ('" + dim_name[2] +
2795
                "', 0.0, 100.0, " + tolerance + " ))";
2796

    
2797
            if (dim > 3) {
2798
                resp = resp.substring(0, resp.length() - 1) + ",";
2799
                resp = resp + "SDO_DIM_ELEMENT ('" + dim_name[3] +
2800
                    "', 0.0, 100.0, " + tolerance + " ))";
2801
            }
2802
        }
2803

    
2804
        if (withsrid) {
2805
            resp = resp + ", " + ora_srid + " )";
2806
        }
2807
        else {
2808
            resp = resp + ", NULL )";
2809
        }
2810

    
2811
        return resp;
2812
    }
2813

    
2814
    /**
2815
     * Gets the SQL sentence to perform an insertion.
2816
     *
2817
     * @param feat feature to be added
2818
     * @param dbLayerDef layer definition
2819
     * @param rowInd row index
2820
     * @param _geoColName geometry field name
2821
     * @return the SQL sentence to perform the insertion
2822
     */
2823
    public static String getRowInsertSql(IFeature feat,
2824
        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2825
        String name = "";
2826
        int ftype = -1;
2827
        String aux_orig = "";
2828
        String aux_limited = "";
2829
        String aux_quotes_ok = "";
2830

    
2831
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2832

    
2833
        String resp = "INSERT INTO \"" + dbLayerDef.getTableName() + "\" ( ";
2834

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

    
2839
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2840
            if (!isOracleAllowedFieldname(name)) continue;
2841
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2842
            // ------------------------------------------------------
2843
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2844
            }
2845
            else {
2846
                name = getValidOracleID(name, i);
2847
                resp = resp + "\"" + name + "\"" + " , ";
2848
            }
2849
        }
2850

    
2851
        resp = resp + _geoColName + " ) VALUES ( ";
2852

    
2853
        for (int i = 0; i < fieldsDescr.length; i++) {
2854
            name = fieldsDescr[i].getFieldName();
2855
            ftype = fieldsDescr[i].getFieldType();
2856

    
2857
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2858
            if (!isOracleAllowedFieldname(name)) continue;
2859
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2860
            // ------------------------------------------------------
2861
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2862

    
2863
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2864
            }
2865
            else {
2866
                if (name.compareToIgnoreCase(
2867
                            OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2868
                    resp = resp + rowInd + " , ";
2869
                }
2870
                else {
2871
                    Value attValue = feat.getAttribute(i);
2872

    
2873
                    if (attValue.toString() == null) {
2874
                        resp = resp + "NULL , ";
2875
                    }
2876
                    else {
2877
                        if (sur.length() > 0) {
2878
                            aux_orig = attValue.toString();
2879
                            aux_limited = cropStringValue(aux_orig, i,
2880
                                    fieldsDescr);
2881
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2882

    
2883
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2884
                        }
2885
                        else {
2886
                            String _aux = attValue.toString();
2887

    
2888
                            if (_aux.length() == 0) {
2889
                                _aux = "NULL";
2890
                            }
2891

    
2892
                            resp = resp + _aux + " , ";
2893
                        }
2894
                    }
2895
                }
2896
            }
2897
        }
2898

    
2899
        resp = resp + " ? )";
2900

    
2901
        return resp;
2902
    }
2903

    
2904
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
2905
            
2906
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
2907
                    return true;
2908
            }
2909
            
2910
            if ((ftype == Types.BINARY)
2911
                || (ftype == Types.ARRAY)
2912
                || (ftype == Types.BLOB)
2913
                || (ftype == Types.CLOB)
2914
                || (ftype == Types.STRUCT)
2915
            ) {
2916
                    return false;
2917
            }
2918
                return true;
2919
        }
2920

    
2921
        /**
2922
     * Gets the SQL sentence to perform an update.
2923
     *
2924
     * @param feat feature to be updated
2925
     * @param dbLayerDef layer definition
2926
     * @param rowInd row index
2927
     * @param geoFieldName geometry field name
2928
     * @return the SQL sentence to perform the update
2929
     */
2930
    public static String getRowUpdateSql(IFeature feat,
2931
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
2932
        String name = "";
2933
        String aux_orig = "";
2934
        String aux_limited = "";
2935
        String aux_quotes_ok = "";
2936

    
2937
        Value[] atts = feat.getAttributes();
2938
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
2939

    
2940
        String resp = "UPDATE \"" + dbLayerDef.getTableName() + "\" SET ";
2941

    
2942
        for (int i = 0; i < _fieldsDescr.length; i++) {
2943
            name = _fieldsDescr[i].getFieldName();
2944

    
2945
            // -------------- FORBIDDEN FIELD NAMES -----------------
2946
            if (!isOracleAllowedFieldname(name)) {
2947
                logger.info("Field: " + name + " will not be updated.");
2948
                continue;
2949
            }
2950

    
2951
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
2952
                        geoFieldName)) {
2953
                logger.info("Field: " + name + " will not be updated (it's a struct).");
2954
                continue;
2955
            }
2956

    
2957
            // ------------------------------------------------------
2958
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
2959
                // resp = resp + "\"" + name + "\"" + " = ?, ";
2960
            }
2961
            else {
2962
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
2963
                aux_orig = atts[i].toString();
2964
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
2965
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
2966
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
2967
                    sur + ", ";
2968
            }
2969
        }
2970

    
2971
        resp = resp + "\"" + geoFieldName + "\" = ?";
2972
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
2973

    
2974
        return resp;
2975
    }
2976

    
2977
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
2978
        String geoname) {
2979
        if (ftype == Types.STRUCT) {
2980
            if (fldname.compareToIgnoreCase(geoname) != 0) {
2981
                return true;
2982
            }
2983
        }
2984

    
2985
        return false;
2986
    }
2987

    
2988
    /**
2989
     * Gets the SQL sentence to perform a deletion.
2990
     *
2991
     * @param dbLayerDef layer definition
2992
     * @param id ROWID of the record to be deleted
2993
     * @return the SQL sentence to perform the deletion
2994
     */
2995
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
2996
        String resp = "DELETE FROM \"" + dbLayerDef.getTableName() + "\"";
2997
        resp = resp + " WHERE ROWID ='" + id + "'";
2998

    
2999
        return resp;
3000
    }
3001

    
3002
    private static String cropStringValue(String orig_val, int i,
3003
        FieldDescription[] _flds) {
3004
        if (orig_val == null) {
3005
            return "NULL";
3006
        }
3007

    
3008
        int tpe = _flds[i].getFieldType();
3009
        int max_size = maxSizeForFieldType(tpe);
3010

    
3011
        if (max_size == -1) {
3012
            return orig_val;
3013
        }
3014

    
3015
        int or_size = orig_val.length();
3016

    
3017
        if (or_size <= max_size) {
3018
            return orig_val;
3019
        }
3020

    
3021
        return orig_val.substring(0, max_size);
3022
    }
3023

    
3024
    private static String avoidQuoteProblem(String str) {
3025
        return str.replaceAll("'", "''");
3026
    }
3027

    
3028
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3029
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3030
            return "";
3031
        }
3032

    
3033
        return "'";
3034
    }
3035

    
3036
    /**
3037
     * Utility function to translate a SRS code from EPSG to Oracle.
3038
     * Uses a datasource based on a DBF file.
3039
     *
3040
     * @param epsg the EPSG code
3041
     * @return the Oracle code
3042
     */
3043
    public static String epsgSridToOracleSrid(String epsg) throws Exception {
3044
        String resp = "8307";
3045

    
3046
        // --------------------------------------------
3047
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3048
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3049
        DataSource ds = null;
3050

    
3051
        try {
3052
            ds = LayerFactory.getDataSourceFactory()
3053
                             .executeSQL(sql,
3054
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3055

    
3056
            if (ds.getRowCount() == 0) {
3057
                logger.error("EPSG code not found in table: " + epsg);
3058
                throw new Exception("Unknown EPSG: " + epsg);
3059
            }
3060

    
3061
            if (ds.getRowCount() > 1) {
3062
                logger.error("===============");
3063
                logger.error(
3064
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
3065
                    epsg);
3066

    
3067
                for (int i = 0; i < ds.getRowCount(); i++) {
3068
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3069

    
3070
                    if (i == 0) {
3071
                        resp = "" + aux;
3072
                    }
3073

    
3074
                    logger.error("" + aux);
3075
                }
3076

    
3077
                logger.error("===============");
3078

    
3079
                return resp;
3080
            }
3081

    
3082
            resp = "" +
3083
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3084
        }
3085
        catch (Exception pe) {
3086
            logger.error("Error with SQL statement. " + pe.getMessage());
3087
        }
3088

    
3089
        return resp;
3090
    }
3091

    
3092
    /**
3093
     * Utility function to translate a SRS code from Oracle to EPSG.
3094
     * Uses a datasource based on a DBF file.
3095
     *
3096
     * @param ora the Oracle code
3097
     * @return the EPSG code
3098
     */
3099
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3100
        String resp = "4326";
3101

    
3102
        // --------------------------------------------
3103
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3104
            " where ORACLE = " + ora + ";";
3105
        DataSource ds = null;
3106

    
3107
        try {
3108
            ds = LayerFactory.getDataSourceFactory()
3109
                             .executeSQL(sql,
3110
                    DataSourceFactory.AUTOMATIC_OPENING);
3111

    
3112
            if (ds.getRowCount() == 0) {
3113
                logger.error("Oracle Spatial code not found in table: " + ora);
3114
                throw new Exception("Unknown Oracle code: " + ora);
3115
            }
3116

    
3117
            if (ds.getRowCount() > 1) {
3118
                logger.error("===============");
3119
                logger.error(
3120
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3121
                    ora);
3122

    
3123
                for (int i = 0; i < ds.getRowCount(); i++) {
3124
                    String aux = "" +
3125
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3126

    
3127
                    if (i == 0) {
3128
                        resp = aux;
3129
                    }
3130

    
3131
                    logger.error("" + aux);
3132
                }
3133

    
3134
                logger.error("===============");
3135

    
3136
                return resp;
3137
            }
3138

    
3139
            resp = "" +
3140
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3141
        }
3142
        catch (Exception pe) {
3143
            logger.error("Error with SQL statement. " + pe.getMessage());
3144
        }
3145

    
3146
        return resp;
3147
    }
3148

    
3149
    /**
3150
     * This methos creates the datasource used to translate the SRS codes:
3151
     * EPSG <--> Oracle.
3152
     *
3153
     * It's called from several places, so checks that the datasource does not exist.
3154
     */
3155
    public static void createOracleEpsgTable() {
3156
        SourceInfo si = LayerFactory.getDataSourceFactory()
3157
                                    .getDriverInfo(ORACLE_EPSG_TABLE_NAME);
3158

    
3159
        if (si != null) { // already created, nothing done
3160
            return;
3161
        }
3162

    
3163
        // Create 'oracle codes - epsg codes' table
3164
        DBFDriver dbfdrv = new DBFDriver();
3165

    
3166
        // dbfdrv.setDataSourceFactory()
3167
        OFileDataSourceAdapter fdsa = new OFileDataSourceAdapter();
3168

    
3169
        fdsa.setDriver(dbfdrv);
3170

    
3171
        // ---------------------------------------------
3172
        FileSourceInfo fsi = new FileSourceInfo();
3173
        fsi.file = createFileString("dbf/" + ORACLE_EPSG_FILE_NAME);
3174
        fsi.spatial = false;
3175
        fsi.name = ORACLE_EPSG_TABLE_NAME;
3176
        fsi.driverName = dbfdrv.getName(); //"DBF Driver";
3177
                                           // ---------------------------------------------
3178

    
3179
        fdsa.setSourceInfo(fsi);
3180

    
3181
        SelectableDataSource sds = null;
3182
        EditableAdapter ea = new EditableAdapter();
3183
        ProjectTable pt = null;
3184

    
3185
        try {
3186
            sds = new SelectableDataSource(fdsa);
3187
            ea.setOriginalDataSource(sds);
3188
            pt = ProjectTableFactory.createTable(ORACLE_EPSG_TABLE_NAME, ea);
3189
        }
3190
        catch (Exception ex) {
3191
            System.err.println("While creating datasource: " + ex.getMessage());
3192
        }
3193

    
3194
        sds.setSourceInfo(fsi);
3195

    
3196
        DataSourceFactory dsf = LayerFactory.getDataSourceFactory();
3197
        dsf.addFileDataSource(fsi.driverName, fsi.name, fsi.file);
3198
        sds.setDataSourceFactory(dsf);
3199
    }
3200

    
3201
    private static String createFileString(String path) {
3202
        try {
3203
            File f = new File(
3204
                    "./gvSIG/extensiones/" + EXTENSION_DIR_NAME + "/" +
3205
                    path);
3206

    
3207
            return f.getCanonicalPath();
3208
        }
3209
        catch (Exception ex) {
3210
            return "./gvSIG/extensiones/" + EXTENSION_DIR_NAME + "/" +
3211
            path;
3212
        }
3213
    }
3214

    
3215
    /**
3216
     * Utility method to get a valid Oracle identifier (in terms of length)
3217
     *
3218
     * @param str Proposed string
3219
     * @param ind field index of the given field name (used by the method to
3220
     * improve the renaming)
3221
     * @return an acceptable oracle identifier.
3222
     */
3223
    public static String getValidOracleID(String str, int ind) {
3224
        if (str.length() <= MAX_ID_LENGTH) {
3225
            return str;
3226
        }
3227

    
3228
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3229
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3230
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3231
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3232
        resp = resp + "_" + (ind % 1000);
3233

    
3234
        return resp;
3235
    }
3236

    
3237
    private static ArrayList ensureSensibleShell(ArrayList cc) {
3238
        if (sameCoordinate((Coordinate) cc.get(0),
3239
                    (Coordinate) cc.get(cc.size() - 1))) {
3240
            if (cc.size() == 2) {
3241
                ArrayList resp = new ArrayList();
3242
                resp.add(cc.get(0));
3243

    
3244
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3245
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3246
                resp.add(newcoo);
3247

    
3248
                newcoo = new Coordinate((Coordinate) cc.get(0));
3249
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3250
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
3251
                resp.add(newcoo);
3252

    
3253
                resp.add(cc.get(0));
3254

    
3255
                return resp;
3256
            }
3257

    
3258
            if (cc.size() == 3) {
3259
                cc.remove(1);
3260

    
3261
                return ensureSensibleShell(cc);
3262
            }
3263

    
3264
            return cc;
3265
        }
3266
        else {
3267
            cc.add(cc.get(0));
3268

    
3269
            return cc;
3270
        }
3271
    }
3272

    
3273
    private static ArrayList ensureSensibleHole(ArrayList cc) {
3274
        if (sameCoordinate((Coordinate) cc.get(0),
3275
                    (Coordinate) cc.get(cc.size() - 1))) {
3276
            if (cc.size() == 2) {
3277
                ArrayList resp = new ArrayList();
3278
                resp.add(cc.get(0));
3279

    
3280
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3281
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3282
                resp.add(newcoo);
3283

    
3284
                newcoo = new Coordinate((Coordinate) cc.get(0));
3285
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3286
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3287
                resp.add(newcoo);
3288

    
3289
                resp.add(cc.get(0));
3290

    
3291
                return resp;
3292
            }
3293

    
3294
            if (cc.size() == 3) {
3295
                cc.remove(1);
3296

    
3297
                return ensureSensibleHole(cc);
3298
            }
3299

    
3300
            return cc;
3301
        }
3302
        else {
3303
            cc.add(cc.get(0));
3304

    
3305
            return cc;
3306
        }
3307
    }
3308

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

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

    
3320
                return resp;
3321
            }
3322
        }
3323

    
3324
        return cc;
3325
    }
3326

    
3327
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3328
        if (c1.x != c2.x) {
3329
            return false;
3330
        }
3331

    
3332
        if (c1.y != c2.y) {
3333
            return false;
3334
        }
3335

    
3336
        return true;
3337
    }
3338

    
3339
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3340
        if (cc.size() == 2) {
3341
            return null;
3342
        }
3343

    
3344
        if (cc.size() == 3) {
3345
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3346
                return null;
3347
            }
3348

    
3349
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3350
                return null;
3351
            }
3352

    
3353
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3354
                return null;
3355
            }
3356

    
3357
            cc.add(cc.get(0));
3358

    
3359
            return cc;
3360
        }
3361

    
3362
        if (!sameCoordinate((Coordinate) cc.get(0),
3363
                    (Coordinate) cc.get(cc.size() - 1))) {
3364
            cc.add(cc.get(0));
3365
        }
3366

    
3367
        return cc;
3368
    }
3369

    
3370
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3371
        Coordinate[] p = new Coordinate[4];
3372
        p[0] = c;
3373

    
3374
        Coordinate nc = new Coordinate(c);
3375
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3376

    
3377
        Coordinate nc2 = new Coordinate(nc);
3378
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3379
        p[1] = nc;
3380
        p[2] = nc2;
3381
        p[3] = new Coordinate(c);
3382

    
3383
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3384
        LinearRing ls = new LinearRing(cs, geomFactory);
3385
        Polygon po = new Polygon(ls, null, geomFactory);
3386
        Polygon[] pos = new Polygon[1];
3387
        pos[0] = po;
3388

    
3389
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3390

    
3391
        return mpo;
3392
    }
3393

    
3394
    public String getSourceProjection() {
3395
        // TODO Auto-generated method stub
3396
        if (tableHasSrid) {
3397
            return epsgSRID;
3398
        }
3399

    
3400
        return destProj;
3401
    }
3402

    
3403
    public String getDestProjection() {
3404
        return destProj;
3405
    }
3406

    
3407
    public void setDestProjection(String toEPSG) {
3408
        destProj = toEPSG;
3409
        try {
3410
                        destProjOracle = epsgSridToOracleSrid(destProj);
3411
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3412
                        
3413
                } catch (Exception e) {
3414
                        logger.error("Unknown EPSG code: " + destProj);
3415
                        destProjOracle = oracleSRID;
3416
                        isDestGeogCS = false;
3417
                }
3418
        
3419
    }
3420
    
3421
    public String getDestProjectionOracleCode() {
3422
            return destProjOracle;
3423
    }
3424
    
3425
    public boolean getIsDestProjectionGeog() {
3426
            return isDestGeogCS;
3427
    }
3428
    
3429
    public String getTableProjectionOracleCode() {
3430
            return oracleSRID;
3431
    }
3432

    
3433
    public boolean canReproject(String toEPSGdestinyProjection) {
3434
        return false;
3435
    }
3436

    
3437
    /**
3438
     * Utility function. Says whether a given field name can be a user field name
3439
     * or not (for example, "ROWID" is not a valid one because it's a system
3440
     * reserved word).
3441
     *
3442
     * @param str proposed firld name
3443
     * @return whether it is valid or not for Oracle databases
3444
     */
3445
    private static boolean isOracleAllowedFieldname(String str) {
3446
        if (str.compareToIgnoreCase("rowid") == 0) {
3447
            return false;
3448
        }
3449

    
3450
        if (str.compareToIgnoreCase("rownum") == 0) {
3451
            return false;
3452
        }
3453

    
3454
        return true;
3455
    }
3456

    
3457
    public Hashtable getHashRelate() {
3458
        return hashRelate;
3459
    }
3460

    
3461
    public void setHashRelate(Hashtable m) {
3462
        hashRelate = m;
3463
    }
3464

    
3465
    public void setNumReg(int n) {
3466
        numReg = n;
3467
    }
3468

    
3469
    private int[] getRandomSample(int maxn_one_based, int n) {
3470
        int[] resp = new int[n];
3471

    
3472
        if (maxn_one_based <= n) {
3473
            resp = new int[maxn_one_based];
3474

    
3475
            for (int i = 0; i < maxn_one_based; i++) {
3476
                resp[i] = i;
3477
            }
3478
        }
3479
        else {
3480
            Random rnd = new Random();
3481

    
3482
            for (int i = 0; i < n; i++) {
3483
                resp[i] = rnd.nextInt(maxn_one_based);
3484
            }
3485
        }
3486

    
3487
        return resp;
3488
    }
3489

    
3490
    private String getRowIdRestrictionCondition(int nrecords) {
3491
        int[] zero_based_rows = getRandomSample(nrecords,
3492
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3493
        String resp = "(";
3494
        Object aux = "";
3495
        ROWID riaux = null;
3496

    
3497
        for (int i = 0; i < zero_based_rows.length; i++) {
3498
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3499
            riaux = (ROWID) aux;
3500
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3501
        }
3502

    
3503
        resp = resp.substring(0, resp.length() - 4);
3504
        resp = resp + ")";
3505

    
3506
        return resp;
3507
    }
3508

    
3509
    private Rectangle2D getBoundingFromSample(int n_max) {
3510
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3511
            " WHERE " + getRowIdRestrictionCondition(n_max);
3512
        STRUCT auxstr = null;
3513
        IGeometry theGeom = null;
3514
        Rectangle2D resp = null;
3515

    
3516
        try {
3517
            Statement st = conn.createStatement();
3518
            ResultSet rs = st.executeQuery(_qry);
3519

    
3520
            if (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
                while (rs.next()) {
3535
                    auxstr = (STRUCT) rs.getObject(1);
3536

    
3537
                    if (auxstr != null) {
3538
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3539

    
3540
                        if (resp == null) {
3541
                            resp = theGeom.getBounds2D();
3542
                        }
3543
                        else {
3544
                            resp.add(theGeom.getBounds2D());
3545
                        }
3546
                    }
3547
                }
3548

    
3549
                rs.close();
3550
                st.close();
3551
            }
3552
            else {
3553
                throw new SQLException("Empty resultset from this query: " +
3554
                    _qry);
3555
            }
3556
        }
3557
        catch (SQLException se) {
3558
            System.err.println("Error while getting sample full extent: " +
3559
                se.getMessage());
3560
        }
3561

    
3562
        if (resp == null) {
3563
            logger.warn(
3564
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3565

    
3566
            return new Rectangle2D.Double(-180, -90, 360, 180);
3567
        }
3568

    
3569
        return resp;
3570
    }
3571

    
3572
    /**
3573
     * Does what it says, puts the LinearRing in counter clock wise
3574
     * order.
3575
     * @param ls The ring to set.
3576
     * @param gf a GeometryFactory object
3577
     * @return A new ring in CCW order.
3578
     *
3579
     */
3580
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3581
        Coordinate[] cc = ls.getCoordinates();
3582

    
3583
        if (CGAlgorithms.isCCW(cc)) {
3584
            return gf.createLinearRing(cc);
3585
        }
3586
        else {
3587
            if (ls instanceof LinearRing) {
3588
                return reverseRing((LinearRing) ls, gf);
3589
            }
3590
            else {
3591
                return reverseLineString(ls, gf);
3592
            }
3593
        }
3594
    }
3595

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

    
3606
        for (int t = numPoints; t >= 0; t--) {
3607
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3608
        }
3609

    
3610
        return gf.createLinearRing(newCoords);
3611
    }
3612

    
3613
    /**
3614
     * Does what it says, reverses the order of the Coordinates in the linestring.
3615
     * @param ls The ls to reverse.
3616
     * @param gf a GeometryFactory object 
3617
     * @return A new ls with the reversed Coordinates.
3618
     *
3619
     */
3620
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3621
        int numPoints = ls.getNumPoints() - 1;
3622
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3623

    
3624
        for (int t = numPoints; t >= 0; t--) {
3625
            newCoords[t] = ls.getCoordinateN(numPoints - t);
3626
        }
3627

    
3628
        return gf.createLinearRing(newCoords);
3629
    }
3630

    
3631
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3632
        if (ge instanceof MultiPolygon) {
3633
            MultiPolygon mp = (MultiPolygon) ge;
3634
            int size = ge.getNumGeometries();
3635
            Polygon[] pols = new Polygon[size];
3636

    
3637
            for (int i = 0; i < size; i++)
3638
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3639
                        gf);
3640

    
3641
            return new MultiPolygon(pols, gf);
3642
        }
3643
        else {
3644
            if (ge instanceof Polygon) {
3645
                Polygon p = (Polygon) ge;
3646
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3647
                int nholes = p.getNumInteriorRing();
3648

    
3649
                if (nholes > 0) {
3650
                    LinearRing[] holes = new LinearRing[nholes];
3651

    
3652
                    for (int i = 0; i < nholes; i++) {
3653
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3654
                    }
3655

    
3656
                    return gf.createPolygon(exterior, holes);
3657
                }
3658
                else {
3659
                    return gf.createPolygon(exterior, null);
3660
                }
3661
            }
3662
            else {
3663
                return ge;
3664
            }
3665
        }
3666
    }
3667

    
3668
    /**
3669
     * Converts from IGeometry to STRUCT
3670
     *
3671
     * @param ig the geometry to convert
3672
     * @param _forced_type forced type to use
3673
     * @param _conn connection
3674
     * @param _o_srid  SRS (oracle code)
3675
     * @param withSrid whether this STRUCT has a non-NULL SRS
3676
     * @param agu_bien whether or not to check the correctness of the holes
3677
     * @param _isGeoCS whether the SRS is geodetic or not
3678
     * @return the generated STRUCT
3679
     */
3680
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
3681
        Connection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
3682
        boolean _isGeoCS) {
3683
        if (ig instanceof FGeometryCollection) {
3684
            FGeometryCollection coll = (FGeometryCollection) ig;
3685

    
3686
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3687
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3688

    
3689
            // logger.error("Collections no soportadas por ahora.");
3690
            // return null;
3691
        }
3692
        else {
3693
            Shape shp = ig.getInternalShape();
3694

    
3695
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3696
                agu_bien, false, _isGeoCS);
3697
        }
3698
    }
3699

    
3700
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3701
        boolean agu_bien, boolean isView) {
3702
            
3703
            if (shp == null) return null; 
3704
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3705
            agu_bien, isView, isGeogCS);
3706
    }
3707

    
3708
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3709
        Connection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3710
        boolean isView, boolean _isGeoCS) {
3711
        int _srid = -1;
3712

    
3713
        if (o_srid.length() > 0) {
3714
            _srid = Integer.parseInt(o_srid);
3715
        }
3716

    
3717
        if (shp == null) {
3718
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3719

    
3720
            return null;
3721
        }
3722

    
3723
        if (shp instanceof Rectangle2D) {
3724
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3725
                _isGeoCS, o_srid, _conn);
3726
        }
3727

    
3728
        try {
3729
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3730
                    _srid, agu_bien, hasSrid);
3731

    
3732
            return the_struct;
3733
        }
3734
        catch (SQLException ex) {
3735
            logger.error("While creating STRUCT: " + ex.getMessage());
3736

    
3737
            return null;
3738
        }
3739
    }
3740

    
3741
    // -------------------------- not ready yet ----------------
3742
    public int getRowIndexByFID(IFeature _fid) {
3743
        if (isNotAvailableYet) {
3744
            return -1;
3745
        }
3746
        else {
3747
            return super.getRowIndexByFID(_fid);
3748
        }
3749
    }
3750

    
3751
    public int getShapeCount() throws IOException {
3752
        if (isNotAvailableYet) {
3753
            return 0;
3754
        }
3755
        else {
3756
            return numReg;
3757
        }
3758
    }
3759

    
3760
    public void setNotAvailableYet(boolean nav) {
3761
        isNotAvailableYet = nav;
3762
    }
3763

    
3764
    // -------------------------------------------------------
3765
    // -------------------------------------------------------
3766
    public String[] getTableNames(Connection conn, String catalog)
3767
        throws SQLException {
3768
        DatabaseMetaData dbmd = conn.getMetaData();
3769
        String[] types = { "TABLE", "VIEW" };
3770

    
3771
        ResultSet rs = null;
3772
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3773
                    ORACLE_GEOMETADATA_VIEW, types), conn);
3774
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3775
//                          ORACLE_GEOMETADATA_VIEW, types);
3776
        TreeMap ret = new TreeMap();
3777

    
3778
        while (rs.next()) {
3779
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
3780
            ret.put(nomCompleto, nomCompleto);
3781
        }
3782

    
3783
        return (String[]) ret.keySet().toArray(new String[0]);
3784
    }
3785

    
3786
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3787
        throws SQLException {
3788
        String tablename = "";
3789
        
3790
        
3791

    
3792
        if (res.next()) {
3793
            tablename = res.getString("TABLE_NAME");
3794
            
3795
            // debug 
3796
            // writeMetaTableToLog(con, tablename);
3797

    
3798
            Statement __st = con.createStatement();
3799

    
3800
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3801
                "union (select VIEW_NAME from USER_VIEWS)) " +
3802
                "intersect (select TABLE_NAME from " + tablename + ")";
3803
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
3804
            ResultSet rs = __st.executeQuery(sql);
3805

    
3806
            return rs;
3807
        }
3808
        else {
3809
            logger.error("Error while getting geometry tables.");
3810

    
3811
            return null;
3812
        }
3813
    }
3814

    
3815
    private void writeMetaTableToLog(Connection con, String tname) {
3816
            
3817
            logger.debug("======================================================");
3818
            logger.debug("=     USER_SDO_GEOM_METADATA     =====================");
3819
            logger.debug("======================================================");
3820

    
3821
            try {
3822
            Statement _stmt = con.createStatement();
3823
            String sql = "SELECT * FROM " + tname;
3824
            ResultSet res = _stmt.executeQuery(sql);
3825
            while (res.next()) {
3826
                    logger.debug("======================================================");
3827
                    logger.debug("TABLE_NAME: " + res.getString("TABLE_NAME"));
3828
                    logger.debug("COLUMN_NAME: " + res.getString("COLUMN_NAME"));
3829
                    logger.debug("SRID: " + res.getString("SRID"));
3830
                    
3831
                    ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3832
                    String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3833
                    logger.debug("DIMINFO: " + dinfo);
3834
                    logger.debug("======================================================");
3835
                    
3836
            }
3837
            } catch (Throwable th) {
3838
                    
3839
            }
3840
            
3841
            
3842
            
3843
            
3844
            
3845
                // TODO Auto-generated method stub
3846
                
3847
        }
3848

    
3849
        /**
3850
     * Gets the field names that can act as row id (always ROWID)
3851
     */
3852
    public String[] getIdFieldsCandidates(Connection conn, String table_name)
3853
        throws SQLException {
3854
        String[] resp = { "ROWID" };
3855

    
3856
        return resp;
3857
    }
3858

    
3859
    /**
3860
     * Gets the field names that can act as geometry fields
3861
     * (queries the user's geographic metadata).
3862
     */
3863
    public String[] getGeometryFieldsCandidates(Connection conn,
3864
        String table_name) throws SQLException {
3865
        Statement _st = conn.createStatement();
3866
        String[] tokens = table_name.split("\\u002E", 2);
3867
        String qry;
3868
        if (tokens.length > 1)
3869
        {
3870
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3871
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" + 
3872
            tokens[1] + "'";
3873
        }
3874
        else
3875
        {
3876
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3877
            " where TABLE_NAME = " + "'" + table_name + "'";
3878

    
3879
        }
3880
        ResultSet _rs = _st.executeQuery(qry);
3881

    
3882
        ArrayList aux = new ArrayList();
3883

    
3884
        while (_rs.next()) {
3885
            String _geo = _rs.getString("COLUMN_NAME");
3886
            aux.add(_geo);
3887
        }
3888

    
3889
        _rs.close();
3890
        _st.close();
3891

    
3892
        return (String[]) aux.toArray(new String[0]);
3893
    }
3894

    
3895
    /**
3896
     * Utility method to check if a given table is empty.
3897
     */
3898
    public boolean isEmptyTable(Connection conn, String tableName) {
3899
        boolean res = true;
3900

    
3901
        try {
3902
            Statement st = conn.createStatement();
3903
            ResultSet rs = null;
3904
            rs = st.executeQuery("select * from " + tableName +
3905
                    " where rownum = 1");
3906
            res = !rs.next();
3907
            rs.close();
3908
            st.close();
3909
        }
3910
        catch (Exception ex) {
3911
            res = true;
3912
        }
3913

    
3914
        return res;
3915
    }
3916

    
3917
    /**
3918
     * Gets all the fields from a table name.
3919
     */
3920
    public String[] getAllFields(Connection conn, String table_name)
3921
        throws SQLException {
3922
        Statement st = conn.createStatement();
3923
        ResultSet rs = st.executeQuery("select * from " + table_name +
3924
                " where rownum = 1");
3925
        ResultSetMetaData rsmd = rs.getMetaData();
3926
        String[] ret = new String[rsmd.getColumnCount()];
3927

    
3928
        for (int i = 0; i < ret.length; i++) {
3929
            ret[i] = rsmd.getColumnName(i + 1);
3930
        }
3931

    
3932
        rs.close();
3933
        st.close();
3934

    
3935
        return ret;
3936
    }
3937

    
3938
    /**
3939
     * Gets all field type names from a table.
3940
     */
3941
    public String[] getAllFieldTypeNames(Connection conn, String table_name)
3942
        throws SQLException {
3943
        Statement st = conn.createStatement();
3944
        ResultSet rs = st.executeQuery("select * from " + table_name +
3945
                " where rownum = 1");
3946
        ResultSetMetaData rsmd = rs.getMetaData();
3947
        String[] ret = new String[rsmd.getColumnCount()];
3948

    
3949
        for (int i = 0; i < ret.length; i++) {
3950
            ret[i] = rsmd.getColumnTypeName(i + 1);
3951
        }
3952

    
3953
        rs.close();
3954
        st.close();
3955

    
3956
        close();
3957

    
3958
        return ret;
3959
    }
3960

    
3961
    /**
3962
     * Gets Oracle's specific connection string for the given parameters.
3963
     */
3964
    public String getConnectionString(String host, String port, String dbname,
3965
        String user, String pw) {
3966
        String _pw = pw;
3967

    
3968
        if (_pw == null) {
3969
            _pw = "null";
3970
        }
3971

    
3972
        String fullstr = CONN_STR_BEGIN;
3973
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
3974
        fullstr = fullstr + "@" + host.toLowerCase();
3975
        fullstr = fullstr + ":" + port;
3976
        fullstr = fullstr + ":" + dbname.toLowerCase();
3977

    
3978
        return fullstr;
3979
    }
3980

    
3981
    /**
3982
     * Gets the Pracle geometries writer associated with this driver.
3983
     */
3984
    public IWriter getWriter() {
3985
        // on(VectorialEditableDBAdapter.java:290)
3986
        if (writer == null) {
3987
            writer = new OracleSpatialWriter(getRowCount());
3988
            writer.setDriver(this);
3989
            writer.setLyrShapeType(getShapeType());
3990
            writer.setGeoCS(isGeogCS());
3991
            writer.setGeoColName(geoColName);
3992
            writer.setSRID(oracleSRID);
3993

    
3994
            try {
3995
                writer.initialize(getLyrDef());
3996
            }
3997
            catch (EditionException e) {
3998
                logger.error("While initializing OS Writer: " + e.getMessage(),
3999
                    e);
4000
            }
4001

    
4002
            writer.setStoreWithSrid(tableHasSrid);
4003
        }
4004

    
4005
        return writer;
4006
    }
4007

    
4008
    /**
4009
     * Tells whether the SRS is geodetic or not
4010
     * @return whether the SRS is geodetic or not
4011
     */
4012
    public boolean isGeogCS() {
4013
        return isGeogCS;
4014
    }
4015

    
4016
    /**
4017
     * Adds a row id to the inner set od IDs.
4018
     * @param id
4019
     */
4020
    public void addRow(String id) {
4021
        Value aux = ValueFactory.createValue(id);
4022
        Integer intobj = new Integer(numReg);
4023
        hashRelate.put(aux, intobj);
4024
        rowToId.put(intobj, id);
4025

    
4026
        numReg++;
4027
    }
4028

    
4029
    /**
4030
     * Removes a row id to the inner set od IDs.
4031
     * @param id
4032
     */
4033
    public void deleteRow(String id) {
4034
        Value aux = ValueFactory.createValue(id);
4035
        Integer intobj = (Integer) hashRelate.get(aux);
4036
        hashRelate.remove(aux);
4037
        rowToId.remove(intobj);
4038

    
4039
        numReg--;
4040
    }
4041

    
4042
    private String getStandardSelectExpression() {
4043
        if (standardSelectExpressionFalse == null) {
4044
            standardSelectExpressionFalse = "";
4045

    
4046
            String[] flds = getLyrDef().getFieldNames();
4047
            int size = flds.length;
4048

    
4049
            for (int i = 0; i < size; i++) {
4050
                if (i > 0) {
4051
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4052
                        "c.\"" + flds[i] + "\", ";
4053
                }
4054
                else {
4055
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4056
                        flds[i] + ", ";
4057
                }
4058
            }
4059

    
4060
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4061
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4062
                    standardSelectExpressionFalse.length() - 2);
4063
        }
4064

    
4065
        return standardSelectExpressionFalse;
4066
    }
4067

    
4068
    /**
4069
     * Allows the method to decide what to do with the geometry field name
4070
     * (remove/add it from the user selected fields).
4071
     *
4072
     * @param flds
4073
     * @param geof
4074
     * @return the possibly modified field names
4075
     */
4076
    public String[] manageGeometryField(String[] flds, String geof) {
4077
        return addEndIfNotContained(flds, geof);
4078
    }
4079

    
4080
    /**
4081
     * Allows the method to decide what to do with the ID field name
4082
     * (remove/add it from the user selected fields).
4083
     *
4084
     * @param flds
4085
     * @param idf
4086
     * @return the possibly modified field names
4087
     */
4088
    public String[] manageIdField(String[] flds, String idf) {
4089
        return addStartIfNotContained(flds, idf);
4090
    }
4091

    
4092
    private String[] addEndIfNotContained(String[] arr, String item) {
4093
        if (contains(arr, item)) {
4094
            return arr;
4095
        }
4096
        else {
4097
            int size = arr.length;
4098
            String[] resp = new String[size + 1];
4099

    
4100
            for (int i = 0; i < size; i++) {
4101
                resp[i] = arr[i];
4102
            }
4103

    
4104
            resp[size] = item;
4105

    
4106
            return resp;
4107
        }
4108
    }
4109

    
4110
    private String[] addStartIfNotContained(String[] arr, String item) {
4111
        if (contains(arr, item)) {
4112
            return arr;
4113
        }
4114
        else {
4115
            int size = arr.length;
4116
            String[] resp = new String[size + 1];
4117

    
4118
            for (int i = 1; i <= size; i++) {
4119
                resp[i] = arr[i];
4120
            }
4121

    
4122
            resp[0] = item;
4123

    
4124
            return resp;
4125
        }
4126
    }
4127

    
4128
    private boolean contains(String[] arr, String item) {
4129
        for (int i = 0; i < arr.length; i++) {
4130
            if (arr[i].compareTo(item) == 0) {
4131
                return true;
4132
            }
4133
        }
4134

    
4135
        return false;
4136
    }
4137

    
4138
    /**
4139
     * This method is called when the user removes the layer from the view.
4140
     * If the IDs were being loaded, the driver will check this field and will
4141
     * let the thread 'die' quietly.
4142
     *
4143
     */
4144
    public void remove() {
4145
        cancelIDLoad = true;
4146
    }
4147
    
4148
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4149
            if (!isgeodetic) return true;
4150
            if (ext.getMinX() > -179.99) return true; 
4151
            if (ext.getMinY() > -89.99) return true; 
4152
            if (ext.getWidth() < 359.99) return true; 
4153
            if (ext.getHeight() < 179.99) return true; 
4154
            return false;
4155
    }
4156
    
4157
    private Rectangle2D getFastEstimatedGeodeticExtent(
4158
                    String tname, String gfield, Connection c, int sample_size, double enlargement) {
4159

    
4160
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4161
            Rectangle2D resp_aux = null;
4162
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4163
            ResultSet _rs = null;
4164

    
4165
            try {
4166
                        PreparedStatement _st = c.prepareStatement(qry);
4167
                        _rs = _st.executeQuery();
4168
                        while (_rs.next()) {
4169
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4170
                                IGeometry ig = getGeometryUsing(aux, false);
4171
                                
4172
                                if (ig == null) continue;
4173
                                
4174
                                if (resp_aux == null) {
4175
                                        resp_aux = ig.getBounds2D();
4176
                                } else {
4177
                                        resp_aux.add(ig.getBounds2D());
4178
                                }
4179
                                
4180
                        }
4181
                } catch (Exception ex) {
4182
                        logger.error("While getting random sample: " + ex.getMessage());
4183
                        return world;
4184
                }
4185
                
4186
                if (resp_aux == null) return world;
4187
                double w = resp_aux.getWidth();
4188
                double h = resp_aux.getHeight();
4189
                double x = resp_aux.getMinX();
4190
                double y = resp_aux.getMinY();
4191
                
4192
                // enlarge 10 times:
4193
                double newx = x - (0.5 * (enlargement - 1)) * w;
4194
                double newy = y - (0.5 * (enlargement - 1)) * w;
4195
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4196
                                enlargement * w,
4197
                                enlargement * h);
4198
                
4199
                
4200
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4201
                
4202
                logger.debug("FAST BB:");
4203
                logger.debug(" min x:" + resp_aux.getMinX());
4204
                logger.debug(" min y:" + resp_aux.getMinY());
4205
                logger.debug("     w:" + resp_aux.getWidth());
4206
                logger.debug("     h:" + resp_aux.getHeight());
4207
                return resp_aux;
4208
    }
4209
    
4210
    private Rectangle2D getEstimatedGeodeticExtent(
4211
                    String tname, String gfield, Connection c, int sample_size, double enlargement) {
4212
            
4213
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4214
            
4215
            ArrayList ids = new ArrayList();
4216
            int _rnd_index = 0;
4217
            ROWID _id = null;
4218
            Random rnd = new Random(System.currentTimeMillis());
4219
            
4220
            for (int i=0; i<sample_size; i++) {
4221
                    _rnd_index = rnd.nextInt(numReg);
4222
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
4223
                    ids.add(_id.stringValue());
4224
            }
4225
            
4226
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
4227
            for (int i=0; i<ids.size(); i++) {
4228
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR "; 
4229
            }
4230
            qry = qry.substring(0, qry.length() - 4) + ")";
4231
            
4232
            Rectangle2D resp_aux = null;
4233
            ResultSet _rs = null;
4234

    
4235
            try {
4236
                        PreparedStatement _st = c.prepareStatement(qry);
4237
                        _rs = _st.executeQuery();
4238
                        while (_rs.next()) {
4239
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4240
                                IGeometry ig = getGeometryUsing(aux, false);
4241
                                
4242
                                if (ig == null) continue;
4243
                                
4244
                                if (resp_aux == null) {
4245
                                        resp_aux = ig.getBounds2D();
4246
                                } else {
4247
                                        resp_aux.add(ig.getBounds2D());
4248
                                }
4249
                                
4250
                        }
4251
                } catch (Exception ex) {
4252
                        logger.error("While getting random sample: " + ex.getMessage());
4253
                        return world;
4254
                }
4255
                
4256
                if (resp_aux == null) return world;
4257
                double w = resp_aux.getWidth();
4258
                double h = resp_aux.getHeight();
4259
                double x = resp_aux.getMinX();
4260
                double y = resp_aux.getMinY();
4261
                
4262
                // enlarge 10 times:
4263
                double newx = x - (0.5 * (enlargement - 1)) * w;
4264
                double newy = y - (0.5 * (enlargement - 1)) * w;
4265
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4266
                                enlargement * w,
4267
                                enlargement * h);
4268
                
4269
                
4270
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4271
                return resp_aux;
4272
    }
4273
    
4274
    
4275
    
4276
}