Statistics
| Revision:

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

History | View | Annotate | Download (129 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
import java.math.BigDecimal;
123

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

    
133
import java.text.ParseException;
134

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

    
142

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

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

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

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

    
197
    private OracleSpatialWriter writer = null;
198

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
301
        conn = _conn;
302

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

    
306
        setLyrDef(lyrDef);
307

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

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

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

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

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

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

    
353

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

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

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

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

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

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

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

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

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

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

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

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

    
406
        return false;
407
    }
408

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

    
414
        HashMap m = new HashMap();
415

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

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

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

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

    
430
        return iter.hasNext();
431
    }
432

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

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

    
441
            return ASSUMED_ORACLE_SRID;
442
        }
443

    
444
        return obj.toString();
445
    }
446

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

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

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

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

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

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

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

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

    
487
                return null;
488

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

    
494
    private void loadSdoMetadata() {
495
        try {
496
            Statement _st = conn.createStatement();
497
            String[] tokens = getTableName().split("\\u002E", 2);
498
            String qry;
499
            if (tokens.length > 1)
500
            {
501
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
502
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" + 
503
                tokens[1] + "'";
504
            }
505
            else
506
            {
507
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
508
                " where TABLE_NAME = " + "'" + getTableName() + "'";
509

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

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

    
518
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
519

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

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

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

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

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

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

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

    
581
        return resp;
582
    }
583

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

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

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

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

    
602
            // -----------------------
603
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
604
            metaData = _rs.getMetaData();
605
            userName = conn.getMetaData().getUserName();
606
            
607

    
608
            // geoColInd = _rs.findColumn(geoColName);
609
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
610

    
611
            DatabaseMetaData dbmd = conn.getMetaData();
612
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
613

    
614
            int cnt = metaData.getColumnCount();
615
            fieldNames = new String[cnt];
616

    
617
            for (int i = 0; i < cnt; i++) {
618
                fieldNames[i] = metaData.getColumnName(i + 1);
619
            }
620

    
621
            getIdFieldNames();
622

    
623
            adjustLyrDef();
624

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

    
632
    private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
633
        int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue() % 10;
634

    
635
        switch (code) {
636
        case 1:
637
            return FShape.POINT;
638

    
639
        case 2:
640
            return FShape.LINE;
641

    
642
        case 3:
643
            return FShape.POLYGON;
644

    
645
        case 5:
646
            return FShape.MULTIPOINT;
647

    
648
        case 6:
649
            return FShape.LINE;
650

    
651
        case 7:
652
            return FShape.POLYGON;
653
        }
654

    
655
        logger.error("Unknown geometry type: " + code);
656

    
657
        return FShape.NULL;
658
    }
659

    
660
    private String getIdFieldNames() {
661
        try {
662
            idFieldNames = "";
663

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

    
672
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
673

    
674
        return idFieldNames;
675
    }
676

    
677
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
678
        int[] _res = new int[1];
679
        _res[0] = 1;
680

    
681
        return _res;
682
    }
683

    
684
    public String getSqlTotal() {
685
        // TODO Auto-generated method stub
686
        return "";
687
    }
688

    
689
    public String getCompleteWhere() {
690
        // TODO Auto-generated method stub
691
        return "";
692
    }
693

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

    
704
        singleCachedFeatureRowNum = -1;
705

    
706
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
707

    
708
        ResultSet localrs = (ResultSet) rs_st[0];
709
        Statement _st = (Statement) rs_st[1];
710

    
711
        return new OracleSpatialFeatureIterator(this, localrs, _st,
712
            oneBasedGeoColInd, use_geotools);
713
    }
714

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

    
723
    public void open() throws DriverException {
724
    }
725

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

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

    
744
        singleCachedFeatureRowNum = -1;
745

    
746
        STRUCT local_st = shapeToStruct(r, FShape.NULL, true, false, true);
747

    
748
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
749

    
750
        ResultSet localrs = (ResultSet) rs_st[0];
751
        Statement _st = (Statement) rs_st[1];
752

    
753
        return new OracleSpatialFeatureIterator(this, localrs, _st,
754
            oneBasedGeoColInd, use_geotools);
755
    }
756

    
757
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
758
        if (workingAreaInTablesCS == null) return r;
759
        return doIntersect(r, workingAreaInTablesCS);
760
    }
761

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

    
771
            // return emptyIt;
772
        }
773

    
774
        singleCachedFeatureRowNum = -1;
775

    
776
        return getFeatureIterator(r, strEPSG);
777
    }
778

    
779
    public String getGeometryField(String fieldName) {
780
        return fieldName;
781

    
782
        // return "ASBINARY(" + fieldName + ")";
783
    }
784

    
785
    public DriverAttributes getDriverAttributes() {
786
        return drvAtts;
787
    }
788

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

    
799
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
800

    
801
        String _sql = "select " + geoColName + " from " + getTableName() +
802
            " where rowid = ?";
803

    
804
        try {
805
            java.sql.PreparedStatement ps = conn.prepareStatement(_sql);
806
            ps.setObject(1, r_id);
807

    
808
            // Statement stmnt = conn.createStatement();
809
            ps.execute();
810

    
811
            ResultSet _res = ps.getResultSet();
812

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

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

    
825
                return nullGeom;
826
            }
827
        }
828
        catch (SQLException se) {
829
            throw new IOException("SQLException: " + se.getMessage());
830
        }
831
    }
832

    
833
    public boolean isWritable() {
834
        return true;
835
    }
836

    
837
    public String getName() {
838
        return NAME;
839
    }
840

    
841
    public int[] getPrimaryKeys()
842
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
843
        return pkOneBasedIndexes;
844
    }
845

    
846
    public void write(DataWare dataWare)
847
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
848
    }
849

    
850
    private void setIdRowTable() {
851
        hashRelate = new Hashtable();
852

    
853
        java.sql.PreparedStatement ps = null;
854

    
855
        try {
856
            String _sql = getIdAndElemInfoFullResulltSetQuery();
857

    
858
            logger.debug("SQL para leer ids: " + _sql);
859
            Statement st = null;
860

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

    
871
            ROWID ri = null;
872

    
873
            int row = 0;
874
            String gid;
875
            Value aux = null;
876

    
877
            // ----------------------------------- types init
878
            ArrayList types = new ArrayList();
879
            int types_aux = 0;
880

    
881
            ARRAY info_aux;
882
            int[] info_aux_int;
883
            int size;
884

    
885
            // ----------------------------------- types init
886
            logger.debug("Beginning of result set:");
887

    
888
            while (_r.next()) {
889
                // ---------------------------------------
890
                ri = (ROWID) _r.getObject(1);
891
                gid = ri.stringValue();
892
                aux = ValueFactory.createValue(gid);
893

    
894
                Integer intobj = new Integer(row);
895
                hashRelate.put(aux, intobj);
896
                rowToId.put(intobj, ri);
897

    
898
                if ((row % 5000) == 0) {
899
                    // ------------------------------------------- cancel load
900
                    if (cancelIDLoad) {
901
                        hashRelate.clear();
902
                        rowToId.clear();
903

    
904
                        return;
905
                    }
906

    
907
                    // -------------------------------------------
908
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
909
                    logger.info("IDs read: " + fmt);
910
                }
911

    
912
                row++;
913

    
914
                // --------------------------------------- types
915
                info_aux = (ARRAY) _r.getObject(2);
916

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

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

    
930
                // --------------------------------------- types end
931
            }
932

    
933
            _r.close();
934
//            ps.close();
935
            st.close();
936
            numReg = row;
937

    
938
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
939

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

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

    
961
    public String[] getFieldNames() {
962
        return fieldNames;
963
    }
964

    
965
    public String getTotalFields() {
966
        String strAux = "";
967

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

    
977
        return strAux;
978
    }
979

    
980
    public int getFieldType(int idField)
981
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
982
        int i = 0;
983

    
984
        try {
985
            i = idField + 1; // idField viene basado en 0
986

    
987
            int __type = metaData.getColumnType(i);
988

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

    
995
            if (__type == Types.VARCHAR) {
996
                return Types.VARCHAR;
997
            }
998

    
999
            if (__type == Types.FLOAT) {
1000
                return Types.FLOAT;
1001
            }
1002

    
1003
            if (__type == Types.DOUBLE) {
1004
                return Types.DOUBLE;
1005
            }
1006

    
1007
            if (__type == Types.INTEGER) {
1008
                return Types.INTEGER;
1009
            }
1010

    
1011
            if (__type == Types.SMALLINT) {
1012
                return Types.SMALLINT;
1013
            }
1014

    
1015
            if (__type == Types.TINYINT) {
1016
                return Types.TINYINT;
1017
            }
1018

    
1019
            if (__type == Types.BIGINT) {
1020
                return Types.BIGINT;
1021
            }
1022

    
1023
            if (__type == Types.BIT) {
1024
                return Types.BIT;
1025
            }
1026

    
1027
            if (__type == Types.DATE) {
1028
                return Types.DATE;
1029
            }
1030

    
1031
            if (__type == Types.DECIMAL) {
1032
                return Types.DOUBLE;
1033
            }
1034

    
1035
            if (__type == Types.NUMERIC) {
1036
                return Types.DOUBLE;
1037
            }
1038

    
1039
            if (__type == Types.DATE) {
1040
                return Types.DATE;
1041
            }
1042

    
1043
            if (__type == Types.TIME) {
1044
                return Types.TIME;
1045
            }
1046

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

    
1056
        return -1;
1057
    }
1058

    
1059
    public Value[] getAttributes(ResultSet rs) {
1060
        Value[] res = null;
1061

    
1062
        try {
1063
            int fcount = rs.getMetaData().getColumnCount();
1064
            res = new Value[fcount];
1065

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

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

    
1092
                // /*
1093
                if (_type == -1) {
1094
                    obj = null;
1095
                }
1096

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

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

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

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

    
1126
            return null;
1127
        }
1128

    
1129
        return res;
1130
    }
1131
    
1132
    public Value[] getAttributesUsingMainMetadata(ResultSet rs) {
1133
        Value[] res = null;
1134

    
1135
        try {
1136
            int fcount = metaData.getColumnCount();
1137
            res = new Value[fcount];
1138

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

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

    
1165
                // /*
1166
                if (_type == -1) {
1167
                    obj = null;
1168
                }
1169

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

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

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

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

    
1199
            return null;
1200
        }
1201

    
1202
        return res;
1203
    }
1204
    
1205

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

    
1211
    public int getFieldWidth(int fieldId) {
1212
        int i = -1;
1213

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

    
1222
        if (i < 0) {
1223
            i = 255;
1224
        }
1225

    
1226
        return i;
1227
    }
1228

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

    
1235
        if ((singleCachedFeature != null) &&
1236
                (rowIndex == singleCachedFeatureRowNum)) {
1237
            return singleCachedFeature.getAttributes()[field_Id];
1238
        }
1239

    
1240
        // return ValueFactory.createNullValue();
1241
        ResultSet _r = null;
1242
        java.sql.PreparedStatement ps = null;
1243

    
1244
        try {
1245
            String rnq = getSearchId();
1246
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1247

    
1248
            ps = conn.prepareStatement(rnq);
1249
            ps.setObject(1, _id);
1250

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

    
1259
        IFeature ife = null;
1260
        Value[] atts = null;
1261

    
1262
        try {
1263
            ROWID ri = (ROWID) _r.getObject(1);
1264
            atts = getAttributesUsingMainMetadata(_r);
1265

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

    
1277
        // -------------------------------
1278
        singleCachedFeature = ife;
1279
        singleCachedFeatureRowNum = rowIndex;
1280

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

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

    
1296
    public Rectangle2D getFullExtent() {
1297
            return full_Extent;
1298
    }
1299

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

    
1312
        if (theStruct == null) {
1313
            return nullGeom;
1314
        }
1315

    
1316
        if (use_gtools) { // geotools
1317
//            _igeom = getGeotoolsIGeometry(theStruct);
1318
        }
1319
        else { // jgeometry
1320
            _igeom = getFMapGeometry(theStruct, false);
1321
        }
1322

    
1323
        return _igeom;
1324
    }
1325

    
1326
    private IGeometry getFMapGeometry(JGeometry jg, boolean force_not_collection) {
1327
        int jgtype = jg.getType();
1328
        int dim = jg.getDimensions();
1329
        IGeometry ig = null;
1330

    
1331
        if ((jgtype != JGeometry.GTYPE_COLLECTION) &&
1332
                (isActuallyACollection(jg))) {
1333
            jgtype = JGeometry.GTYPE_COLLECTION;
1334
        }
1335

    
1336
        switch (jgtype) {
1337
        case JGeometry.GTYPE_COLLECTION:
1338

    
1339
            int srid = jg.getSRID();
1340
            ig = getFMapGeometryCollection(jg, dim, srid);
1341

    
1342
            break;
1343

    
1344
        case JGeometry.GTYPE_POINT:
1345
        case JGeometry.GTYPE_MULTIPOINT:
1346
            ig = getFMapGeometryPoint(jg, dim);
1347

    
1348
            break;
1349

    
1350
        case JGeometry.GTYPE_CURVE:
1351
        case JGeometry.GTYPE_MULTICURVE:
1352
            ig = getFMapGeometryMultiLineString(jg, dim);
1353

    
1354
            break;
1355

    
1356
        case JGeometry.GTYPE_POLYGON:
1357
        case JGeometry.GTYPE_MULTIPOLYGON:
1358
            ig = getFMapGeometryMultipolygon(jg, dim);
1359

    
1360
            break;
1361
        }
1362

    
1363
        return ig;
1364
    }
1365

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

    
1372
        Datum[] all_info_array = null;
1373
        Object[] elems_info_aray = null;
1374
        Datum[] all_ords = null;
1375

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

    
1385
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1386
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1387

    
1388
        for (int i = 0; i < elems_info_aray.length; i++) {
1389
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1390
        }
1391

    
1392
        // _elems_info_aray, ords_of_groups
1393
        int no_of_elems = ords_of_groups.length;
1394
        IGeometry[] geoms = new IGeometry[no_of_elems];
1395

    
1396
        for (int i = 0; i < no_of_elems; i++) {
1397
            Datum[] item_info_array = null;
1398
            Datum[] item_ords = null;
1399
            NUMBER gtype = null;
1400

    
1401
            try {
1402
                item_info_array = (Datum[]) _elems_info_aray[i];
1403
                item_ords = (Datum[]) ords_of_groups[i];
1404

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

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

    
1417
            STRUCT itemst = null;
1418

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

    
1428
            geoms[i] = getFMapGeometry(itemst, true);
1429
        }
1430

    
1431
        return new FGeometryCollection(geoms);
1432
    }
1433

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

    
1444
        try {
1445
            the_data = st.getOracleAttributes();
1446

    
1447
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1448
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1449

    
1450
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1451

    
1452
            if (dim < 2) {
1453
                dim = 2;
1454
            }
1455

    
1456
            IGeometry ig = null;
1457

    
1458
            if (isActuallyACollection(the_data)) {
1459
                jgtype = FShape.MULTI;
1460
            }
1461

    
1462
            switch (jgtype) {
1463
            case FShape.MULTI:
1464

    
1465
                int srid = ((NUMBER) the_data[1]).intValue();
1466
                ig = getFMapGeometryCollection(the_data, dim, srid);
1467

    
1468
                break;
1469

    
1470
            case FShape.POINT:
1471
                ig = getFMapGeometryPoint(the_data, dim);
1472

    
1473
                break;
1474

    
1475
            case FShape.LINE:
1476
                ig = getFMapGeometryMultiLineString(the_data, dim);
1477

    
1478
                break;
1479

    
1480
            case FShape.POLYGON:
1481
                ig = getFMapGeometryMultipolygon(the_data, dim);
1482

    
1483
                break;
1484
            }
1485

    
1486
            return ig;
1487
        }
1488
        catch (SQLException e) {
1489
            logger.error(e);
1490
        }
1491

    
1492
        return null;
1493
    }
1494

    
1495
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1496
        int size = input.length / n;
1497
        double[] resp = new double[size];
1498

    
1499
        for (int i = 0; i < size; i++) {
1500
            resp[i] = input[(i * n) + ind];
1501
        }
1502

    
1503
        return resp;
1504
    }
1505

    
1506
    private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1507
        int size = input.length / n;
1508
        double[] resp = new double[size];
1509

    
1510
        for (int i = 0; i < size; i++) {
1511
            resp[i] = input[(i * n) + ind];
1512
        }
1513

    
1514
        return resp;
1515
    }
1516

    
1517
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1518
        IGeometry ig = null;
1519

    
1520
        if (jg.isCircle()) {
1521
            ig = getCircleFromJGeometry(jg);
1522
        }
1523
        else {
1524
            Shape shape = jg.createShape();
1525
            GeneralPathX gpx = new GeneralPathX(shape);
1526

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

    
1536
        return ig;
1537
    }
1538

    
1539
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1540
        IGeometry ig = null;
1541

    
1542
        if (OracleSpatialUtils.isCircle(the_data)) {
1543
            ig = getCircleFromStruct(the_data);
1544
        }
1545
        else {
1546
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1547

    
1548
            if (dim == 2) {
1549
                ig = ShapeFactory.createPolygon2D(gpx);
1550
            }
1551
            else {
1552
                double[] ords = null;
1553

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

    
1562
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1563
                ig = ShapeFactory.createPolygon3D(gpx, z);
1564
            }
1565
        }
1566

    
1567
        return ig;
1568
    }
1569

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

    
1577
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1578

    
1579
        Point2D cent = (Point2D) cent_rad[0];
1580
        double radius = ((Double) cent_rad[1]).doubleValue();
1581

    
1582
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1583

    
1584
        return circ;
1585
    }
1586

    
1587
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1588
        double[] threep = null;
1589

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

    
1597
            return new FNullGeometry();
1598
        }
1599

    
1600
        Point2D[] three = new Point2D.Double[3];
1601
        three[0] = new Point2D.Double(threep[0], threep[1]);
1602
        three[1] = new Point2D.Double(threep[2], threep[3]);
1603
        three[2] = new Point2D.Double(threep[4], threep[5]);
1604

    
1605
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1606

    
1607
        Point2D cent = (Point2D) cent_rad[0];
1608
        double radius = ((Double) cent_rad[1]).doubleValue();
1609

    
1610
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1611

    
1612
        return circ;
1613
    }
1614

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

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

    
1628
        return ig;
1629
    }
1630

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

    
1636
        if (dim == 2) {
1637
            ig = ShapeFactory.createPolyline2D(gpx);
1638
        }
1639
        else {
1640
            ords = OracleSpatialUtils.getOrds(the_data);
1641

    
1642
            double[] z = getIndBigDecimalModule(ords, 2, dim);
1643
            ig = ShapeFactory.createPolyline3D(gpx, z);
1644
        }
1645

    
1646
        return ig;
1647
    }
1648

    
1649
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1650
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1651

    
1652
            return getFMapGeometrySdoPoint(jg_point, dim);
1653
        }
1654

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

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

    
1666
            if (dim >= 3) {
1667
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1668
            }
1669
        }
1670

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

    
1688
        return ig;
1689
    }
1690

    
1691
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1692
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1693

    
1694
        if (ords == null) { // sdo_point
1695

    
1696
            return getFMapGeometrySdoPoint(the_data, dim);
1697
        }
1698

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

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

    
1710
            if (dim >= 3) {
1711
                z[i] = ords[(i * dim) + 2];
1712
            }
1713
        }
1714

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

    
1732
        return ig;
1733
    }
1734

    
1735
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1736
        double[] p = jgp.getPoint();
1737
        IGeometry ig = null;
1738

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

    
1746
        return ig;
1747
    }
1748

    
1749
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1750
        double x = 0;
1751
        double y = 0;
1752
        double z = 0;
1753

    
1754
        try {
1755
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1756
            x = ((NUMBER) aux[0]).doubleValue();
1757
            y = ((NUMBER) aux[1]).doubleValue();
1758

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

    
1768
        IGeometry ig = null;
1769

    
1770
        if (d == 2) {
1771
            ig = ShapeFactory.createPoint2D(x, y);
1772
        }
1773
        else {
1774
            ig = ShapeFactory.createPoint3D(x, y, z);
1775
        }
1776

    
1777
        return ig;
1778
    }
1779

    
1780
    private boolean isActuallyACollection(JGeometry jg) {
1781
        int[] info = jg.getElemInfo();
1782

    
1783
        if (info == null) {
1784
            return false; // sdo_point
1785
        }
1786

    
1787
        int size = info.length / 3;
1788

    
1789
        if (size == 1) {
1790
            return false;
1791
        }
1792

    
1793
        if (size == 2) {
1794
            return ((info[1] % 1000) != (info[4] % 1000));
1795
        }
1796

    
1797
        int second = info[4] % 1000;
1798

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

    
1805
        return false;
1806
    }
1807

    
1808
    private boolean isActuallyACollection(Datum[] the_data) {
1809
        int[] info = null;
1810

    
1811
        try {
1812
            ARRAY aux = (ARRAY) the_data[3];
1813

    
1814
            if (aux == null) {
1815
                return false;
1816
            }
1817

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

    
1823
            return false;
1824
        }
1825

    
1826
        if (info == null) {
1827
            return false; // sdo_point
1828
        }
1829

    
1830
        int size = info.length / 3;
1831

    
1832
        if (size == 1) {
1833
            return false;
1834
        }
1835

    
1836
        if (size == 2) {
1837
            return ((info[1] % 1000) != (info[4] % 1000));
1838
        }
1839

    
1840
        int second = info[4] % 1000;
1841

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

    
1848
        return false;
1849
    }
1850

    
1851
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1852
        int main_type = jg.getType();
1853

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

    
1860
        for (int i = 0; i < elems_info_aray.length; i++) {
1861
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1862
        }
1863

    
1864
        // _elems_info_aray, ords_of_groups
1865
        int no_of_elems = ords_of_groups.length;
1866
        IGeometry[] geoms = new IGeometry[no_of_elems];
1867

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

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

    
1878
            JGeometry itemjg = null;
1879

    
1880
            if (tableHasSrid) {
1881
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1882
            }
1883
            else {
1884
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1885
            }
1886

    
1887
            geoms[i] = getFMapGeometry(itemjg, true);
1888
        }
1889

    
1890
        return new FGeometryCollection(geoms);
1891
    }
1892

    
1893
    private Datum[] updateIndexes(Datum[] info) {
1894
        int size = info.length / 3;
1895
        NUMBER[] resp = new NUMBER[3 * size];
1896

    
1897
        try {
1898
            int rest = info[0].intValue() - 1;
1899

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

    
1910
        return resp;
1911
    }
1912

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

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

    
1924
        return resp;
1925
    }
1926

    
1927
    private int[] appendIntArrays(int[] head, int[] tail) {
1928
        int[] resp = new int[head.length + tail.length];
1929
        int hsize = head.length;
1930

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

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

    
1939
        return resp;
1940
    }
1941

    
1942
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
1943
        Datum[] resp = new Datum[head.length + tail.length];
1944
        int hsize = head.length;
1945

    
1946
        for (int i = 0; i < hsize; i++) {
1947
            resp[i] = head[i];
1948
        }
1949

    
1950
        for (int i = 0; i < tail.length; i++) {
1951
            resp[hsize + i] = tail[i];
1952
        }
1953

    
1954
        return resp;
1955
    }
1956

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

    
1963
        return resp;
1964
    }
1965

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

    
1972
        return resp;
1973
    }
1974

    
1975
    private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
1976
        Datum[] resp = new Datum[last_inc - first_inc + 1];
1977

    
1978
        for (int i = first_inc; i <= last_inc; i++) {
1979
            resp[i - first_inc] = all[i];
1980
        }
1981

    
1982
        return resp;
1983
    }
1984

    
1985
    private double[] getSubSet(double[] all, int first_inc, int last_inc) {
1986
        double[] resp = new double[last_inc - first_inc + 1];
1987

    
1988
        for (int i = first_inc; i <= last_inc; i++) {
1989
            resp[i - first_inc] = all[i];
1990
        }
1991

    
1992
        return resp;
1993
    }
1994

    
1995
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) {
1996
        Object[] resp = new Object[groups.length];
1997

    
1998
        if (resp.length == 1) {
1999
            resp[0] = all;
2000

    
2001
            return resp;
2002
        }
2003

    
2004
        int ind = 0;
2005
        int[] aux = (int[]) groups[1];
2006
        int _end = aux[0] - 2;
2007
        Datum[] ord_aux = getSubSet(all, 0, _end);
2008

    
2009
        int _start = _end + 1;
2010
        resp[ind] = ord_aux;
2011
        ind++;
2012

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

    
2022
        // last
2023
        _end = all.length - 1;
2024
        ord_aux = getSubSet(all, _start, _end);
2025
        resp[groups.length - 1] = ord_aux;
2026

    
2027
        return resp;
2028
    }
2029

    
2030
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2031
        Object[] resp = new Object[groups.length];
2032

    
2033
        if (resp.length == 1) {
2034
            resp[0] = all;
2035

    
2036
            return resp;
2037
        }
2038

    
2039
        int ind = 0;
2040
        int[] aux = (int[]) groups[1];
2041
        int _end = aux[0] - 2;
2042
        double[] ord_aux = getSubSet(all, 0, _end);
2043

    
2044
        int _start = _end + 1;
2045
        resp[ind] = ord_aux;
2046
        ind++;
2047

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

    
2057
        // last
2058
        _end = all.length - 1;
2059
        ord_aux = getSubSet(all, _start, _end);
2060
        resp[groups.length - 1] = ord_aux;
2061

    
2062
        return resp;
2063
    }
2064

    
2065
    private Object[] groupByElement(int[] all_elem) {
2066
        ArrayList resp = new ArrayList();
2067

    
2068
        int size = all_elem.length / 3;
2069

    
2070
        int[] aux = getNthGroupOfThree(all_elem, 0);
2071

    
2072
        int[] newaux;
2073
        int i = 1;
2074

    
2075
        while (i < size) {
2076
            newaux = getNthGroupOfThree(all_elem, i);
2077

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

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

    
2099
            i++;
2100
        }
2101

    
2102
        resp.add(aux);
2103

    
2104
        return resp.toArray();
2105
    }
2106

    
2107
    private Object[] groupByElement(Datum[] all_elem) {
2108
        ArrayList resp = new ArrayList();
2109

    
2110
        int size = all_elem.length / 3;
2111

    
2112
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2113

    
2114
        Datum[] newaux;
2115
        int i = 1;
2116

    
2117
        try {
2118
            while (i < size) {
2119
                newaux = getNthGroupOfThree(all_elem, i);
2120

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

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

    
2142
                i++;
2143
            }
2144
        }
2145
        catch (SQLException se) {
2146
            logger.error("Unexpected error: " + se.getMessage());
2147
        }
2148

    
2149
        resp.add(aux);
2150

    
2151
        return resp.toArray();
2152
    }
2153

    
2154
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2155
        Point2D p = _jgeom.getJavaPoint();
2156
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2157

    
2158
        return ig;
2159
    }
2160

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

    
2167
        for (int i = 0; i < l; i++) {
2168
            x[i] = pp[i].getX();
2169
            y[i] = pp[i].getY();
2170
        }
2171

    
2172
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2173

    
2174
        return ig;
2175
    }
2176

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

    
2183
        switch (type) {
2184
        case FShape.LINE:
2185

    
2186
            FPolyline2D fpl = new FPolyline2D(gpx);
2187
            ig = ShapeFactory.createPolyline2D(gpx);
2188

    
2189
            break;
2190

    
2191
        case FShape.POLYGON:
2192

    
2193
            FPolygon2D fpg = new FPolygon2D(gpx);
2194
            ig = ShapeFactory.createPolygon2D(gpx);
2195

    
2196
            break;
2197
        }
2198

    
2199
        return ig;
2200
    }
2201

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

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

    
2249
        case JGeometry.GTYPE_CURVE:
2250
        case JGeometry.GTYPE_MULTICURVE:
2251
            return FShape.LINE;
2252
        }
2253

    
2254
        System.err.println("Unhandled Oracle Spatial geometry type: " + type +
2255
            " (conversion returned FShape.NULL)");
2256

    
2257
        return FShape.NULL;
2258
    }
2259

    
2260
    private void cleanWhereClause() {
2261
        emptyWhereClause = false;
2262

    
2263
        String aux = getWhereClauseWithoutWhere();
2264

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

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

    
2291
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2292
        String resp = "";
2293

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

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

    
2318
    public void setWorkingArea(Rectangle2D rect) {
2319
    }
2320

    
2321
    private void setWAStructt() {
2322
    }
2323

    
2324
    private Geometry shapeToGeometry(Shape shp) {
2325
        if (shp == null) {
2326
            return null;
2327
        }
2328

    
2329
        int type = FShape.POLYGON;
2330

    
2331
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2332
            type = FShape.LINE;
2333
        }
2334

    
2335
        if (shp instanceof FPoint2D) {
2336
            type = FShape.POINT;
2337
        }
2338

    
2339
        if (shp instanceof FMultiPoint2D) {
2340
            type = FShape.MULTIPOINT;
2341
        }
2342

    
2343
        GeneralPathX wagp = new GeneralPathX(shp);
2344
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2345

    
2346
        return FConverter.java2d_to_jts(fwagp);
2347
    }
2348

    
2349
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2350
        Shape shape = _jg.createShape();
2351

    
2352
        return shape.getBounds2D();
2353
    }
2354

    
2355
    private void printStruct(STRUCT st) {
2356
        System.out.println("----------------------------------------------");
2357

    
2358
        try {
2359
            Object[] att = st.getAttributes();
2360
            int l = att.length;
2361

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

    
2371
        System.out.println("----------------------------------------------");
2372
    }
2373

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

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

    
2384
        STRUCT resp = null;
2385

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

    
2393
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2394
            new_obj[0] = new NUMBER(2003);
2395

    
2396
            if (hasSrid) {
2397
                new_obj[1] = new NUMBER(_oracleSRID);
2398
            }
2399
            else {
2400
                new_obj[1] = null;
2401
            }
2402

    
2403
            new_obj[2] = null;
2404

    
2405
            NUMBER[] elem_info = new NUMBER[3];
2406
            elem_info[0] = new NUMBER(1);
2407
            elem_info[1] = new NUMBER(1003);
2408
            elem_info[2] = new NUMBER(3);
2409
            new_obj[3] = elem_info;
2410

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

    
2419
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2420
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2421
                    __conn);
2422

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

    
2430
        return resp;
2431
    }
2432

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

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

    
2447
        System.err.println("main sel = " + main_sel);
2448

    
2449
        ResultSet _rs = null;
2450
        Statement _stmnt = null;
2451
        Object[] _resp = new Object[2];
2452

    
2453
        try {
2454
            _stmnt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
2455
                    ResultSet.CONCUR_READ_ONLY);
2456
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2457
            _stmnt.setFetchSize(FETCH_SIZE);
2458

    
2459
            _rs = _stmnt.executeQuery(main_sel);
2460

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

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

    
2473
        return _resp;
2474
    }
2475

    
2476
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2477
        String resp = "";
2478

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

    
2484
            for (int i = 0; i < vertices.length; i++) {
2485
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2486
                    vertices[i].doubleValue() + ", ";
2487
            }
2488

    
2489
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2490
                    mdsys_sdo_ordinate_array.length() - 2);
2491
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2492
                mdsys_sdo_ordinate_array + ")";
2493

    
2494
            String aux = "";
2495

    
2496
            if (hasSrid) {
2497
                aux = oracleSRID;
2498

    
2499
                if (_isGeogCS) {
2500
                    aux = "0";
2501
                }
2502
            }
2503
            else {
2504
                aux = "null";
2505
            }
2506

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

    
2516
        return resp;
2517
    }
2518
    
2519
    private String getIdsQueryWhereClause(boolean with_where) {
2520
                String resp = "";
2521
                
2522
                String _where = "";
2523
                if (with_where) _where = " where ";
2524

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

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

    
2546
                // resp = resp + " order by rowid";
2547
                return resp;
2548
        }
2549

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

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

    
2570
    public int getShapeType() {
2571
        return shapeType;
2572
    }
2573

    
2574
    private String getWhereClauseWithoutWhere() {
2575
        String resp = "";
2576
        String old = getLyrDef().getWhereClause();
2577
        resp = old;
2578

    
2579
        if (old.length() <= 6) {
2580
            return old;
2581
        }
2582

    
2583
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2584
            resp = resp.substring(6, resp.length());
2585
        }
2586

    
2587
        return resp;
2588
    }
2589

    
2590
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2591
        if (r1.getMaxX() <= r2.getMinX()) {
2592
            return null;
2593
        }
2594

    
2595
        if (r2.getMaxX() <= r1.getMinX()) {
2596
            return null;
2597
        }
2598

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

    
2603
        if (r2.getMaxY() <= r1.getMinY()) {
2604
            return null;
2605
        }
2606

    
2607
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2608
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2609
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2610
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2611

    
2612
        double w = maxx - minx;
2613
        double h = maxy - miny;
2614

    
2615
        return new Rectangle2D.Double(minx, miny, w, h);
2616
    }
2617

    
2618
    private static int maxSizeForFieldType(int _type) {
2619
        switch (_type) {
2620
        case Types.VARCHAR:
2621
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2622

    
2623
        case Types.LONGVARCHAR:
2624
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2625
        }
2626

    
2627
        return -1;
2628
    }
2629

    
2630
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2631
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2632

    
2633
        switch (fieldDesc.getFieldType()) {
2634
        case Types.SMALLINT:
2635
            aux = "NUMBER(5, 0)";
2636

    
2637
            break;
2638

    
2639
        case Types.INTEGER:
2640
            aux = "NUMBER(10, 0)";
2641

    
2642
            break;
2643

    
2644
        case Types.BIGINT:
2645
            aux = "NUMBER(38, 0)";
2646

    
2647
            break;
2648

    
2649
        case Types.BOOLEAN:
2650
            aux = "NUMBER(1, 0)";
2651

    
2652
            break;
2653

    
2654
        case Types.DECIMAL:
2655
            aux = "NUMBER";
2656

    
2657
            break;
2658

    
2659
        case Types.NUMERIC:
2660
            aux = "NUMBER";
2661

    
2662
            break;
2663

    
2664
        case Types.DOUBLE:
2665
            aux = "FLOAT";
2666

    
2667
            break;
2668

    
2669
        case Types.FLOAT:
2670
            aux = "FLOAT";
2671

    
2672
            break;
2673

    
2674
        case Types.CHAR:
2675
            aux = "CHAR(1 BYTE)";
2676

    
2677
            break;
2678

    
2679
        case Types.VARCHAR:
2680
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2681

    
2682
            break;
2683

    
2684
        case Types.LONGVARCHAR:
2685
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2686

    
2687
            break;
2688
        }
2689

    
2690
        return aux;
2691
    }
2692

    
2693
    // -----------------------------------------------------------
2694
    // -----------------------------------------------------------
2695
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2696
        return "DROP TABLE " + dbLayerDef.getTableName() +
2697
        " CASCADE CONSTRAINTS";
2698
    }
2699

    
2700
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2701
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2702

    
2703
        String type = "";
2704
        String name = "";
2705

    
2706
        String resp = "CREATE TABLE " + dbLayerDef.getTableName() + " ( ";
2707

    
2708
        for (int i = 0; i < flds.length; i++) {
2709
            name = flds[i].getFieldName();
2710

    
2711
            // -------------- FORBIDDEN FIELD NAMES -----------------
2712
            if (!isOracleAllowedFieldname(name)) {
2713
                continue;
2714
            }
2715

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

    
2727
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2728
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2729
        resp = resp + ", ";
2730

    
2731
        String pk = "CONSTRAINT " + getDerivedNAme(dbLayerDef.getTableName(), "PK") +
2732
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD +
2733
            "\") ENABLE";
2734

    
2735
        resp = resp + pk + " )";
2736

    
2737
        return resp;
2738
    }
2739
    
2740
    private static String getDerivedNAme(String tname, String suffix) {
2741
            
2742
            int ind = tname.lastIndexOf("."); 
2743
            if (ind == -1) {
2744
                    
2745
                    int l = Math.min(28, tname.length());
2746
                    return tname.substring(0, l) + "_" + suffix;
2747

    
2748
            } else {
2749
                    
2750
                    String pre = tname.substring(0, ind);
2751
                    String post = tname.substring(ind + 1, tname.length());
2752
                    int lpost = Math.min(24, post.length());
2753
                    int lpre = Math.min(3, pre.length());
2754
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
2755
            }
2756
            
2757
    }
2758

    
2759
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2760
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
2761
            " ON " + dbLayerDef.getTableName() + " (\"" +
2762
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
2763
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2764

    
2765
        return resp;
2766
    }
2767

    
2768
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2769
            
2770
            String tname = dbLayerDef.getTableName();
2771
            int ind = tname.lastIndexOf(".");
2772
            if (ind != -1) {
2773
                    String schema = tname.substring(0, ind);
2774
                    tname = tname.substring(ind + 1, tname.length());
2775
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2776
            " WHERE TABLE_NAME = '" + tname + "' AND OWNER = '" + schema + "'";
2777
                     
2778
            } else{
2779
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2780
            " WHERE TABLE_NAME = '" + tname + "'";
2781
            }
2782
    }
2783

    
2784
    /**
2785
     * UTility method to get the SQL sentence needed to update the geographic metadata table
2786
     * with a new bounding box and SRS
2787
     *
2788
     * @param tName table name
2789
     * @param ora_srid new SRS
2790
     * @param bbox new bounding box
2791
     * @param dim geometries dimension
2792
     * @param withsrid False if the SRS is set to NULL. True otherwise.
2793
     * @return the SQL sentence to perform the update
2794
     */
2795
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
2796
        Rectangle2D bbox, int dim, boolean withsrid) {
2797
        String[] dim_name = new String[dim];
2798
        double tolerance = 0.5;
2799

    
2800
        if (ora_srid.compareTo(GEODETIC_SRID) == 0) {
2801
            dim_name[0] = "LONGITUDE";
2802
            dim_name[1] = "LATITUDE";
2803
        }
2804
        else {
2805
            dim_name[0] = "X";
2806
            dim_name[1] = "Y";
2807

    
2808
            if (dim > 2) {
2809
                dim_name[2] = "Z";
2810

    
2811
                if (dim > 3) {
2812
                    dim_name[3] = "T";
2813
                }
2814
            }
2815
        }
2816

    
2817
        String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " " +
2818
            " ( OWNER, TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
2819
            + "'" + schema + "', "
2820
            + "'" + tName + "', "
2821
            + "'" + DEFAULT_GEO_FIELD + "', " +
2822
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2823
            bbox.getMinX() + ", " + bbox.getMaxX() + ", " + tolerance + " ), " +
2824
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + bbox.getMinY() + ", " +
2825
            bbox.getMaxY() + ", " + tolerance + " ))";
2826

    
2827
        if (dim > 2) {
2828
            resp = resp.substring(0, resp.length() - 1) + ",";
2829
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
2830
                "', 0.0, 100.0, " + tolerance + " ))";
2831

    
2832
            if (dim > 3) {
2833
                resp = resp.substring(0, resp.length() - 1) + ",";
2834
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
2835
                    "', 0.0, 100.0, " + tolerance + " ))";
2836
            }
2837
        }
2838

    
2839
        if (withsrid) {
2840
            resp = resp + ", " + ora_srid + " )";
2841
        }
2842
        else {
2843
            resp = resp + ", NULL )";
2844
        }
2845

    
2846
        return resp;
2847
    }
2848

    
2849
    /**
2850
     * Gets the SQL sentence to perform an insertion.
2851
     *
2852
     * @param feat feature to be added
2853
     * @param dbLayerDef layer definition
2854
     * @param rowInd row index
2855
     * @param _geoColName geometry field name
2856
     * @return the SQL sentence to perform the insertion
2857
     */
2858
    public static String getRowInsertSql(IFeature feat,
2859
        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2860
        String name = "";
2861
        int ftype = -1;
2862
        String aux_orig = "";
2863
        String aux_limited = "";
2864
        String aux_quotes_ok = "";
2865

    
2866
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2867

    
2868
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
2869

    
2870
        for (int i = 0; i < fieldsDescr.length; i++) {
2871
            name = fieldsDescr[i].getFieldName();
2872
            ftype = fieldsDescr[i].getFieldType();
2873

    
2874
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2875
            if (!isOracleAllowedFieldname(name)) continue;
2876
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2877
            // ------------------------------------------------------
2878
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2879
            }
2880
            else {
2881
                name = getValidOracleID(name, i);
2882
                resp = resp + "\"" + name + "\"" + " , ";
2883
            }
2884
        }
2885

    
2886
        resp = resp + _geoColName + " ) VALUES ( ";
2887

    
2888
        for (int i = 0; i < fieldsDescr.length; i++) {
2889
            name = fieldsDescr[i].getFieldName();
2890
            ftype = fieldsDescr[i].getFieldType();
2891

    
2892
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2893
            if (!isOracleAllowedFieldname(name)) continue;
2894
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2895
            // ------------------------------------------------------
2896
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2897

    
2898
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2899
            }
2900
            else {
2901
                if (name.compareToIgnoreCase(
2902
                            OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2903
                    resp = resp + rowInd + " , ";
2904
                }
2905
                else {
2906
                    Value attValue = feat.getAttribute(i);
2907

    
2908
                    if (attValue.toString() == null) {
2909
                        resp = resp + "NULL , ";
2910
                    }
2911
                    else {
2912
                        if (sur.length() > 0) {
2913
                            aux_orig = attValue.toString();
2914
                            aux_limited = cropStringValue(aux_orig, i,
2915
                                    fieldsDescr);
2916
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2917

    
2918
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2919
                        }
2920
                        else {
2921
                            String _aux = attValue.toString();
2922

    
2923
                            if (_aux.length() == 0) {
2924
                                _aux = "NULL";
2925
                            }
2926

    
2927
                            resp = resp + _aux + " , ";
2928
                        }
2929
                    }
2930
                }
2931
            }
2932
        }
2933

    
2934
        resp = resp + " ? )";
2935

    
2936
        return resp;
2937
    }
2938

    
2939
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
2940
            
2941
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
2942
                    return true;
2943
            }
2944
            
2945
            if ((ftype == Types.BINARY)
2946
                || (ftype == Types.ARRAY)
2947
                || (ftype == Types.BLOB)
2948
                || (ftype == Types.CLOB)
2949
                || (ftype == Types.STRUCT)
2950
            ) {
2951
                    return false;
2952
            }
2953
                return true;
2954
        }
2955

    
2956
        /**
2957
     * Gets the SQL sentence to perform an update.
2958
     *
2959
     * @param feat feature to be updated
2960
     * @param dbLayerDef layer definition
2961
     * @param rowInd row index
2962
     * @param geoFieldName geometry field name
2963
     * @return the SQL sentence to perform the update
2964
     */
2965
    public static String getRowUpdateSql(IFeature feat,
2966
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
2967
        String name = "";
2968
        String aux_orig = "";
2969
        String aux_limited = "";
2970
        String aux_quotes_ok = "";
2971

    
2972
        Value[] atts = feat.getAttributes();
2973
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
2974

    
2975
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
2976

    
2977
        for (int i = 0; i < _fieldsDescr.length; i++) {
2978
            name = _fieldsDescr[i].getFieldName();
2979

    
2980
            // -------------- FORBIDDEN FIELD NAMES -----------------
2981
            if (!isOracleAllowedFieldname(name)) {
2982
                logger.info("Field: " + name + " will not be updated.");
2983
                continue;
2984
            }
2985

    
2986
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
2987
                        geoFieldName)) {
2988
                logger.info("Field: " + name + " will not be updated (it's a struct).");
2989
                continue;
2990
            }
2991

    
2992
            // ------------------------------------------------------
2993
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
2994
                // resp = resp + "\"" + name + "\"" + " = ?, ";
2995
            }
2996
            else {
2997
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
2998
                aux_orig = atts[i].toString();
2999
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
3000
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
3001
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
3002
                    sur + ", ";
3003
            }
3004
        }
3005

    
3006
        resp = resp + "\"" + geoFieldName + "\" = ?";
3007
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
3008

    
3009
        return resp;
3010
    }
3011

    
3012
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
3013
        String geoname) {
3014
        if (ftype == Types.STRUCT) {
3015
            if (fldname.compareToIgnoreCase(geoname) != 0) {
3016
                return true;
3017
            }
3018
        }
3019

    
3020
        return false;
3021
    }
3022

    
3023
    /**
3024
     * Gets the SQL sentence to perform a deletion.
3025
     *
3026
     * @param dbLayerDef layer definition
3027
     * @param id ROWID of the record to be deleted
3028
     * @return the SQL sentence to perform the deletion
3029
     */
3030
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
3031
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
3032
        resp = resp + " WHERE ROWID ='" + id + "'";
3033

    
3034
        return resp;
3035
    }
3036

    
3037
    private static String cropStringValue(String orig_val, int i,
3038
        FieldDescription[] _flds) {
3039
        if (orig_val == null) {
3040
            return "NULL";
3041
        }
3042

    
3043
        int tpe = _flds[i].getFieldType();
3044
        int max_size = maxSizeForFieldType(tpe);
3045

    
3046
        if (max_size == -1) {
3047
            return orig_val;
3048
        }
3049

    
3050
        int or_size = orig_val.length();
3051

    
3052
        if (or_size <= max_size) {
3053
            return orig_val;
3054
        }
3055

    
3056
        return orig_val.substring(0, max_size);
3057
    }
3058

    
3059
    private static String avoidQuoteProblem(String str) {
3060
        return str.replaceAll("'", "''");
3061
    }
3062

    
3063
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3064
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3065
            return "";
3066
        }
3067

    
3068
        return "'";
3069
    }
3070

    
3071
    /**
3072
     * Utility function to translate a SRS code from EPSG to Oracle.
3073
     * Uses a datasource based on a DBF file.
3074
     *
3075
     * @param epsg the EPSG code
3076
     * @return the Oracle code
3077
     */
3078
    public static String epsgSridToOracleSrid(String epsg) throws Exception {
3079
        String resp = "8307";
3080

    
3081
        // --------------------------------------------
3082
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3083
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3084
        DataSource ds = null;
3085

    
3086
        try {
3087
            ds = LayerFactory.getDataSourceFactory()
3088
                             .executeSQL(sql,
3089
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3090

    
3091
            if (ds.getRowCount() == 0) {
3092
                logger.error("EPSG code not found in table: " + epsg);
3093
                throw new Exception("Unknown EPSG: " + epsg);
3094
            }
3095

    
3096
            if (ds.getRowCount() > 1) {
3097
                logger.error("===============");
3098
                logger.error(
3099
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
3100
                    epsg);
3101

    
3102
                for (int i = 0; i < ds.getRowCount(); i++) {
3103
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3104

    
3105
                    if (i == 0) {
3106
                        resp = "" + aux;
3107
                    }
3108

    
3109
                    logger.error("" + aux);
3110
                }
3111

    
3112
                logger.error("===============");
3113

    
3114
                return resp;
3115
            }
3116

    
3117
            resp = "" +
3118
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3119
        }
3120
        catch (Exception pe) {
3121
            logger.error("Error with SQL statement. " + pe.getMessage());
3122
        }
3123

    
3124
        return resp;
3125
    }
3126

    
3127
    /**
3128
     * Utility function to translate a SRS code from Oracle to EPSG.
3129
     * Uses a datasource based on a DBF file.
3130
     *
3131
     * @param ora the Oracle code
3132
     * @return the EPSG code
3133
     */
3134
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3135
        String resp = "4326";
3136

    
3137
        // --------------------------------------------
3138
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3139
            " where ORACLE = " + ora + ";";
3140
        DataSource ds = null;
3141

    
3142
        try {
3143
            ds = LayerFactory.getDataSourceFactory()
3144
                             .executeSQL(sql,
3145
                    DataSourceFactory.AUTOMATIC_OPENING);
3146

    
3147
            if (ds.getRowCount() == 0) {
3148
                logger.error("Oracle Spatial code not found in table: " + ora);
3149
                throw new Exception("Unknown Oracle code: " + ora);
3150
            }
3151

    
3152
            if (ds.getRowCount() > 1) {
3153
                logger.error("===============");
3154
                logger.error(
3155
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3156
                    ora);
3157

    
3158
                for (int i = 0; i < ds.getRowCount(); i++) {
3159
                    String aux = "" +
3160
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3161

    
3162
                    if (i == 0) {
3163
                        resp = aux;
3164
                    }
3165

    
3166
                    logger.error("" + aux);
3167
                }
3168

    
3169
                logger.error("===============");
3170

    
3171
                return resp;
3172
            }
3173

    
3174
            resp = "" +
3175
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3176
        }
3177
        catch (Exception pe) {
3178
            logger.error("Error with SQL statement. " + pe.getMessage());
3179
        }
3180

    
3181
        return resp;
3182
    }
3183

    
3184
    /**
3185
     * This methos creates the datasource used to translate the SRS codes:
3186
     * EPSG <--> Oracle.
3187
     *
3188
     * It's called from several places, so checks that the datasource does not exist.
3189
     */
3190
    public static void createOracleEpsgTable() {
3191
        SourceInfo si = LayerFactory.getDataSourceFactory()
3192
                                    .getDriverInfo(ORACLE_EPSG_TABLE_NAME);
3193

    
3194
        if (si != null) { // already created, nothing done
3195
            return;
3196
        }
3197

    
3198
        // Create 'oracle codes - epsg codes' table
3199
        DBFDriver dbfdrv = new DBFDriver();
3200

    
3201
        // dbfdrv.setDataSourceFactory()
3202
        OFileDataSourceAdapter fdsa = new OFileDataSourceAdapter();
3203

    
3204
        fdsa.setDriver(dbfdrv);
3205

    
3206
        // ---------------------------------------------
3207
        FileSourceInfo fsi = new FileSourceInfo();
3208
        fsi.file = createFileString("dbf/" + ORACLE_EPSG_FILE_NAME);
3209
        fsi.spatial = false;
3210
        fsi.name = ORACLE_EPSG_TABLE_NAME;
3211
        fsi.driverName = dbfdrv.getName(); //"DBF Driver";
3212
                                           // ---------------------------------------------
3213

    
3214
        fdsa.setSourceInfo(fsi);
3215

    
3216
        SelectableDataSource sds = null;
3217
        EditableAdapter ea = new EditableAdapter();
3218
        ProjectTable pt = null;
3219

    
3220
        try {
3221
            sds = new SelectableDataSource(fdsa);
3222
            ea.setOriginalDataSource(sds);
3223
            pt = ProjectTableFactory.createTable(ORACLE_EPSG_TABLE_NAME, ea);
3224
        }
3225
        catch (Exception ex) {
3226
            System.err.println("While creating datasource: " + ex.getMessage());
3227
        }
3228

    
3229
        sds.setSourceInfo(fsi);
3230

    
3231
        DataSourceFactory dsf = LayerFactory.getDataSourceFactory();
3232
        dsf.addFileDataSource(fsi.driverName, fsi.name, fsi.file);
3233
        sds.setDataSourceFactory(dsf);
3234
    }
3235

    
3236
    private static String createFileString(String path) {
3237
        try {
3238
            File f = new File(
3239
                    "./gvSIG/extensiones/" + EXTENSION_DIR_NAME + "/" +
3240
                    path);
3241

    
3242
            return f.getCanonicalPath();
3243
        }
3244
        catch (Exception ex) {
3245
            return "./gvSIG/extensiones/" + EXTENSION_DIR_NAME + "/" +
3246
            path;
3247
        }
3248
    }
3249

    
3250
    /**
3251
     * Utility method to get a valid Oracle identifier (in terms of length)
3252
     *
3253
     * @param str Proposed string
3254
     * @param ind field index of the given field name (used by the method to
3255
     * improve the renaming)
3256
     * @return an acceptable oracle identifier.
3257
     */
3258
    public static String getValidOracleID(String str, int ind) {
3259
        if (str.length() <= MAX_ID_LENGTH) {
3260
            return str;
3261
        }
3262

    
3263
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3264
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3265
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3266
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3267
        resp = resp + "_" + (ind % 1000);
3268

    
3269
        return resp;
3270
    }
3271

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

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

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

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

    
3290
                return resp;
3291
            }
3292

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

    
3296
                return ensureSensibleShell(cc);
3297
            }
3298

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

    
3304
            return cc;
3305
        }
3306
    }
3307

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

    
3315
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3316
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3317
                resp.add(newcoo);
3318

    
3319
                newcoo = new Coordinate((Coordinate) cc.get(0));
3320
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3321
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3322
                resp.add(newcoo);
3323

    
3324
                resp.add(cc.get(0));
3325

    
3326
                return resp;
3327
            }
3328

    
3329
            if (cc.size() == 3) {
3330
                cc.remove(1);
3331

    
3332
                return ensureSensibleHole(cc);
3333
            }
3334

    
3335
            return cc;
3336
        }
3337
        else {
3338
            cc.add(cc.get(0));
3339

    
3340
            return cc;
3341
        }
3342
    }
3343

    
3344
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
3345
        if (cc.size() == 2) {
3346
            if (sameCoordinate((Coordinate) cc.get(0),
3347
                        (Coordinate) cc.get(cc.size() - 1))) {
3348
                ArrayList resp = new ArrayList();
3349
                resp.add(cc.get(0));
3350

    
3351
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3352
                newc.x = newc.x + IRRELEVANT_DISTANCE;
3353
                resp.add(newc);
3354

    
3355
                return resp;
3356
            }
3357
        }
3358

    
3359
        return cc;
3360
    }
3361

    
3362
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3363
        if (c1.x != c2.x) {
3364
            return false;
3365
        }
3366

    
3367
        if (c1.y != c2.y) {
3368
            return false;
3369
        }
3370

    
3371
        return true;
3372
    }
3373

    
3374
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3375
        if (cc.size() == 2) {
3376
            return null;
3377
        }
3378

    
3379
        if (cc.size() == 3) {
3380
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3381
                return null;
3382
            }
3383

    
3384
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3385
                return null;
3386
            }
3387

    
3388
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3389
                return null;
3390
            }
3391

    
3392
            cc.add(cc.get(0));
3393

    
3394
            return cc;
3395
        }
3396

    
3397
        if (!sameCoordinate((Coordinate) cc.get(0),
3398
                    (Coordinate) cc.get(cc.size() - 1))) {
3399
            cc.add(cc.get(0));
3400
        }
3401

    
3402
        return cc;
3403
    }
3404

    
3405
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3406
        Coordinate[] p = new Coordinate[4];
3407
        p[0] = c;
3408

    
3409
        Coordinate nc = new Coordinate(c);
3410
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3411

    
3412
        Coordinate nc2 = new Coordinate(nc);
3413
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3414
        p[1] = nc;
3415
        p[2] = nc2;
3416
        p[3] = new Coordinate(c);
3417

    
3418
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3419
        LinearRing ls = new LinearRing(cs, geomFactory);
3420
        Polygon po = new Polygon(ls, null, geomFactory);
3421
        Polygon[] pos = new Polygon[1];
3422
        pos[0] = po;
3423

    
3424
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3425

    
3426
        return mpo;
3427
    }
3428

    
3429
    public String getSourceProjection() {
3430
        // TODO Auto-generated method stub
3431
        if (tableHasSrid) {
3432
            return epsgSRID;
3433
        }
3434

    
3435
        return destProj;
3436
    }
3437

    
3438
    public String getDestProjection() {
3439
        return destProj;
3440
    }
3441

    
3442
    public void setDestProjection(String toEPSG) {
3443
        destProj = toEPSG;
3444
        try {
3445
                        destProjOracle = epsgSridToOracleSrid(destProj);
3446
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3447
                        
3448
                } catch (Exception e) {
3449
                        logger.error("Unknown EPSG code: " + destProj);
3450
                        destProjOracle = oracleSRID;
3451
                        isDestGeogCS = false;
3452
                }
3453
        
3454
    }
3455
    
3456
    public String getDestProjectionOracleCode() {
3457
            return destProjOracle;
3458
    }
3459
    
3460
    public boolean getIsDestProjectionGeog() {
3461
            return isDestGeogCS;
3462
    }
3463
    
3464
    public String getTableProjectionOracleCode() {
3465
            return oracleSRID;
3466
    }
3467

    
3468
    public boolean canReproject(String toEPSGdestinyProjection) {
3469
        return false;
3470
    }
3471

    
3472
    /**
3473
     * Utility function. Says whether a given field name can be a user field name
3474
     * or not (for example, "ROWID" is not a valid one because it's a system
3475
     * reserved word).
3476
     *
3477
     * @param str proposed firld name
3478
     * @return whether it is valid or not for Oracle databases
3479
     */
3480
    private static boolean isOracleAllowedFieldname(String str) {
3481
        if (str.compareToIgnoreCase("rowid") == 0) {
3482
            return false;
3483
        }
3484

    
3485
        if (str.compareToIgnoreCase("rownum") == 0) {
3486
            return false;
3487
        }
3488

    
3489
        return true;
3490
    }
3491

    
3492
    public Hashtable getHashRelate() {
3493
        return hashRelate;
3494
    }
3495

    
3496
    public void setHashRelate(Hashtable m) {
3497
        hashRelate = m;
3498
    }
3499

    
3500
    public void setNumReg(int n) {
3501
        numReg = n;
3502
    }
3503

    
3504
    private int[] getRandomSample(int maxn_one_based, int n) {
3505
        int[] resp = new int[n];
3506

    
3507
        if (maxn_one_based <= n) {
3508
            resp = new int[maxn_one_based];
3509

    
3510
            for (int i = 0; i < maxn_one_based; i++) {
3511
                resp[i] = i;
3512
            }
3513
        }
3514
        else {
3515
            Random rnd = new Random();
3516

    
3517
            for (int i = 0; i < n; i++) {
3518
                resp[i] = rnd.nextInt(maxn_one_based);
3519
            }
3520
        }
3521

    
3522
        return resp;
3523
    }
3524

    
3525
    private String getRowIdRestrictionCondition(int nrecords) {
3526
        int[] zero_based_rows = getRandomSample(nrecords,
3527
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3528
        String resp = "(";
3529
        Object aux = "";
3530
        ROWID riaux = null;
3531

    
3532
        for (int i = 0; i < zero_based_rows.length; i++) {
3533
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3534
            riaux = (ROWID) aux;
3535
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3536
        }
3537

    
3538
        resp = resp.substring(0, resp.length() - 4);
3539
        resp = resp + ")";
3540

    
3541
        return resp;
3542
    }
3543

    
3544
    private Rectangle2D getBoundingFromSample(int n_max) {
3545
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3546
            " WHERE " + getRowIdRestrictionCondition(n_max);
3547
        STRUCT auxstr = null;
3548
        IGeometry theGeom = null;
3549
        Rectangle2D resp = null;
3550

    
3551
        try {
3552
            Statement st = conn.createStatement();
3553
            ResultSet rs = st.executeQuery(_qry);
3554

    
3555
            if (rs.next()) {
3556
                auxstr = (STRUCT) rs.getObject(1);
3557

    
3558
                if (auxstr != null) {
3559
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3560

    
3561
                    if (resp == null) {
3562
                        resp = theGeom.getBounds2D();
3563
                    }
3564
                    else {
3565
                        resp.add(theGeom.getBounds2D());
3566
                    }
3567
                }
3568

    
3569
                while (rs.next()) {
3570
                    auxstr = (STRUCT) rs.getObject(1);
3571

    
3572
                    if (auxstr != null) {
3573
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3574

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

    
3584
                rs.close();
3585
                st.close();
3586
            }
3587
            else {
3588
                throw new SQLException("Empty resultset from this query: " +
3589
                    _qry);
3590
            }
3591
        }
3592
        catch (SQLException se) {
3593
            System.err.println("Error while getting sample full extent: " +
3594
                se.getMessage());
3595
        }
3596

    
3597
        if (resp == null) {
3598
            logger.warn(
3599
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3600

    
3601
            return new Rectangle2D.Double(-180, -90, 360, 180);
3602
        }
3603

    
3604
        return resp;
3605
    }
3606

    
3607
    /**
3608
     * Does what it says, puts the LinearRing in counter clock wise
3609
     * order.
3610
     * @param ls The ring to set.
3611
     * @param gf a GeometryFactory object
3612
     * @return A new ring in CCW order.
3613
     *
3614
     */
3615
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3616
        Coordinate[] cc = ls.getCoordinates();
3617

    
3618
        if (CGAlgorithms.isCCW(cc)) {
3619
            return gf.createLinearRing(cc);
3620
        }
3621
        else {
3622
            if (ls instanceof LinearRing) {
3623
                return reverseRing((LinearRing) ls, gf);
3624
            }
3625
            else {
3626
                return reverseLineString(ls, gf);
3627
            }
3628
        }
3629
    }
3630

    
3631
    /**
3632
     * Does what it says, reverses the order of the Coordinates in the ring.
3633
     * @param lr The ring to reverse.
3634
     * @return A new ring with the reversed Coordinates.
3635
     *
3636
     */
3637
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3638
        int numPoints = lr.getNumPoints() - 1;
3639
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3640

    
3641
        for (int t = numPoints; t >= 0; t--) {
3642
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3643
        }
3644

    
3645
        return gf.createLinearRing(newCoords);
3646
    }
3647

    
3648
    /**
3649
     * Does what it says, reverses the order of the Coordinates in the linestring.
3650
     * @param ls The ls to reverse.
3651
     * @param gf a GeometryFactory object 
3652
     * @return A new ls with the reversed Coordinates.
3653
     *
3654
     */
3655
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3656
        int numPoints = ls.getNumPoints() - 1;
3657
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3658

    
3659
        for (int t = numPoints; t >= 0; t--) {
3660
            newCoords[t] = ls.getCoordinateN(numPoints - t);
3661
        }
3662

    
3663
        return gf.createLinearRing(newCoords);
3664
    }
3665

    
3666
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3667
        if (ge instanceof MultiPolygon) {
3668
            MultiPolygon mp = (MultiPolygon) ge;
3669
            int size = ge.getNumGeometries();
3670
            Polygon[] pols = new Polygon[size];
3671

    
3672
            for (int i = 0; i < size; i++)
3673
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3674
                        gf);
3675

    
3676
            return new MultiPolygon(pols, gf);
3677
        }
3678
        else {
3679
            if (ge instanceof Polygon) {
3680
                Polygon p = (Polygon) ge;
3681
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3682
                int nholes = p.getNumInteriorRing();
3683

    
3684
                if (nholes > 0) {
3685
                    LinearRing[] holes = new LinearRing[nholes];
3686

    
3687
                    for (int i = 0; i < nholes; i++) {
3688
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3689
                    }
3690

    
3691
                    return gf.createPolygon(exterior, holes);
3692
                }
3693
                else {
3694
                    return gf.createPolygon(exterior, null);
3695
                }
3696
            }
3697
            else {
3698
                return ge;
3699
            }
3700
        }
3701
    }
3702

    
3703
    /**
3704
     * Converts from IGeometry to STRUCT
3705
     *
3706
     * @param ig the geometry to convert
3707
     * @param _forced_type forced type to use
3708
     * @param _conn connection
3709
     * @param _o_srid  SRS (oracle code)
3710
     * @param withSrid whether this STRUCT has a non-NULL SRS
3711
     * @param agu_bien whether or not to check the correctness of the holes
3712
     * @param _isGeoCS whether the SRS is geodetic or not
3713
     * @return the generated STRUCT
3714
     */
3715
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
3716
        Connection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
3717
        boolean _isGeoCS) {
3718
        if (ig instanceof FGeometryCollection) {
3719
            FGeometryCollection coll = (FGeometryCollection) ig;
3720

    
3721
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3722
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3723

    
3724
            // logger.error("Collections no soportadas por ahora.");
3725
            // return null;
3726
        }
3727
        else {
3728
            Shape shp = ig.getInternalShape();
3729

    
3730
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3731
                agu_bien, false, _isGeoCS);
3732
        }
3733
    }
3734

    
3735
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3736
        boolean agu_bien, boolean isView) {
3737
            
3738
            if (shp == null) return null; 
3739
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3740
            agu_bien, isView, isGeogCS);
3741
    }
3742

    
3743
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3744
        Connection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3745
        boolean isView, boolean _isGeoCS) {
3746
        int _srid = -1;
3747

    
3748
        if (o_srid.length() > 0) {
3749
            _srid = Integer.parseInt(o_srid);
3750
        }
3751

    
3752
        if (shp == null) {
3753
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3754

    
3755
            return null;
3756
        }
3757

    
3758
        if (shp instanceof Rectangle2D) {
3759
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3760
                _isGeoCS, o_srid, _conn);
3761
        }
3762

    
3763
        try {
3764
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3765
                    _srid, agu_bien, hasSrid);
3766

    
3767
            return the_struct;
3768
        }
3769
        catch (SQLException ex) {
3770
            logger.error("While creating STRUCT: " + ex.getMessage());
3771

    
3772
            return null;
3773
        }
3774
    }
3775

    
3776
    // -------------------------- not ready yet ----------------
3777
    public int getRowIndexByFID(IFeature _fid) {
3778
        if (isNotAvailableYet) {
3779
            return -1;
3780
        }
3781
        else {
3782
            return super.getRowIndexByFID(_fid);
3783
        }
3784
    }
3785

    
3786
    public int getShapeCount() throws IOException {
3787
        if (isNotAvailableYet) {
3788
            return 0;
3789
        }
3790
        else {
3791
            return numReg;
3792
        }
3793
    }
3794

    
3795
    public void setNotAvailableYet(boolean nav) {
3796
        isNotAvailableYet = nav;
3797
    }
3798

    
3799
    // -------------------------------------------------------
3800
    // -------------------------------------------------------
3801
    public String[] getTableNames(Connection conn, String catalog)
3802
        throws SQLException {
3803
        DatabaseMetaData dbmd = conn.getMetaData();
3804
        String[] types = { "TABLE", "VIEW" };
3805
        // String[] types = { "VIEW" };
3806

    
3807
        ResultSet rs = null;
3808
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3809
                    ORACLE_GEOMETADATA_VIEW, types), conn);
3810
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3811
//                          ORACLE_GEOMETADATA_VIEW, types);
3812
        TreeMap ret = new TreeMap();
3813

    
3814
        while (rs.next()) {
3815
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
3816
            ret.put(nomCompleto, nomCompleto);
3817
        }
3818

    
3819
        return (String[]) ret.keySet().toArray(new String[0]);
3820
    }
3821

    
3822
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3823
        throws SQLException {
3824
        String tablename = "";
3825
        
3826
        
3827

    
3828
        if (res.next()) {
3829
            tablename = res.getString("TABLE_NAME");
3830
            
3831
            // debug 
3832
            // writeMetaTableToLog(con, tablename);
3833

    
3834
            Statement __st = con.createStatement();
3835

    
3836
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3837
                "union (select VIEW_NAME from USER_VIEWS)) " +
3838
                "intersect (select TABLE_NAME from " + tablename + ")";
3839
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
3840
            ResultSet rs = __st.executeQuery(sql);
3841

    
3842
            return rs;
3843
        }
3844
        else {
3845
            logger.error("Error while getting geometry tables.");
3846

    
3847
            return null;
3848
        }
3849
    }
3850

    
3851
    private void writeMetaTableToLog(Connection con, String tname) {
3852
            
3853
            logger.debug("======================================================");
3854
            logger.debug("=     USER_SDO_GEOM_METADATA     =====================");
3855
            logger.debug("======================================================");
3856

    
3857
            try {
3858
            Statement _stmt = con.createStatement();
3859
            String sql = "SELECT * FROM " + tname;
3860
            ResultSet res = _stmt.executeQuery(sql);
3861
            while (res.next()) {
3862
                    logger.debug("======================================================");
3863
                    logger.debug("TABLE_NAME: " + res.getString("TABLE_NAME"));
3864
                    logger.debug("COLUMN_NAME: " + res.getString("COLUMN_NAME"));
3865
                    logger.debug("SRID: " + res.getString("SRID"));
3866
                    
3867
                    ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3868
                    String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3869
                    logger.debug("DIMINFO: " + dinfo);
3870
                    logger.debug("======================================================");
3871
                    
3872
            }
3873
            } catch (Throwable th) {
3874
                    
3875
            }
3876
            
3877
            
3878
            
3879
            
3880
            
3881
                // TODO Auto-generated method stub
3882
                
3883
        }
3884

    
3885
        /**
3886
     * Gets the field names that can act as row id (always ROWID)
3887
     */
3888
    public String[] getIdFieldsCandidates(Connection conn, String table_name)
3889
        throws SQLException {
3890
            
3891
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
3892
            Statement _st = conn.createStatement();
3893
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3894
            _rs.close();
3895
            _st.close();
3896

    
3897
            String[] resp = { "ROWID" };
3898
        return resp;
3899
    }
3900

    
3901
    /**
3902
     * Gets the field names that can act as geometry fields
3903
     * (queries the user's geographic metadata).
3904
     */
3905
    public String[] getGeometryFieldsCandidates(Connection conn,
3906
        String table_name) throws SQLException {
3907
            
3908
        Statement _st = conn.createStatement();
3909
        String[] tokens = table_name.split("\\u002E", 2);
3910
        String qry;
3911
        if (tokens.length > 1)
3912
        {
3913
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3914
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" + 
3915
            tokens[1] + "'";
3916
        }
3917
        else
3918
        {
3919
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3920
            " where TABLE_NAME = " + "'" + table_name + "'";
3921

    
3922
        }
3923
        ResultSet _rs = _st.executeQuery(qry);
3924

    
3925
        ArrayList aux = new ArrayList();
3926

    
3927
        while (_rs.next()) {
3928
            String _geo = _rs.getString("COLUMN_NAME");
3929
            aux.add(_geo);
3930
        }
3931

    
3932
        _rs.close();
3933
        _st.close();
3934

    
3935
        String[] resp = (String[]) aux.toArray(new String[0]); 
3936
        
3937
        return checkIndexes(conn, resp, table_name);
3938
    }
3939

    
3940
    private String[] checkIndexes(Connection c, String[] all, String __t) throws SQLException {
3941

    
3942
            ArrayList good_ones = new ArrayList();
3943
            String t = __t;
3944
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
3945

    
3946
            for (int i=0; i<all.length; i++) {
3947
                    
3948
                String qry = "SELECT SRID, DIMINFO FROM " + ORACLE_GEOMETADATA_VIEW +
3949
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
3950
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
3951
                
3952
                Statement _st = c.createStatement();
3953
                ResultSet _rs = _st.executeQuery(qry);
3954
                if (_rs.next()) {
3955
                        String _srid = toString((BigDecimal) _rs.getObject(1));
3956
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
3957
                        int len = diminfo.getOracleArray().length;
3958
                        if (allowsGeoQueries(c, t, all[i], _srid, len)) {
3959
                                good_ones.add(all[i]);
3960
                        }
3961
                }
3962
                _rs.close();
3963
                _st.close();
3964
            }
3965
            
3966
            if (good_ones.size() == 0) {
3967
                    throw new SQLException("no_indexes_on_declared_geo_fields");
3968
            }
3969
            return (String[]) good_ones.toArray(new String[0]);
3970
    }
3971
    
3972
    private String toString(BigDecimal number) {
3973
            
3974
            if (number == null) return "NULL";
3975
            return "" + number.intValue();
3976
        }
3977

    
3978
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
3979
            String p = getPointConstructor(dims, _srid);
3980
            String qry = "SELECT * FROM " + _t.toUpperCase() + " WHERE (ROWNUM = 1)";
3981
            qry = "SELECT * FROM (" + qry + ") WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'";
3982

    
3983
            try {
3984
                        Statement _st = c.createStatement();
3985
                        ResultSet _rs = _st.executeQuery(qry);
3986
                        _rs.close();
3987
                        _st.close();
3988
                } catch (Exception ex) {
3989
                        return false;
3990
                }
3991
                return true;
3992
        }
3993

    
3994
        private String getPointConstructor(int dims, String _srid) {
3995
                
3996
                String coord = "";
3997
                for (int i=0; i<dims; i++) coord = coord + "0, ";
3998
                coord = coord.substring(0, coord.length() - 2);
3999
                
4000
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
4001
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
4002
        }
4003

    
4004
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
4005
            
4006
            if (l == null) return false;
4007
            if (str == null) return false;
4008
            
4009
            String item = "";
4010
            for (int i=0; i<l.size(); i++) {
4011
                    if (l.get(i) instanceof String) {
4012
                            item = (String) l.get(i);
4013
                            if (item.compareToIgnoreCase(str) == 0) return true;
4014
                    }
4015
            }
4016
            return false;
4017
    }
4018

    
4019
        /**
4020
     * Utility method to check if a given table is empty.
4021
     */
4022
    public boolean isEmptyTable(Connection conn, String tableName) {
4023
        boolean res = true;
4024

    
4025
        try {
4026
            Statement st = conn.createStatement();
4027
            ResultSet rs = null;
4028
            rs = st.executeQuery("select * from " + tableName +
4029
                    " where rownum = 1");
4030
            res = !rs.next();
4031
            rs.close();
4032
            st.close();
4033
        }
4034
        catch (Exception ex) {
4035
            res = true;
4036
        }
4037

    
4038
        return res;
4039
    }
4040

    
4041
    /**
4042
     * Gets all the fields from a table name.
4043
     */
4044
    public String[] getAllFields(Connection conn, String table_name)
4045
        throws SQLException {
4046
        Statement st = conn.createStatement();
4047
        ResultSet rs = st.executeQuery("select * from " + table_name +
4048
                " where rownum = 1");
4049
        ResultSetMetaData rsmd = rs.getMetaData();
4050
        String[] ret = new String[rsmd.getColumnCount()];
4051

    
4052
        for (int i = 0; i < ret.length; i++) {
4053
            ret[i] = rsmd.getColumnName(i + 1);
4054
        }
4055

    
4056
        rs.close();
4057
        st.close();
4058

    
4059
        return ret;
4060
    }
4061

    
4062
    /**
4063
     * Gets all field type names from a table.
4064
     */
4065
    public String[] getAllFieldTypeNames(Connection conn, String table_name)
4066
        throws SQLException {
4067
        Statement st = conn.createStatement();
4068
        ResultSet rs = st.executeQuery("select * from " + table_name +
4069
                " where rownum = 1");
4070
        ResultSetMetaData rsmd = rs.getMetaData();
4071
        String[] ret = new String[rsmd.getColumnCount()];
4072

    
4073
        for (int i = 0; i < ret.length; i++) {
4074
            ret[i] = rsmd.getColumnTypeName(i + 1);
4075
        }
4076

    
4077
        rs.close();
4078
        st.close();
4079

    
4080
        close();
4081

    
4082
        return ret;
4083
    }
4084

    
4085
    /**
4086
     * Gets Oracle's specific connection string for the given parameters.
4087
     */
4088
    public String getConnectionString(String host, String port, String dbname,
4089
        String user, String pw) {
4090
        String _pw = pw;
4091

    
4092
        if (_pw == null) {
4093
            _pw = "null";
4094
        }
4095

    
4096
        String fullstr = CONN_STR_BEGIN;
4097
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
4098
        fullstr = fullstr + "@" + host.toLowerCase();
4099
        fullstr = fullstr + ":" + port;
4100
        fullstr = fullstr + ":" + dbname.toLowerCase();
4101

    
4102
        return fullstr;
4103
    }
4104

    
4105
    /**
4106
     * Gets the Pracle geometries writer associated with this driver.
4107
     */
4108
    public IWriter getWriter() {
4109
        // on(VectorialEditableDBAdapter.java:290)
4110
        if (writer == null) {
4111
            writer = new OracleSpatialWriter(getRowCount());
4112
            writer.setDriver(this);
4113
            writer.setLyrShapeType(getShapeType());
4114
            writer.setGeoCS(isGeogCS());
4115
            writer.setGeoColName(geoColName);
4116
            writer.setSRID(oracleSRID);
4117

    
4118
            try {
4119
                writer.initialize(getLyrDef());
4120
            }
4121
            catch (EditionException e) {
4122
                logger.error("While initializing OS Writer: " + e.getMessage(),
4123
                    e);
4124
            }
4125

    
4126
            writer.setStoreWithSrid(tableHasSrid);
4127
        }
4128

    
4129
        return writer;
4130
    }
4131

    
4132
    /**
4133
     * Tells whether the SRS is geodetic or not
4134
     * @return whether the SRS is geodetic or not
4135
     */
4136
    public boolean isGeogCS() {
4137
        return isGeogCS;
4138
    }
4139

    
4140
    /**
4141
     * Adds a row id to the inner set od IDs.
4142
     * @param id
4143
     */
4144
    public void addRow(String id) {
4145
        Value aux = ValueFactory.createValue(id);
4146
        Integer intobj = new Integer(numReg);
4147
        hashRelate.put(aux, intobj);
4148
        rowToId.put(intobj, id);
4149

    
4150
        numReg++;
4151
    }
4152

    
4153
    /**
4154
     * Removes a row id to the inner set od IDs.
4155
     * @param id
4156
     */
4157
    public void deleteRow(String id) {
4158
        Value aux = ValueFactory.createValue(id);
4159
        Integer intobj = (Integer) hashRelate.get(aux);
4160
        hashRelate.remove(aux);
4161
        rowToId.remove(intobj);
4162

    
4163
        numReg--;
4164
    }
4165

    
4166
    private String getStandardSelectExpression() {
4167
        if (standardSelectExpressionFalse == null) {
4168
            standardSelectExpressionFalse = "";
4169

    
4170
            String[] flds = getLyrDef().getFieldNames();
4171
            int size = flds.length;
4172

    
4173
            for (int i = 0; i < size; i++) {
4174
                if (i > 0) {
4175
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4176
                        "c.\"" + flds[i] + "\", ";
4177
                }
4178
                else {
4179
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4180
                        flds[i] + ", ";
4181
                }
4182
            }
4183

    
4184
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4185
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4186
                    standardSelectExpressionFalse.length() - 2);
4187
        }
4188

    
4189
        return standardSelectExpressionFalse;
4190
    }
4191

    
4192
    /**
4193
     * Allows the method to decide what to do with the geometry field name
4194
     * (remove/add it from the user selected fields).
4195
     *
4196
     * @param flds
4197
     * @param geof
4198
     * @return the possibly modified field names
4199
     */
4200
    public String[] manageGeometryField(String[] flds, String geof) {
4201
        return addEndIfNotContained(flds, geof);
4202
    }
4203

    
4204
    /**
4205
     * Allows the method to decide what to do with the ID field name
4206
     * (remove/add it from the user selected fields).
4207
     *
4208
     * @param flds
4209
     * @param idf
4210
     * @return the possibly modified field names
4211
     */
4212
    public String[] manageIdField(String[] flds, String idf) {
4213
        return addStartIfNotContained(flds, idf);
4214
    }
4215

    
4216
    private String[] addEndIfNotContained(String[] arr, String item) {
4217
        if (contains(arr, item)) {
4218
            return arr;
4219
        }
4220
        else {
4221
            int size = arr.length;
4222
            String[] resp = new String[size + 1];
4223

    
4224
            for (int i = 0; i < size; i++) {
4225
                resp[i] = arr[i];
4226
            }
4227

    
4228
            resp[size] = item;
4229

    
4230
            return resp;
4231
        }
4232
    }
4233

    
4234
    private String[] addStartIfNotContained(String[] arr, String item) {
4235
        if (contains(arr, item)) {
4236
            return arr;
4237
        }
4238
        else {
4239
            int size = arr.length;
4240
            String[] resp = new String[size + 1];
4241

    
4242
            for (int i = 1; i <= size; i++) {
4243
                resp[i] = arr[i];
4244
            }
4245

    
4246
            resp[0] = item;
4247

    
4248
            return resp;
4249
        }
4250
    }
4251

    
4252
    private boolean contains(String[] arr, String item) {
4253
        for (int i = 0; i < arr.length; i++) {
4254
            if (arr[i].compareTo(item) == 0) {
4255
                return true;
4256
            }
4257
        }
4258

    
4259
        return false;
4260
    }
4261

    
4262
    /**
4263
     * This method is called when the user removes the layer from the view.
4264
     * If the IDs were being loaded, the driver will check this field and will
4265
     * let the thread 'die' quietly.
4266
     *
4267
     */
4268
    public void remove() {
4269
        cancelIDLoad = true;
4270
    }
4271
    
4272
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4273
            if (!isgeodetic) return true;
4274
            if (ext.getMinX() > -179.99) return true; 
4275
            if (ext.getMinY() > -89.99) return true; 
4276
            if (ext.getWidth() < 359.99) return true; 
4277
            if (ext.getHeight() < 179.99) return true; 
4278
            return false;
4279
    }
4280
    
4281
    private Rectangle2D getFastEstimatedGeodeticExtent(
4282
                    String tname, String gfield, Connection c, int sample_size, double enlargement) {
4283

    
4284
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4285
            Rectangle2D resp_aux = null;
4286
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4287
            ResultSet _rs = null;
4288

    
4289
            try {
4290
                        PreparedStatement _st = c.prepareStatement(qry);
4291
                        _rs = _st.executeQuery();
4292
                        while (_rs.next()) {
4293
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4294
                                IGeometry ig = getGeometryUsing(aux, false);
4295
                                
4296
                                if (ig == null) continue;
4297
                                
4298
                                if (resp_aux == null) {
4299
                                        resp_aux = ig.getBounds2D();
4300
                                } else {
4301
                                        resp_aux.add(ig.getBounds2D());
4302
                                }
4303
                                
4304
                        }
4305
                } catch (Exception ex) {
4306
                        logger.error("While getting random sample: " + ex.getMessage());
4307
                        return world;
4308
                }
4309
                
4310
                if (resp_aux == null) return world;
4311
                double w = resp_aux.getWidth();
4312
                double h = resp_aux.getHeight();
4313
                double x = resp_aux.getMinX();
4314
                double y = resp_aux.getMinY();
4315
                
4316
                // enlarge 10 times:
4317
                double newx = x - (0.5 * (enlargement - 1)) * w;
4318
                double newy = y - (0.5 * (enlargement - 1)) * w;
4319
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4320
                                enlargement * w,
4321
                                enlargement * h);
4322
                
4323
                
4324
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4325
                
4326
                logger.debug("FAST BB:");
4327
                logger.debug(" min x:" + resp_aux.getMinX());
4328
                logger.debug(" min y:" + resp_aux.getMinY());
4329
                logger.debug("     w:" + resp_aux.getWidth());
4330
                logger.debug("     h:" + resp_aux.getHeight());
4331
                return resp_aux;
4332
    }
4333
    
4334
    private Rectangle2D getEstimatedGeodeticExtent(
4335
                    String tname, String gfield, Connection c, int sample_size, double enlargement) {
4336
            
4337
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4338
            
4339
            ArrayList ids = new ArrayList();
4340
            int _rnd_index = 0;
4341
            ROWID _id = null;
4342
            Random rnd = new Random(System.currentTimeMillis());
4343
            
4344
            for (int i=0; i<sample_size; i++) {
4345
                    _rnd_index = rnd.nextInt(numReg);
4346
                    _id = (ROWID) rowToId.get(new Integer((int) _rnd_index));
4347
                    ids.add(_id.stringValue());
4348
            }
4349
            
4350
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE (";
4351
            for (int i=0; i<ids.size(); i++) {
4352
                    qry = qry + "(ROWID = '" + ((String) ids.get(i)) + "') OR "; 
4353
            }
4354
            qry = qry.substring(0, qry.length() - 4) + ")";
4355
            
4356
            Rectangle2D resp_aux = null;
4357
            ResultSet _rs = null;
4358

    
4359
            try {
4360
                        PreparedStatement _st = c.prepareStatement(qry);
4361
                        _rs = _st.executeQuery();
4362
                        while (_rs.next()) {
4363
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4364
                                IGeometry ig = getGeometryUsing(aux, false);
4365
                                
4366
                                if (ig == null) continue;
4367
                                
4368
                                if (resp_aux == null) {
4369
                                        resp_aux = ig.getBounds2D();
4370
                                } else {
4371
                                        resp_aux.add(ig.getBounds2D());
4372
                                }
4373
                                
4374
                        }
4375
                } catch (Exception ex) {
4376
                        logger.error("While getting random sample: " + ex.getMessage());
4377
                        return world;
4378
                }
4379
                
4380
                if (resp_aux == null) return world;
4381
                double w = resp_aux.getWidth();
4382
                double h = resp_aux.getHeight();
4383
                double x = resp_aux.getMinX();
4384
                double y = resp_aux.getMinY();
4385
                
4386
                // enlarge 10 times:
4387
                double newx = x - (0.5 * (enlargement - 1)) * w;
4388
                double newy = y - (0.5 * (enlargement - 1)) * w;
4389
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4390
                                enlargement * w,
4391
                                enlargement * h);
4392
                
4393
                
4394
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4395
                return resp_aux;
4396
    }
4397
    
4398
    public void setUserName(String u) {
4399
            userName = u;
4400
    }
4401
    
4402
    public String getUserName() {
4403
            return userName;
4404
    }
4405
    
4406
    
4407
    
4408
}