Statistics
| Revision:

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

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

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

    
100
import oracle.jdbc.OracleConnection;
101

    
102
// import oracle.spatial.geometry.JGeometry;
103

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

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

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

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

    
121
import java.io.File;
122
import java.io.IOException;
123
import java.math.BigDecimal;
124

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

    
134
import java.text.ParseException;
135

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

    
143

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

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

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

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

    
199
    private OracleSpatialWriter writer = null;
200

    
201
    // utility object to convert geometries.
202
//    private GeometryConverter geotools_conv;
203

    
204
    // switch variable
205
    private boolean use_geotools = false;
206
    private boolean tableHasSrid = true;
207

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

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

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

    
232
    // ----------------------------------------------
233
    private boolean cancelIDLoad = false;
234

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

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

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

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

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

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

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

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

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

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

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

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

    
305
        setLyrDef(lyrDef);
306

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

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

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

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

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

    
344
    private void getMetadata() {
345
            
346
            long id_load_start = System.currentTimeMillis();
347
        setIdRowTable();
348
        long id_load_end = System.currentTimeMillis();
349
        
350
        long delay = id_load_end - id_load_start;
351
        if (delay < ID_MIN_DELAY) {
352
                logger.info("Ids thread delayed by: " + (ID_MIN_DELAY - delay) + " ms.");
353
                try {
354
                                Thread.sleep(ID_MIN_DELAY - delay);
355
                        } catch (InterruptedException e) {
356
                                logger.error("While delaying ids thread: " + e.getMessage());
357
                        }
358
        }
359

    
360
        if (!hasRealiableExtent) {
361
                full_Extent = getEstimatedGeodeticExtent(
362
                                getTableName(), geoColName, conn, 20, 1.5);
363
        }
364

    
365

    
366
        if (cancelIDLoad) {
367
            return;
368
        }
369
    }
370

    
371
    private boolean needsCollectionLayer() {
372
        try {
373
            // SELECT DISTINCT(C.GEOM.SDO_GTYPE) FROM COMUICV C
374
            // String qry = "select distinct(c."  + geoColName + ".SDO_GTYPE) from " + getTableName() + " c";
375
            String qry = "select c." + geoColName + ".SDO_ELEM_INFO from " +
376
                getTableName() + " c";
377

    
378
            // SDO_ELEM_INFO
379
            Statement _st = conn.createStatement();
380
            ResultSet _rs = _st.executeQuery(qry);
381

    
382
            ArrayList types = new ArrayList();
383
            int aux = 0;
384

    
385
            ARRAY info_aux;
386
            int[] info_aux_int;
387
            int size;
388

    
389
            while (_rs.next()) {
390
                // aux = _rs.getInt(1);
391
                info_aux = (ARRAY) _rs.getObject(1);
392
                info_aux_int = info_aux.getIntArray();
393
                size = info_aux_int.length / 3;
394

    
395
                for (int i = 0; i < size; i++) {
396
                    aux = info_aux_int[(3 * i) + 1];
397
                }
398

    
399
                types.add(new Integer(aux % 1000));
400

    
401
                if ((aux % 1000) != 3) {
402
                    System.err.println("x");
403
                }
404
            }
405

    
406
            _rs.close();
407
            _st.close();
408

    
409
            boolean resp = hasSeveralGeometryTypes(types, false);
410

    
411
            return resp;
412
        }
413
        catch (Exception se) {
414
            System.err.println("Error while getting SDO metadata: " +
415
                se.getMessage());
416
        }
417

    
418
        return false;
419
    }
420

    
421
    private boolean hasSeveralGeometryTypes(ArrayList tt, boolean are_dims) {
422
        if (tt.size() == 0) {
423
            return false;
424
        }
425

    
426
        HashMap m = new HashMap();
427

    
428
        for (int i = 0; i < tt.size(); i++) {
429
            Integer integ = (Integer) tt.get(i);
430
            int val = integ.intValue();
431

    
432
            if ((val == 4) && (!are_dims)) {
433
                return true;
434
            }
435

    
436
            m.put("" + (val % 4), "a type");
437
        }
438

    
439
        Iterator iter = m.keySet().iterator();
440
        iter.next();
441

    
442
        return iter.hasNext();
443
    }
444

    
445
    private String getOracleSridFromCurrentRecord(ResultSet _rs)
446
        throws SQLException {
447
        Object obj = _rs.getObject("SRID");
448

    
449
        if (obj == null) {
450
            logger.warn("No SRID found for this table.");
451
            tableHasSrid = false;
452

    
453
            return ASSUMED_ORACLE_SRID;
454
        }
455

    
456
        return obj.toString();
457
    }
458

    
459
    private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
460
        throws SQLException {
461
        ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
462

    
463
        if (dim_info_array == null) {
464
            // no full extent found:
465
            return null;
466
        }
467
        else {
468
            Datum[] da = dim_info_array.getOracleArray();
469

    
470
            STRUCT sx = (STRUCT) da[0];
471
            STRUCT sy = (STRUCT) da[1];
472

    
473
            try {
474
                double minx = Double.parseDouble(sx.getAttributes()[1].toString());
475
                double maxx = Double.parseDouble(sx.getAttributes()[2].toString());
476
                double miny = Double.parseDouble(sy.getAttributes()[1].toString());
477
                double maxy = Double.parseDouble(sy.getAttributes()[2].toString());
478

    
479
                if (minx > maxx) {
480
                    double aux = minx;
481
                    minx = maxx;
482
                    maxx = aux;
483
                }
484

    
485
                if (miny > maxy) {
486
                    double aux = miny;
487
                    miny = maxy;
488
                    maxy = aux;
489
                }
490

    
491
                return getRectangle(minx, maxx, miny, maxy);
492

    
493
                // fullExtentJTS = shapeToGeometry(fullExtent);
494
            }
495
            catch (Exception ex) {
496
                System.err.println(
497
                    "Error while getting full extent from metadata table.");
498

    
499
                return null;
500

    
501
                // fullExtentJTS = null;
502
            }
503
        }
504
    }
505

    
506
    private void loadSdoMetadata() {
507
        try {
508
            Statement _st = conn.createStatement();
509
            String[] tokens = getTableName().split("\\u002E", 2);
510
            String qry;
511
            if (tokens.length > 1)
512
            {
513
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
514
                " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" + 
515
                tokens[1] + "'";
516
            }
517
            else
518
            {
519
                    qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
520
                " where TABLE_NAME = " + "'" + getTableName() + "'";
521

    
522
            }
523
//            String qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
524
//                " where TABLE_NAME = " + "'" + getTableName() + "'";
525
            ResultSet _rs = _st.executeQuery(qry);
526

    
527
            if (_rs.next()) {
528
                oracleSRID = getOracleSridFromCurrentRecord(_rs);
529

    
530
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
531

    
532
                try {
533
                                        epsgSRID = oracleSridToEpsgSrid(oracleSRID);
534
                                } catch (Exception e) {
535
                                        logger.error("Unknown oracle SRID: " + oracleSRID);
536
                                        tableHasSrid = false;
537
                                }
538
                full_Extent = getFullExtentFromCurrentRecord(_rs);
539
                
540
                hasRealiableExtent = realiableExtent(full_Extent, isGeogCS); 
541
                
542
                if (!hasRealiableExtent) {
543
                        full_Extent = getFastEstimatedGeodeticExtent(
544
                                        getTableName(), geoColName, conn, 20, 10);
545
                }
546

    
547
                _rs.close();
548
                _st.close();
549
            }
550
            else {
551
                throw new SQLException("Empty resultset from this query: " +
552
                    qry);
553
            }
554
        }
555
        catch (SQLException se) {
556
            System.err.println("Error while getting SDO metadata: " +
557
                se.getMessage());
558
        }
559
    }
560

    
561
    /**
562
     * Utility method to find out if a coordinate system is geodetic or not.
563
     *
564
     * @param oracleSRID2 the coordinate system's oracle code
565
     * @param thas whether the table has a coordinate system set.
566
     * if not, the method returns false.
567
     * @return whether the coordinate system is geodetic or not.
568
     */
569
    public static boolean getIsGCS(String oracleSRID2, boolean thas) {
570

    
571
        if (!thas) return false;
572
        int ora_cs = 0;
573

    
574
        try {
575
            ora_cs = Integer.parseInt(oracleSRID2);
576
        }
577
        catch (Exception ex) {
578
            return false;
579
        }
580

    
581
        if (((ora_cs >= 8000) && (ora_cs <= 8999)) || (ora_cs == 524288)) {
582
            return true;
583
        } else {
584
                return false;
585
        }
586
    }
587

    
588
    private Rectangle2D getRectangle(double minx, double maxx, double miny,
589
        double maxy) {
590
        Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx,
591
                maxy - miny);
592

    
593
        return resp;
594
    }
595

    
596
    private void oneRowMetadata() {
597
        try {
598
            String _sql = "select " + getStandardSelectExpression() + ", c." +
599
                geoColName + " from " + getTableName() + " c ";
600

    
601
            st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
602
                    ResultSet.CONCUR_READ_ONLY);
603

    
604
            ResultSet _rs = st.executeQuery(_sql + " where (rownum = 1)");
605

    
606
            if (_rs.next()) {
607
                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
608
                shapeType = getShapeTypeOfStruct(sample_geo);
609
            }
610
            else {
611
                shapeType = FShape.MULTI;
612
            }
613

    
614
            // -----------------------
615
            _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
616
            metaData = _rs.getMetaData();
617
            userName = conn.getMetaData().getUserName();
618
            
619

    
620
            // geoColInd = _rs.findColumn(geoColName);
621
            oneBasedGeoColInd = metaData.getColumnCount() + 1;
622

    
623
            DatabaseMetaData dbmd = conn.getMetaData();
624
            pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
625

    
626
            int cnt = metaData.getColumnCount();
627
            fieldNames = new String[cnt];
628

    
629
            for (int i = 0; i < cnt; i++) {
630
                fieldNames[i] = metaData.getColumnName(i + 1);
631
            }
632

    
633
            getIdFieldNames();
634

    
635
            adjustLyrDef();
636

    
637
            _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan 
638
        }
639
        catch (SQLException se) {
640
            logger.error("While getting metadata. " + se.getMessage());
641
        }
642
    }
643

    
644
    private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
645
        int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue() % 10;
646
        
647
        switch (code) {
648
        case 1:
649
            return FShape.POINT;
650

    
651
        case 2:
652
            return FShape.LINE;
653

    
654
        case 3:
655
            return FShape.POLYGON;
656

    
657
        case 4:
658
            return FShape.MULTI;
659

    
660
        case 5:
661
            return FShape.MULTIPOINT;
662

    
663
        case 6:
664
            return FShape.LINE;
665

    
666
        case 7:
667
            return FShape.POLYGON;
668
        }
669

    
670
        logger.error("Unknown geometry type: " + code);
671

    
672
        return FShape.NULL;
673
    }
674

    
675
    private String getIdFieldNames() {
676
        try {
677
            idFieldNames = "";
678

    
679
            for (int i = 0; i < pkOneBasedIndexes.length; i++) {
680
                idFieldNames = idFieldNames +
681
                    metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
682
            }
683
        }
684
        catch (SQLException se) {
685
        }
686

    
687
        idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
688

    
689
        return idFieldNames;
690
    }
691

    
692
    private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
693
        int[] _res = new int[1];
694
        _res[0] = 1;
695

    
696
        return _res;
697
    }
698

    
699
    public String getSqlTotal() {
700
        // TODO Auto-generated method stub
701
        return "";
702
    }
703

    
704
    public String getCompleteWhere() {
705
        // TODO Auto-generated method stub
706
        return "";
707
    }
708

    
709
    /**
710
     * Gets the feature iterator for a given SQL sentence (ignores previous filters
711
     * and uses directly that sentence to query the table).
712
     */
713
    public IFeatureIterator getFeatureIterator(String sql)
714
        throws DriverException {
715
        if (isNotAvailableYet) {
716
            return null;
717
        }
718

    
719
        singleCachedFeatureRowNum = -1;
720

    
721
        Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
722

    
723
        ResultSet localrs = (ResultSet) rs_st[0];
724
        Statement _st = (Statement) rs_st[1];
725

    
726
        return new OracleSpatialFeatureIterator(this, localrs, _st,
727
            oneBasedGeoColInd, use_geotools);
728
    }
729

    
730
    /**
731
     * Gets Oracle particular connection string beginning: "jdbc:oracle:thin:"
732
     */
733
    public String getConnectionStringBeginning() {
734
        // oracle
735
        return CONN_STR_BEGIN;
736
    }
737

    
738
    public void open() throws DriverException {
739
    }
740

    
741
    /**
742
     * Gets Oracle's default port: 1521
743
     */
744
    public int getDefaultPort() {
745
        // oracle port
746
        return 1521;
747
    }
748

    
749
    /**
750
     * Gets the feature iterator for a given rectangle (the view's bounding box)
751
     * and a SRS.
752
     */
753
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
754
        throws DriverException {
755
        if (isNotAvailableYet) {
756
            return null;
757
        } 
758

    
759
        singleCachedFeatureRowNum = -1;
760

    
761
        STRUCT local_st = shapeToStruct(r, FShape.NULL, true, false, true);
762

    
763
        Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
764

    
765
        ResultSet localrs = (ResultSet) rs_st[0];
766
        Statement _st = (Statement) rs_st[1];
767

    
768
        return new OracleSpatialFeatureIterator(this, localrs, _st,
769
            oneBasedGeoColInd, use_geotools);
770
    }
771

    
772
    private Rectangle2D intersectWithWorkingArea(Rectangle2D r) {
773
        if (workingAreaInTablesCS == null) return r;
774
        return doIntersect(r, workingAreaInTablesCS);
775
    }
776

    
777
    /**
778
     * This method reverts to the one without the fields specification.
779
     * The fields have been selected from the start.
780
     */
781
    public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
782
        String[] alphaNumericFieldsNeeded) throws DriverException {
783
        if (isNotAvailableYet) {
784
            return null;
785
        }
786

    
787
        singleCachedFeatureRowNum = -1;
788

    
789
        return getFeatureIterator(r, strEPSG);
790
    }
791

    
792
    public String getGeometryField(String fieldName) {
793
        return fieldName;
794

    
795
        // return "ASBINARY(" + fieldName + ")";
796
    }
797

    
798
    public DriverAttributes getDriverAttributes() {
799
        return drvAtts;
800
    }
801

    
802
    /**
803
     * Gets the requested geometry. Always performs a new query in this case.
804
     * This should be a rare way to get the geometries. The standard way is by using
805
     * the iterators.
806
     */
807
    public IGeometry getShape(int _ind) throws IOException {
808
        if (isNotAvailableYet) {
809
            return nullGeom;
810
        }
811

    
812
        ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
813

    
814
        String _sql = "select " + geoColName + " from " + getTableName() +
815
            " where rowid = ?";
816

    
817
        try {
818
            java.sql.PreparedStatement ps = conn.prepareStatement(_sql);
819
            ps.setObject(1, r_id);
820

    
821
            // Statement stmnt = conn.createStatement();
822
            ps.execute();
823

    
824
            ResultSet _res = ps.getResultSet();
825

    
826
            if (_res.next()) {
827
                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
828
                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
829
                _res.close();
830
                ps.close();
831

    
832
                return theGeom;
833
            }
834
            else {
835
                logger.error("Unable to get shape: " + _ind +
836
                    " (probably due to edition)");
837

    
838
                return nullGeom;
839
            }
840
        }
841
        catch (SQLException se) {
842
            throw new IOException("SQLException: " + se.getMessage());
843
        }
844
    }
845

    
846
    public boolean isWritable() {
847
        return true;
848
    }
849

    
850
    public String getName() {
851
        return NAME;
852
    }
853

    
854
    public int[] getPrimaryKeys()
855
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
856
        return pkOneBasedIndexes;
857
    }
858

    
859
    public void write(DataWare dataWare)
860
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
861
    }
862

    
863
    private void setIdRowTable() {
864
        hashRelate = new Hashtable();
865

    
866
        java.sql.PreparedStatement ps = null;
867

    
868
        try {
869
            String _sql = getIdAndElemInfoFullResulltSetQuery();
870

    
871
            logger.debug("SQL para leer ids: " + _sql);
872
            Statement st = null;
873

    
874
            
875
            st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
876
                        ResultSet.CONCUR_READ_ONLY);
877
            
878
            st.setFetchSize(FETCH_SIZE);
879
            logger.info("FETCH_SIZE = " + FETCH_SIZE);
880
            
881
            ResultSet _r = null;
882
            _r = st.executeQuery(_sql);
883

    
884
            ROWID ri = null;
885

    
886
            int row = 0;
887
            String gid;
888
            Value aux = null;
889

    
890
            // ----------------------------------- types init
891
            ArrayList types = new ArrayList();
892
            int types_aux = 0;
893

    
894
            ARRAY info_aux;
895
            int[] info_aux_int;
896
            int size;
897

    
898
            // ----------------------------------- types init
899
            logger.debug("Beginning of result set:");
900

    
901
            while (_r.next()) {
902
                // ---------------------------------------
903
                ri = (ROWID) _r.getObject(1);
904
                gid = ri.stringValue();
905
                aux = ValueFactory.createValue(gid);
906

    
907
                Integer intobj = new Integer(row);
908
                hashRelate.put(aux, intobj);
909
                rowToId.put(intobj, ri);
910

    
911
                if ((row % 5000) == 0) {
912
                    // ------------------------------------------- cancel load
913
                    if (cancelIDLoad) {
914
                        hashRelate.clear();
915
                        rowToId.clear();
916

    
917
                        return;
918
                    }
919

    
920
                    // -------------------------------------------
921
                    String fmt = OracleSpatialUtils.getFormattedInteger(row);
922
                    logger.info("IDs read: " + fmt);
923
                }
924

    
925
                row++;
926

    
927
                // --------------------------------------- types
928
                info_aux = (ARRAY) _r.getObject(2);
929

    
930
                if (info_aux == null) {
931
                    // logger.debug("NULL info array found in record: " + row);
932
                }
933
                else {
934
                    info_aux_int = info_aux.getIntArray();
935
                    size = info_aux_int.length / 3;
936

    
937
                    for (int i = 0; i < size; i++) {
938
                        types_aux = info_aux_int[(3 * i) + 1];
939
                        types.add(new Integer(types_aux % 1000));
940
                    }
941
                }
942

    
943
                // --------------------------------------- types end
944
            }
945

    
946
            _r.close();
947
//            ps.close();
948
            st.close();
949
            numReg = row;
950

    
951
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
952

    
953
            if (needsCollectionLayer) {
954
                shapeType = FShape.MULTI;
955
            }
956
        }
957
        catch (SQLException e) {
958
            System.err.println("While setting id-row hashmap: " +
959
                e.getMessage());
960
        }
961
    }
962

    
963
    public int getFieldCount()
964
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
965
        try {
966
            return metaData.getColumnCount();
967
        }
968
        catch (SQLException e) {
969
            System.err.println("While getting field count: " + e.getMessage());
970
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e.getMessage());
971
        }
972
    }
973

    
974
    public String[] getFieldNames() {
975
        return fieldNames;
976
    }
977

    
978
    public String getTotalFields() {
979
        String strAux = "";
980

    
981
        for (int i = 0; i < fieldNames.length; i++) {
982
            if (i == 0) {
983
                strAux = fieldNames[i];
984
            }
985
            else {
986
                strAux = strAux + ", " + fieldNames[i];
987
            }
988
        }
989

    
990
        return strAux;
991
    }
992

    
993
    public int getFieldType(int idField)
994
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
995
        int i = 0;
996

    
997
        try {
998
            i = idField + 1; // idField viene basado en 0
999

    
1000
            int __type = metaData.getColumnType(i);
1001

    
1002
            // we must add this entry because we did not remove the 'geometry' column
1003
            if (__type == Types.STRUCT) {
1004
                return Types.VARCHAR; // .STRUCT;
1005
                                      // ----------------------------------------------------------------------
1006
            }
1007

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1060
            if (__type == Types.TIMESTAMP) {
1061
                return Types.TIMESTAMP;
1062
            }
1063
        }
1064
        catch (SQLException e) {
1065
            System.err.println("i = " + i);
1066
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(e);
1067
        }
1068

    
1069
        return -1;
1070
    }
1071

    
1072
    public Value[] getAttributes(ResultSet rs) {
1073
        Value[] res = null;
1074

    
1075
        try {
1076
            int fcount = rs.getMetaData().getColumnCount();
1077
            res = new Value[fcount];
1078

    
1079
            for (int i = 0; i < fcount; i++) {
1080
                Object obj = rs.getObject(i + 1);
1081
                String objToString = null;
1082
                int _type = -1;
1083

    
1084
                if (obj instanceof String) {
1085
                    objToString = (String) obj;
1086
                    _type = Types.VARCHAR;
1087
                }
1088
                else {
1089
                    if (obj instanceof ROWID) {
1090
                        objToString = ((ROWID) obj).stringValue();
1091
                        _type = Types.VARCHAR;
1092
                    }
1093
                    else {
1094
                        if (obj instanceof STRUCT) {
1095
                            objToString = "STRUCT";
1096
                            _type = Types.VARCHAR;
1097
                        }
1098
                        else {
1099
                            objToString = (obj == null) ? "NULL" : obj.toString();
1100
                            _type = getFieldType(i);
1101
                        }
1102
                    }
1103
                }
1104

    
1105
                // /*
1106
                if (_type == -1) {
1107
                    obj = null;
1108
                }
1109

    
1110
                // */
1111
                if (obj == null) {
1112
                    res[i] = ValueFactory.createNullValue();
1113
                }
1114
                else {
1115
                    if (_type == Types.DATE) {
1116
                        objToString = objToString.replace('-', '/');
1117
                    }
1118

    
1119
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1120
                }
1121
            }
1122
        }
1123
        catch (SQLException se) {
1124
            System.err.println("Error while getting attributes: " +
1125
                se.getMessage());
1126

    
1127
            return null;
1128
        }
1129
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1130
            System.err.println("Error while getting attributes: " +
1131
                e.getMessage());
1132

    
1133
            return null;
1134
        }
1135
        catch (ParseException e) {
1136
            System.err.println("Error while getting attributes: " +
1137
                e.getMessage());
1138

    
1139
            return null;
1140
        }
1141

    
1142
        return res;
1143
    }
1144
    
1145
    public Value[] getAttributesUsingMainMetadata(ResultSet rs) {
1146
        Value[] res = null;
1147

    
1148
        try {
1149
            int fcount = metaData.getColumnCount();
1150
            res = new Value[fcount];
1151

    
1152
            for (int i = 0; i < fcount; i++) {
1153
                Object obj = rs.getObject(i + 1);
1154
                String objToString = null;
1155
                int _type = -1;
1156

    
1157
                if (obj instanceof String) {
1158
                    objToString = (String) obj;
1159
                    _type = Types.VARCHAR;
1160
                }
1161
                else {
1162
                    if (obj instanceof ROWID) {
1163
                        objToString = ((ROWID) obj).stringValue();
1164
                        _type = Types.VARCHAR;
1165
                    }
1166
                    else {
1167
                        if (obj instanceof STRUCT) {
1168
                            objToString = "STRUCT";
1169
                            _type = Types.VARCHAR;
1170
                        }
1171
                        else {
1172
                            objToString = (obj == null) ? "NULL" : obj.toString();
1173
                            _type = getFieldType(i);
1174
                        }
1175
                    }
1176
                }
1177

    
1178
                // /*
1179
                if (_type == -1) {
1180
                    obj = null;
1181
                }
1182

    
1183
                // */
1184
                if (obj == null) {
1185
                    res[i] = ValueFactory.createNullValue();
1186
                }
1187
                else {
1188
                    if (_type == Types.DATE) {
1189
                        objToString = objToString.replace('-', '/');
1190
                    }
1191

    
1192
                    res[i] = ValueFactory.createValueByType(objToString, _type);
1193
                }
1194
            }
1195
        }
1196
        catch (SQLException se) {
1197
            System.err.println("Error while getting attributes: " +
1198
                se.getMessage());
1199

    
1200
            return null;
1201
        }
1202
        catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
1203
            System.err.println("Error while getting attributes: " +
1204
                e.getMessage());
1205

    
1206
            return null;
1207
        }
1208
        catch (ParseException e) {
1209
            System.err.println("Error while getting attributes: " +
1210
                e.getMessage());
1211

    
1212
            return null;
1213
        }
1214

    
1215
        return res;
1216
    }
1217
    
1218

    
1219
    public String getFieldName(int fieldId)
1220
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1221
        return fieldNames[fieldId];
1222
    }
1223

    
1224
    public int getFieldWidth(int fieldId) {
1225
        int i = -1;
1226

    
1227
        try {
1228
            int aux = fieldId + 1; // fieldId viene basado en 0
1229
            i = metaData.getColumnDisplaySize(aux);
1230
        }
1231
        catch (SQLException e) {
1232
            System.err.println("While getting field width: " + e.getMessage());
1233
        }
1234

    
1235
        if (i < 0) {
1236
            i = 255;
1237
        }
1238

    
1239
        return i;
1240
    }
1241

    
1242
    public Value getFieldValue(long rowIndex, int field_Id)
1243
        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1244
        if (isNotAvailableYet) {
1245
            return nullVal;
1246
        }
1247

    
1248
        if ((singleCachedFeature != null) &&
1249
                (rowIndex == singleCachedFeatureRowNum)) {
1250
            return singleCachedFeature.getAttributes()[field_Id];
1251
        }
1252

    
1253
        // return ValueFactory.createNullValue();
1254
        ResultSet _r = null;
1255
        java.sql.PreparedStatement ps = null;
1256

    
1257
        try {
1258
            String rnq = getSearchId();
1259
            ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1260

    
1261
            ps = conn.prepareStatement(rnq);
1262
            ps.setObject(1, _id);
1263

    
1264
            ps.execute();
1265
            _r = ps.getResultSet();
1266
            _r.next();
1267
        }
1268
        catch (SQLException se) {
1269
            throw new com.hardcode.gdbms.engine.data.driver.DriverException(se.getMessage());
1270
        }
1271

    
1272
        IFeature ife = null;
1273
        Value[] atts = null;
1274

    
1275
        try {
1276
            ROWID ri = (ROWID) _r.getObject(1);
1277
            atts = getAttributesUsingMainMetadata(_r);
1278

    
1279
            String gid = ri.stringValue();
1280
            STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1281
            IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1282
            ife = new DefaultFeature(theGeom, atts, gid);
1283
            _r.close();
1284
            ps.close();
1285
        }
1286
        catch (SQLException se) {
1287
            logger.error("Error while doing next(): " + se.getMessage(), se);
1288
        }
1289

    
1290
        // -------------------------------
1291
        singleCachedFeature = ife;
1292
        singleCachedFeatureRowNum = rowIndex;
1293

    
1294
        // -------------------------------
1295
        if (atts == null) {
1296
            return ValueFactory.createNullValue();
1297
        }
1298
        else {
1299
            return atts[field_Id];
1300
        }
1301
    }
1302

    
1303
    public static void showMemory() {
1304
        Runtime r = Runtime.getRuntime();
1305
        long mem = r.totalMemory() - r.freeMemory();
1306
        System.err.println("Memoria total: " + mem);
1307
    }
1308

    
1309
    public Rectangle2D getFullExtent() {
1310
            return full_Extent;
1311
    }
1312

    
1313
    /**
1314
     * Utility method to get a geometry from a struct.
1315
     *
1316
     * @param theStruct the struct to be converted
1317
     * @param use_gtools switch to use geotools classes or not
1318
     * @return the geometry
1319
     * @throws SQLException
1320
     */
1321
    public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
1322
        throws SQLException {
1323
        IGeometry _igeom = null;
1324

    
1325
        if (theStruct == null) {
1326
            return nullGeom;
1327
        }
1328

    
1329
        if (use_gtools) { // geotools
1330
//            _igeom = getGeotoolsIGeometry(theStruct);
1331
        }
1332
        else { // jgeometry
1333
            _igeom = getFMapGeometry(theStruct, false);
1334
        }
1335

    
1336
        return _igeom;
1337
    }
1338

    
1339
    /*
1340
    private IGeometry getFMapGeometry(JGeometry jg, boolean force_not_collection) {
1341
        int jgtype = jg.getType();
1342
        int dim = jg.getDimensions();
1343
        IGeometry ig = null;
1344

1345
        if ((jgtype != JGeometry.GTYPE_COLLECTION) &&
1346
                (isActuallyACollection(jg))) {
1347
            jgtype = JGeometry.GTYPE_COLLECTION;
1348
        }
1349

1350
        switch (jgtype) {
1351
        case JGeometry.GTYPE_COLLECTION:
1352

1353
            int srid = jg.getSRID();
1354
            ig = getFMapGeometryCollection(jg, dim, srid);
1355

1356
            break;
1357

1358
        case JGeometry.GTYPE_POINT:
1359
        case JGeometry.GTYPE_MULTIPOINT:
1360
            ig = getFMapGeometryPoint(jg, dim);
1361

1362
            break;
1363

1364
        case JGeometry.GTYPE_CURVE:
1365
        case JGeometry.GTYPE_MULTICURVE:
1366
            ig = getFMapGeometryMultiLineString(jg, dim);
1367

1368
            break;
1369

1370
        case JGeometry.GTYPE_POLYGON:
1371
        case JGeometry.GTYPE_MULTIPOLYGON:
1372
            ig = getFMapGeometryMultipolygon(jg, dim);
1373

1374
            break;
1375
        }
1376

1377
        return ig;
1378
    }
1379
    */
1380

    
1381
    private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim) {
1382
        // int __srid) {
1383
            
1384
            NUMBER _srid = new NUMBER(0);
1385
        NUMBER main_type = new NUMBER((dim * 1000) +
1386
                OracleSpatialUtils.getStructType(the_data));
1387
        
1388

    
1389
        Datum[] all_info_array = null;
1390
        Object[] elems_info_aray = null;
1391
        Datum[] all_ords = null;
1392

    
1393
        Object[] ords_of_groups = null;
1394
        Object[] _elems_info_aray = null;
1395
        try {
1396
            all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1397
            elems_info_aray = groupByElement(all_info_array);
1398
            all_ords = ((ARRAY) the_data[4]).getOracleArray();
1399
            
1400
            ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1401
            _elems_info_aray = new Object[elems_info_aray.length];
1402
        }
1403
        catch (SQLException e) {
1404
            logger.error("Unexpected error: " + e.getMessage());
1405
        }
1406

    
1407

    
1408
        for (int i = 0; i < elems_info_aray.length; i++) {
1409
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1410
        }
1411

    
1412
        // _elems_info_aray, ords_of_groups
1413
        int no_of_elems = ords_of_groups.length;
1414
        IGeometry[] geoms = new IGeometry[no_of_elems];
1415

    
1416
        for (int i = 0; i < no_of_elems; i++) {
1417
            Datum[] item_info_array = null;
1418
            Datum[] item_ords = null;
1419
            NUMBER gtype = null;
1420

    
1421
            try {
1422
                item_info_array = (Datum[]) _elems_info_aray[i];
1423
                item_ords = (Datum[]) ords_of_groups[i];
1424

    
1425
                gtype = new NUMBER((dim * 1000) +
1426
                        (item_info_array[1].intValue() % 1000));
1427
                
1428
                if (tableHasSrid) {
1429
                        _srid = new NUMBER(Integer.parseInt(oracleSRID));
1430
                }
1431
            }
1432
            catch (SQLException se) {
1433
                logger.error("Unexpected error: " + se.getMessage());
1434
            }
1435

    
1436
            // if it's the first geometry, the type is the collection's main type (no?) - no
1437
            // if (i == 0) gtype = main_type;
1438
            
1439
            STRUCT itemst = null;
1440

    
1441
            if (tableHasSrid) {
1442
                    
1443
                itemst = OracleSpatialUtils.createStruct(gtype, _srid,
1444
                        item_info_array, item_ords, conn);
1445
            }
1446
            else {
1447
                itemst = OracleSpatialUtils.createStruct(gtype, null,
1448
                        item_info_array, item_ords, conn);
1449
            }
1450

    
1451
            geoms[i] = getFMapGeometry(itemst, true);
1452
        }
1453

    
1454
        return new FGeometryCollection(geoms);
1455
    }
1456

    
1457
    /**
1458
     * Utility method to transform a struct into a IGeometry.
1459
     *
1460
     * @param st the struct to be converted
1461
     * @param force_not_collection t5his parameter is currently ignored
1462
     * @return the IGeometry
1463
     */
1464
    public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1465
            
1466
            if (st == null) {
1467
                    return new FNullGeometry();
1468
            }
1469
            
1470
        Datum[] the_data = null;
1471

    
1472
        try {
1473
            the_data = st.getOracleAttributes();
1474

    
1475
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1476
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1477

    
1478
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1479

    
1480
            if (dim < 2) {
1481
                dim = 2;
1482
            }
1483

    
1484
            IGeometry ig = null;
1485

    
1486
            if (isActuallyACollection(the_data)) {
1487
                    logger.debug("isActuallyACollection(the_data) = TRUE");
1488
                jgtype = FShape.MULTI;
1489
            }
1490

    
1491
            switch (jgtype) {
1492
            case FShape.MULTI:
1493

    
1494
                // int srid = ((NUMBER) the_data[1]).intValue();
1495
                ig = getFMapGeometryCollection(the_data, dim);
1496

    
1497
                break;
1498

    
1499
            case FShape.POINT:
1500
                ig = getFMapGeometryPoint(the_data, dim);
1501

    
1502
                break;
1503

    
1504
            case FShape.LINE:
1505
                ig = getFMapGeometryMultiLineString(the_data, dim);
1506

    
1507
                break;
1508

    
1509
            case FShape.POLYGON:
1510
                ig = getFMapGeometryMultipolygon(the_data, dim);
1511

    
1512
                break;
1513
            }
1514

    
1515
            return ig;
1516
        }
1517
        catch (SQLException e) {
1518
            logger.error(e);
1519
        }
1520

    
1521
        return null;
1522
    }
1523

    
1524
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1525
        int size = input.length / n;
1526
        double[] resp = new double[size];
1527

    
1528
        for (int i = 0; i < size; i++) {
1529
            resp[i] = input[(i * n) + ind];
1530
        }
1531

    
1532
        return resp;
1533
    }
1534

    
1535
    private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1536
        int size = input.length / n;
1537
        double[] resp = new double[size];
1538

    
1539
        for (int i = 0; i < size; i++) {
1540
            resp[i] = input[(i * n) + ind];
1541
        }
1542

    
1543
        return resp;
1544
    }
1545

    
1546
    /*
1547
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1548
        IGeometry ig = null;
1549

1550
        if (jg.isCircle()) {
1551
            ig = getCircleFromJGeometry(jg);
1552
        }
1553
        else {
1554
            Shape shape = jg.createShape();
1555
            GeneralPathX gpx = new GeneralPathX(shape);
1556

1557
            if (dim == 2) {
1558
                ig = ShapeFactory.createPolygon2D(gpx);
1559
            }
1560
            else {
1561
                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1562
                ig = ShapeFactory.createPolygon3D(gpx, z);
1563
            }
1564
        }
1565

1566
        return ig;
1567
    }
1568
    */
1569

    
1570
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1571
        IGeometry ig = null;
1572

    
1573
        if (OracleSpatialUtils.isCircle(the_data)) {
1574
            ig = getCircleFromStruct(the_data);
1575
        }
1576
        else {
1577
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1578

    
1579
            if (dim == 2) {
1580
                ig = ShapeFactory.createPolygon2D(gpx);
1581
            }
1582
            else {
1583
                double[] ords = null;
1584

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

    
1593
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1594
                ig = ShapeFactory.createPolygon3D(gpx, z);
1595
            }
1596
        }
1597

    
1598
        return ig;
1599
    }
1600

    
1601
    /*
1602
    private IGeometry getCircleFromJGeometry(JGeometry jg) {
1603
        double[] threep = jg.getOrdinatesArray();
1604
        Point2D[] three = new Point2D.Double[3];
1605
        three[0] = new Point2D.Double(threep[0], threep[1]);
1606
        three[1] = new Point2D.Double(threep[2], threep[3]);
1607
        three[2] = new Point2D.Double(threep[4], threep[5]);
1608

1609
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1610

1611
        Point2D cent = (Point2D) cent_rad[0];
1612
        double radius = ((Double) cent_rad[1]).doubleValue();
1613

1614
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1615

1616
        return circ;
1617
    }
1618
    */
1619

    
1620
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1621
        double[] threep = null;
1622

    
1623
        try {
1624
            threep = ((ARRAY) the_data[4]).getDoubleArray();
1625
        }
1626
        catch (SQLException se) {
1627
            logger.error("While getting ords from struct: " + se.getMessage(),
1628
                se);
1629

    
1630
            return new FNullGeometry();
1631
        }
1632

    
1633
        Point2D[] three = new Point2D.Double[3];
1634
        three[0] = new Point2D.Double(threep[0], threep[1]);
1635
        three[1] = new Point2D.Double(threep[2], threep[3]);
1636
        three[2] = new Point2D.Double(threep[4], threep[5]);
1637

    
1638
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1639

    
1640
        Point2D cent = (Point2D) cent_rad[0];
1641
        double radius = ((Double) cent_rad[1]).doubleValue();
1642

    
1643
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1644

    
1645
        return circ;
1646
    }
1647

    
1648
    /*
1649
    private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1650
        Shape shape = jg.createShape();
1651
        GeneralPathX gpx = new GeneralPathX(shape);
1652
        IGeometry ig = null;
1653

1654
        if (dim == 2) {
1655
            ig = ShapeFactory.createPolyline2D(gpx);
1656
        }
1657
        else {
1658
            double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1659
            ig = ShapeFactory.createPolyline3D(gpx, z);
1660
        }
1661

1662
        return ig;
1663
    }
1664
    */
1665

    
1666
    private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1667
        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1668
        IGeometry ig = null;
1669
        double[] ords = null;
1670

    
1671
        if (dim == 2) {
1672
            ig = ShapeFactory.createPolyline2D(gpx);
1673
        }
1674
        else {
1675
            ords = OracleSpatialUtils.getOrds(the_data);
1676

    
1677
            double[] z = getIndBigDecimalModule(ords, 2, dim);
1678
            ig = ShapeFactory.createPolyline3D(gpx, z);
1679
        }
1680

    
1681
        return ig;
1682
    }
1683

    
1684
    /*
1685
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1686
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1687

1688
            return getFMapGeometrySdoPoint(jg_point, dim);
1689
        }
1690

1691
        IGeometry ig = null;
1692
        int total_size = jg_point.getOrdinatesArray().length;
1693
        int no_po = total_size / dim;
1694
        double[] x = new double[no_po];
1695
        double[] y = new double[no_po];
1696
        double[] z = new double[no_po];
1697

1698
        for (int i = 0; i < no_po; i++) {
1699
            x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1700
            y[i] = jg_point.getOrdinatesArray()[(i * dim) + 1];
1701

1702
            if (dim >= 3) {
1703
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1704
            }
1705
        }
1706

1707
        if (dim == 2) {
1708
            if (no_po == 1) {
1709
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1710
            }
1711
            else {
1712
                ig = ShapeFactory.createMultipoint2D(x, y);
1713
            }
1714
        }
1715
        else {
1716
            if (no_po == 1) {
1717
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1718
            }
1719
            else {
1720
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1721
            }
1722
        }
1723

1724
        return ig;
1725
    }
1726
    */
1727

    
1728
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1729
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1730

    
1731
        if (ords == null) { // sdo_point
1732

    
1733
            return getFMapGeometrySdoPoint(the_data, dim);
1734
        }
1735

    
1736
        IGeometry ig = null;
1737
        int total_size = ords.length;
1738
        int no_po = total_size / dim;
1739
        double[] x = new double[no_po];
1740
        double[] y = new double[no_po];
1741
        double[] z = new double[no_po];
1742

    
1743
        for (int i = 0; i < no_po; i++) {
1744
            x[i] = ords[i * dim]; // pp[i].getX();
1745
            y[i] = ords[(i * dim) + 1];
1746

    
1747
            if (dim >= 3) {
1748
                z[i] = ords[(i * dim) + 2];
1749
            }
1750
        }
1751

    
1752
        if (dim == 2) {
1753
            if (no_po == 1) {
1754
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1755
            }
1756
            else {
1757
                ig = ShapeFactory.createMultipoint2D(x, y);
1758
            }
1759
        }
1760
        else {
1761
            if (no_po == 1) {
1762
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1763
            }
1764
            else {
1765
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1766
            }
1767
        }
1768

    
1769
        return ig;
1770
    }
1771

    
1772
    /*
1773
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1774
        double[] p = jgp.getPoint();
1775
        IGeometry ig = null;
1776

1777
        if (d == 2) {
1778
            ig = ShapeFactory.createPoint2D(p[0], p[1]);
1779
        }
1780
        else {
1781
            ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1782
        }
1783

1784
        return ig;
1785
    }
1786
    */
1787

    
1788
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1789
        double x = 0;
1790
        double y = 0;
1791
        double z = 0;
1792

    
1793
        try {
1794
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1795
            x = ((NUMBER) aux[0]).doubleValue();
1796
            y = ((NUMBER) aux[1]).doubleValue();
1797

    
1798
            if (d > 2) {
1799
                z = ((NUMBER) aux[2]).doubleValue();
1800
            }
1801
        }
1802
        catch (SQLException se) {
1803
            logger.error("While getting sdo point ordinates: " +
1804
                se.getMessage(), se);
1805
        }
1806

    
1807
        IGeometry ig = null;
1808

    
1809
        if (d == 2) {
1810
            ig = ShapeFactory.createPoint2D(x, y);
1811
        }
1812
        else {
1813
            ig = ShapeFactory.createPoint3D(x, y, z);
1814
        }
1815

    
1816
        return ig;
1817
    }
1818

    
1819
    /*
1820
    private boolean isActuallyACollection(JGeometry jg) {
1821
        int[] info = jg.getElemInfo();
1822

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

1827
        int size = info.length / 3;
1828

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

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

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

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

1845
        return false;
1846
    }
1847
    */
1848

    
1849
    private boolean isActuallyACollection(Datum[] the_data) {
1850
        int[] info = null;
1851

    
1852
        try {
1853
            ARRAY aux = (ARRAY) the_data[3];
1854

    
1855
            if (aux == null) {
1856
                return false;
1857
            }
1858

    
1859
            info = aux.getIntArray();
1860
        }
1861
        catch (SQLException se) {
1862
            logger.error("While checking collection: " + se.getMessage());
1863
            return false;
1864
        }
1865

    
1866
        if (info == null) {
1867
            return false; // sdo_point
1868
        }
1869

    
1870
        int size = info.length / 3;
1871

    
1872
        if (size == 1) {
1873
            return false;
1874
        }
1875

    
1876
        if (size == 2) {
1877
            return ((info[1] % 1000) != (info[4] % 1000)) && 
1878
            ( ! ((info[1] == 1005) && (info[4] == 2)) );
1879
        }
1880

    
1881
        int second = info[4] % 1000;
1882
        int item = 0;
1883

    
1884
        for (int i = 2; i < size; i++) {
1885
                item = info[(i * 3) + 1] % 1000;
1886
            if ((item != second) &&
1887
                            ( ! ((item == 5) && (second == 2)) )
1888
                            ) {
1889
                return true;
1890
            }
1891
        }
1892

    
1893
        return false;
1894
    }
1895

    
1896
    /*
1897
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1898
        int main_type = jg.getType();
1899

1900
        int[] all_info_array = jg.getElemInfo();
1901
        Object[] elems_info_aray = groupByElement(all_info_array);
1902
        double[] all_ords = jg.getOrdinatesArray();
1903
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1904
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1905

1906
        for (int i = 0; i < elems_info_aray.length; i++) {
1907
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1908
        }
1909

1910
        // _elems_info_aray, ords_of_groups
1911
        int no_of_elems = ords_of_groups.length;
1912
        IGeometry[] geoms = new IGeometry[no_of_elems];
1913

1914
        for (int i = 0; i < no_of_elems; i++) {
1915
            int[] item_info_array = (int[]) _elems_info_aray[i];
1916
            double[] item_ords = (double[]) ords_of_groups[i];
1917
            int gtype = (dim * 1000) + (item_info_array[1] % 1000);
1918

1919
            // if it's the first geometry, the type is the collection's main type (no?)
1920
            if (i == 0) {
1921
                gtype = main_type;
1922
            }
1923

1924
            JGeometry itemjg = null;
1925

1926
            if (tableHasSrid) {
1927
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1928
            }
1929
            else {
1930
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1931
            }
1932

1933
            geoms[i] = getFMapGeometry(itemjg, true);
1934
        }
1935

1936
        return new FGeometryCollection(geoms);
1937
    }
1938
    */
1939

    
1940
    private Datum[] updateIndexes(Datum[] info) {
1941
        int size = info.length / 3;
1942
        NUMBER[] resp = new NUMBER[3 * size];
1943

    
1944
        try {
1945
            int rest = info[0].intValue() - 1;
1946

    
1947
            for (int i = 0; i < size; i++) {
1948
                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1949
                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
1950
                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
1951
            }
1952
        }
1953
        catch (SQLException se) {
1954
            logger.error("Unexpected error: " + se.getMessage());
1955
        }
1956

    
1957
        return resp;
1958
    }
1959

    
1960
    private int[] updateIndexes(int[] info) {
1961
        int size = info.length / 3;
1962
        int[] resp = new int[3 * size];
1963
        int rest = info[0] - 1;
1964

    
1965
        for (int i = 0; i < size; i++) {
1966
            resp[3 * i] = info[3 * i] - rest;
1967
            resp[(3 * i) + 1] = info[(3 * i) + 1];
1968
            resp[(3 * i) + 2] = info[(3 * i) + 2];
1969
        }
1970

    
1971
        return resp;
1972
    }
1973

    
1974
    private int[] appendIntArrays(int[] head, int[] tail) {
1975
        int[] resp = new int[head.length + tail.length];
1976
        int hsize = head.length;
1977

    
1978
        for (int i = 0; i < hsize; i++) {
1979
            resp[i] = head[i];
1980
        }
1981

    
1982
        for (int i = 0; i < tail.length; i++) {
1983
            resp[hsize + i] = tail[i];
1984
        }
1985

    
1986
        return resp;
1987
    }
1988

    
1989
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
1990
        Datum[] resp = new Datum[head.length + tail.length];
1991
        int hsize = head.length;
1992

    
1993
        for (int i = 0; i < hsize; i++) {
1994
            resp[i] = head[i];
1995
        }
1996

    
1997
        for (int i = 0; i < tail.length; i++) {
1998
            resp[hsize + i] = tail[i];
1999
        }
2000

    
2001
        return resp;
2002
    }
2003

    
2004
    private int[] getNthGroupOfThree(int[] list, int n) {
2005
        int[] resp = new int[3];
2006
        resp[0] = list[3 * n];
2007
        resp[1] = list[(3 * n) + 1];
2008
        resp[2] = list[(3 * n) + 2];
2009

    
2010
        return resp;
2011
    }
2012

    
2013
    private Datum[] getNthGroupOfThree(Datum[] list, int n) {
2014
        Datum[] resp = new Datum[3];
2015
        resp[0] = list[3 * n];
2016
        resp[1] = list[(3 * n) + 1];
2017
        resp[2] = list[(3 * n) + 2];
2018

    
2019
        return resp;
2020
    }
2021

    
2022
    private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
2023
        Datum[] resp = new Datum[last_inc - first_inc + 1];
2024

    
2025
        for (int i = first_inc; i <= last_inc; i++) {
2026
            resp[i - first_inc] = all[i];
2027
        }
2028

    
2029
        return resp;
2030
    }
2031

    
2032
    private double[] getSubSet(double[] all, int first_inc, int last_inc) {
2033
        double[] resp = new double[last_inc - first_inc + 1];
2034

    
2035
        for (int i = first_inc; i <= last_inc; i++) {
2036
            resp[i - first_inc] = all[i];
2037
        }
2038

    
2039
        return resp;
2040
    }
2041

    
2042
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) throws SQLException {
2043
        Object[] resp = new Object[groups.length];
2044

    
2045
        if (resp.length == 1) {
2046
            resp[0] = all;
2047

    
2048
            return resp;
2049
        }
2050

    
2051
        int ind = 0;
2052
        Datum[] aux = (Datum[]) groups[1];
2053
        int _end = aux[0].intValue() - 2;
2054
        Datum[] ord_aux = getSubSet(all, 0, _end);
2055

    
2056
        int _start = _end + 1;
2057
        resp[ind] = ord_aux;
2058
        ind++;
2059

    
2060
        for (int i = 2; i < groups.length; i++) {
2061
            aux = (Datum[]) groups[i];
2062
            _end = aux[0].intValue() - 2;
2063
            ord_aux = getSubSet(all, _start, _end);
2064
            resp[ind] = ord_aux;
2065
            ind++;
2066
            _start = _end + 1;
2067
        }
2068

    
2069
        // last
2070
        _end = all.length - 1;
2071
        ord_aux = getSubSet(all, _start, _end);
2072
        resp[groups.length - 1] = ord_aux;
2073

    
2074
        return resp;
2075
    }
2076

    
2077
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2078
        Object[] resp = new Object[groups.length];
2079

    
2080
        if (resp.length == 1) {
2081
            resp[0] = all;
2082

    
2083
            return resp;
2084
        }
2085

    
2086
        int ind = 0;
2087
        int[] aux = (int[]) groups[1];
2088
        int _end = aux[0] - 2;
2089
        double[] ord_aux = getSubSet(all, 0, _end);
2090

    
2091
        int _start = _end + 1;
2092
        resp[ind] = ord_aux;
2093
        ind++;
2094

    
2095
        for (int i = 2; i < groups.length; i++) {
2096
            aux = (int[]) groups[i];
2097
            _end = aux[0] - 2;
2098
            ord_aux = getSubSet(all, _start, _end);
2099
            resp[ind] = ord_aux;
2100
            ind++;
2101
            _start = _end + 1;
2102
        }
2103

    
2104
        // last
2105
        _end = all.length - 1;
2106
        ord_aux = getSubSet(all, _start, _end);
2107
        resp[groups.length - 1] = ord_aux;
2108

    
2109
        return resp;
2110
    }
2111

    
2112
    private Object[] groupByElement(int[] all_elem) {
2113
        ArrayList resp = new ArrayList();
2114

    
2115
        int size = all_elem.length / 3;
2116

    
2117
        int[] aux = getNthGroupOfThree(all_elem, 0);
2118

    
2119
        int[] newaux;
2120
        int i = 1;
2121

    
2122
        while (i < size) {
2123
            newaux = getNthGroupOfThree(all_elem, i);
2124

    
2125
            if (newaux[0] == aux[0]) {
2126
                // aux[2] says how many components
2127
                for (int j = 0; j < aux[2]; j++) {
2128
                    aux = appendIntArrays(aux,
2129
                            getNthGroupOfThree(all_elem, j + i));
2130
                }
2131

    
2132
                resp.add(aux);
2133
                i = i + aux[2];
2134
                aux = getNthGroupOfThree(all_elem, i);
2135
            }
2136
            else {
2137
                if (newaux[1] == 2003) {
2138
                    aux = appendIntArrays(aux, newaux);
2139
                }
2140
                else {
2141
                    resp.add(aux);
2142
                    aux = getNthGroupOfThree(all_elem, i);
2143
                }
2144
            }
2145

    
2146
            i++;
2147
        }
2148

    
2149
        resp.add(aux);
2150

    
2151
        return resp.toArray();
2152
    }
2153

    
2154
    private Object[] groupByElement(Datum[] all_elem) {
2155
        ArrayList resp = new ArrayList();
2156

    
2157
        int size = all_elem.length / 3;
2158

    
2159
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2160

    
2161
        Datum[] newaux;
2162
        int i = 1;
2163

    
2164
        try {
2165
            while (i < size) {
2166
                newaux = getNthGroupOfThree(all_elem, i);
2167

    
2168
                if (newaux[0] == aux[0]) {
2169
                    // aux[2] says how many components
2170
                    for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
2171
                        aux = appendDatArrays(aux,
2172
                                getNthGroupOfThree(all_elem, j + i));
2173
                    }
2174

    
2175
                    resp.add(aux);
2176
                    i = i + ((NUMBER) aux[2]).intValue();
2177
                    aux = getNthGroupOfThree(all_elem, i);
2178
                }
2179
                else {
2180
                    if (((NUMBER) newaux[1]).intValue() == 2003) {
2181
                        aux = appendDatArrays(aux, newaux);
2182
                    }
2183
                    else {
2184
                        resp.add(aux);
2185
                        aux = getNthGroupOfThree(all_elem, i);
2186
                    }
2187
                }
2188

    
2189
                i++;
2190
            }
2191
        }
2192
        catch (SQLException se) {
2193
            logger.error("Unexpected error: " + se.getMessage());
2194
        }
2195

    
2196
        resp.add(aux);
2197

    
2198
        return resp.toArray();
2199
    }
2200

    
2201
    /*
2202
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2203
        Point2D p = _jgeom.getJavaPoint();
2204
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2205

2206
        return ig;
2207
    }
2208

2209
    private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2210
        Point2D[] pp = _jgeom.getJavaPoints();
2211
        int l = pp.length;
2212
        double[] x = new double[l];
2213
        double[] y = new double[l];
2214

2215
        for (int i = 0; i < l; i++) {
2216
            x[i] = pp[i].getX();
2217
            y[i] = pp[i].getY();
2218
        }
2219

2220
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2221

2222
        return ig;
2223
    }
2224

2225
    private IGeometry getJGeometryOther(JGeometry _jgeom) {
2226
        int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2227
        Shape shape = _jgeom.createShape();
2228
        GeneralPathX gpx = new GeneralPathX(shape);
2229
        IGeometry ig = null;
2230

2231
        switch (type) {
2232
        case FShape.LINE:
2233

2234
            FPolyline2D fpl = new FPolyline2D(gpx);
2235
            ig = ShapeFactory.createPolyline2D(gpx);
2236

2237
            break;
2238

2239
        case FShape.POLYGON:
2240

2241
            FPolygon2D fpg = new FPolygon2D(gpx);
2242
            ig = ShapeFactory.createPolygon2D(gpx);
2243

2244
            break;
2245
        }
2246

2247
        return ig;
2248
    }
2249
    */
2250

    
2251
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
2252
        /*
2253
         * Tipos en Oracle Spatial usando JGeometry
2254
         *
2255
         * GTYPE_COLLECTION collection geometry type
2256
         * GTYPE_CURVE curve geoemtry type
2257
         * GTYPE_MULTICURVE multi-curve geometry type
2258
         * GTYPE_MULTIPOINT multi-point geometry type
2259
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
2260
         * GTYPE_POINT point geometry type
2261
         * GTYPE_POLYGON  polygon geometry type
2262
         *
2263
         * Tipos gvSIG FShape
2264
         *
2265
         * NULL = 0;
2266
         * POINT = 1;
2267
         * LINE = 2;
2268
         * POLYGON = 4;
2269
         * TEXT = 8;
2270
         * MULTI = 16;
2271
         * MULTIPOINT = 32;
2272
         * CIRCLE = 64;
2273
         * ARC = 128;
2274
         * ELLIPSE=256;
2275
         * Z=512
2276
         */
2277
        switch (type) {
2278
        case JGeometry_GTYPE_POLYGON:
2279
        case JGeometry_GTYPE_MULTIPOLYGON:
2280
            return FShape.POLYGON;
2281

    
2282
        case JGeometry_GTYPE_CURVE:
2283
        case JGeometry_GTYPE_MULTICURVE:
2284
            return FShape.LINE;
2285
        }
2286

    
2287
        System.err.println("Unhandled Oracle Spatial geometry type: " + type +
2288
            " (conversion returned FShape.NULL)");
2289

    
2290
        return FShape.NULL;
2291
    }
2292

    
2293
    private void cleanWhereClause() {
2294
        emptyWhereClause = false;
2295

    
2296
        String aux = getWhereClauseWithoutWhere();
2297

    
2298
        for (int i = 0; i < aux.length(); i++)
2299
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
2300
                return;
2301
            }
2302

    
2303
        getLyrDef().setWhereClause("");
2304
        emptyWhereClause = true;
2305
    }
2306
    
2307
    private String getValidViewConstructor(
2308
                    STRUCT _st,
2309
                    String ora_srid,
2310
                    boolean _hassrid,
2311
                    boolean _isgeocs) {
2312
            
2313
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
2314
            String resp = "";
2315
            if ((_hassrid) && (_isgeocs)) {
2316
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
2317
            } else {
2318
                    resp = sdo;
2319
            }
2320
             
2321
            return resp;
2322
    }
2323

    
2324
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2325
        String resp = "";
2326

    
2327
        if (isGeogCS) {
2328
            String vport = "sdo_filter(" + geoColName +
2329
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
2330
                "), 'querytype=window') = 'TRUE'";
2331

    
2332
                resp = "select " + getStandardSelectExpression() + ", c." +
2333
                    geoColName + " from " + getTableName() + " c where ";
2334
                if (idsLoadWhere.length() > 0) {
2335
                        resp = resp + " (" + idsLoadWhere + ") AND "; 
2336
                }
2337
                resp = resp + "(" + vport + ")";
2338
        }
2339
        else {
2340
                resp = "select " + getStandardSelectExpression() + ", c." +
2341
                    geoColName + " from " + getTableName() + " c where ";
2342
                if (idsLoadWhere.length() > 0) {
2343
                        resp = resp + " (" + idsLoadWhere + ") AND "; 
2344
                }
2345
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
2346
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
2347
        }
2348
        
2349
//        return "select " + getStandardSelectExpression() + ", c." +
2350
//        geoColName + " from " + getTableName() + " c";
2351
        return resp;
2352
    }
2353

    
2354
    public void setWorkingArea(Rectangle2D rect) {
2355
    }
2356

    
2357
    private void setWAStructt() {
2358
    }
2359

    
2360
    private Geometry shapeToGeometry(Shape shp) {
2361
        if (shp == null) {
2362
            return null;
2363
        }
2364

    
2365
        int type = FShape.POLYGON;
2366

    
2367
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2368
            type = FShape.LINE;
2369
        }
2370

    
2371
        if (shp instanceof FPoint2D) {
2372
            type = FShape.POINT;
2373
        }
2374

    
2375
        if (shp instanceof FMultiPoint2D) {
2376
            type = FShape.MULTIPOINT;
2377
        }
2378

    
2379
        GeneralPathX wagp = new GeneralPathX(shp);
2380
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2381

    
2382
        return FConverter.java2d_to_jts(fwagp);
2383
    }
2384

    
2385
    /*
2386
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2387
        Shape shape = _jg.createShape();
2388

2389
        return shape.getBounds2D();
2390
    }
2391
    */
2392

    
2393
    private void printStruct(STRUCT st) {
2394
        System.out.println("----------------------------------------------");
2395

    
2396
        try {
2397
            Object[] att = st.getAttributes();
2398
            int l = att.length;
2399

    
2400
            for (int i = 0; i < l; i++) {
2401
                System.out.println("ATT " + i + ": " + att[i].toString());
2402
            }
2403
        }
2404
        catch (Exception ex) {
2405
            System.out.println(
2406
                "- Error ---------------------------------------");
2407
        }
2408

    
2409
        System.out.println("----------------------------------------------");
2410
    }
2411

    
2412
    private static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
2413
        boolean isView, boolean _isGeogCS, String _oracleSRID, Connection __conn) {
2414
        Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2415
        Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2416

    
2417
        if ((_isGeogCS) && (isView)) {
2418
            c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2419
            c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2420
        }
2421

    
2422
        STRUCT resp = null;
2423

    
2424
        try {
2425
            // System.out.println("ABIERTA: " + (!conn.isClosed()));
2426
            // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2427
            // Object[] old_obj = resp.getAttributes();
2428
            int size = 5;
2429
            Object[] new_obj = new Object[size];
2430

    
2431
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2432
            new_obj[0] = new NUMBER(2003);
2433

    
2434
            if (hasSrid) {
2435
                new_obj[1] = new NUMBER(_oracleSRID);
2436
            }
2437
            else {
2438
                new_obj[1] = null;
2439
            }
2440

    
2441
            new_obj[2] = null;
2442

    
2443
            NUMBER[] elem_info = new NUMBER[3];
2444
            elem_info[0] = new NUMBER(1);
2445
            elem_info[1] = new NUMBER(1003);
2446
            elem_info[2] = new NUMBER(3);
2447
            new_obj[3] = elem_info;
2448

    
2449
            NUMBER[] ords = null;
2450
            ords = new NUMBER[4];
2451
            ords[0] = new NUMBER(c1.getX());
2452
            ords[1] = new NUMBER(c1.getY());
2453
            ords[2] = new NUMBER(c2.getX());
2454
            ords[3] = new NUMBER(c2.getY());
2455
            new_obj[4] = ords;
2456

    
2457
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2458
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2459
                    __conn);
2460

    
2461
            resp = new STRUCT(dsc, __conn, new_obj);
2462
        }
2463
        catch (Exception ex) {
2464
            logger.error("Error while creating rect struct: " +
2465
                ex.getMessage(), ex);
2466
        }
2467

    
2468
        return resp;
2469
    }
2470

    
2471
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2472
        boolean hasSrid) throws DriverException {
2473
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
2474
        String main_sel = "";
2475

    
2476
        if (fixsql == null) {
2477
            // main_sel = getMainSelect3(var_name);
2478
                String idswhere = getIdsQueryWhereClause(false);
2479
            main_sel = getMainSelect(sdo_intersect, idswhere);
2480
        }
2481
        else {
2482
            main_sel = fixsql;
2483
        }
2484

    
2485
        logger.debug("MAIN SEL = " + main_sel);
2486

    
2487
        ResultSet _rs = null;
2488
        Statement _stmnt = null;
2489
        Object[] _resp = new Object[2];
2490

    
2491
        try {
2492
            _stmnt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
2493
                    ResultSet.CONCUR_READ_ONLY);
2494
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2495
            _stmnt.setFetchSize(FETCH_SIZE);
2496

    
2497
            _rs = _stmnt.executeQuery(main_sel);
2498

    
2499
            // stmnt.close();
2500
        }
2501
        catch (SQLException se) {
2502
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
2503
                se);
2504
            throw new DriverException(se);
2505
        }
2506

    
2507
        // this method returns the statement too, so that it can be closed afterwards
2508
        _resp[0] = _rs;
2509
        _resp[1] = _stmnt;
2510

    
2511
        return _resp;
2512
    }
2513

    
2514
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2515
        String resp = "";
2516

    
2517
        try {
2518
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2519
            String mdsys_sdo_ordinate_array = "";
2520
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2521

    
2522
            for (int i = 0; i < vertices.length; i++) {
2523
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2524
                    vertices[i].doubleValue() + ", ";
2525
            }
2526

    
2527
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2528
                    mdsys_sdo_ordinate_array.length() - 2);
2529
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2530
                mdsys_sdo_ordinate_array + ")";
2531

    
2532
            String aux = "";
2533

    
2534
            if (hasSrid) {
2535
                aux = oracleSRID;
2536

    
2537
                if (_isGeogCS) {
2538
                    aux = "0";
2539
                }
2540
            }
2541
            else {
2542
                aux = "null";
2543
            }
2544

    
2545
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
2546
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
2547
                ")";
2548
        }
2549
        catch (Exception ex) {
2550
            System.err.println("Error while getting sdo contructor: " +
2551
                ex.getMessage());
2552
        }
2553

    
2554
        return resp;
2555
    }
2556
    
2557
    private String getIdsQueryWhereClause(boolean with_where) {
2558
                String resp = "";
2559
                
2560
                String _where = "";
2561
                if (with_where) _where = " where ";
2562

    
2563
                if (workingAreaInTablesCSStruct == null) {
2564
                        if (emptyWhereClause) {
2565
                                // return "select rowid from " + getTableName();
2566
                        } else {
2567
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
2568
                                                + ")";
2569
                        }
2570
                } else {
2571
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
2572
                                        oracleSRID, tableHasSrid, isGeogCS);
2573

    
2574
                        if (emptyWhereClause) {
2575
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
2576
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2577
                        } else {
2578
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
2579
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
2580
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2581
                        }
2582
                }
2583

    
2584
                // resp = resp + " order by rowid";
2585
                return resp;
2586
        }
2587

    
2588
    public String getIdAndElemInfoFullResulltSetQuery() {
2589
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
2590
            getTableName() + " c";
2591
        
2592
        resp = resp + getIdsQueryWhereClause(true);
2593
        return resp;
2594
    }
2595

    
2596
    private String getSearchId() {
2597
        if (emptyWhereClause) {
2598
            return "select " + getStandardSelectExpression() + ", c." +
2599
            geoColName + " from " + getTableName() + " c where rowid = ?";
2600
        }
2601
        else {
2602
            return "select " + getStandardSelectExpression() + ", c." +
2603
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
2604
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
2605
        }
2606
    }
2607

    
2608
    public int getShapeType() {
2609
        return shapeType;
2610
    }
2611

    
2612
    private String getWhereClauseWithoutWhere() {
2613
        String resp = "";
2614
        String old = getLyrDef().getWhereClause();
2615
        resp = old;
2616

    
2617
        if (old.length() <= 6) {
2618
            return old;
2619
        }
2620

    
2621
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2622
            resp = resp.substring(6, resp.length());
2623
        }
2624

    
2625
        return resp;
2626
    }
2627

    
2628
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2629
        if (r1.getMaxX() <= r2.getMinX()) {
2630
            return null;
2631
        }
2632

    
2633
        if (r2.getMaxX() <= r1.getMinX()) {
2634
            return null;
2635
        }
2636

    
2637
        if (r1.getMaxY() <= r2.getMinY()) {
2638
            return null;
2639
        }
2640

    
2641
        if (r2.getMaxY() <= r1.getMinY()) {
2642
            return null;
2643
        }
2644

    
2645
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2646
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2647
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2648
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2649

    
2650
        double w = maxx - minx;
2651
        double h = maxy - miny;
2652

    
2653
        return new Rectangle2D.Double(minx, miny, w, h);
2654
    }
2655

    
2656
    private static int maxSizeForFieldType(int _type) {
2657
        switch (_type) {
2658
        case Types.VARCHAR:
2659
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2660

    
2661
        case Types.LONGVARCHAR:
2662
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2663
        }
2664

    
2665
        return -1;
2666
    }
2667

    
2668
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2669
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2670

    
2671
        switch (fieldDesc.getFieldType()) {
2672
        case Types.SMALLINT:
2673
            aux = "NUMBER(5, 0)";
2674

    
2675
            break;
2676

    
2677
        case Types.INTEGER:
2678
            aux = "NUMBER(10, 0)";
2679

    
2680
            break;
2681

    
2682
        case Types.BIGINT:
2683
            aux = "NUMBER(38, 0)";
2684

    
2685
            break;
2686

    
2687
        case Types.BOOLEAN:
2688
            aux = "NUMBER(1, 0)";
2689

    
2690
            break;
2691

    
2692
        case Types.DECIMAL:
2693
            aux = "NUMBER";
2694

    
2695
            break;
2696

    
2697
        case Types.NUMERIC:
2698
            aux = "NUMBER";
2699

    
2700
            break;
2701

    
2702
        case Types.DOUBLE:
2703
            aux = "FLOAT";
2704

    
2705
            break;
2706

    
2707
        case Types.FLOAT:
2708
            aux = "FLOAT";
2709

    
2710
            break;
2711

    
2712
        case Types.CHAR:
2713
            aux = "CHAR(1 BYTE)";
2714

    
2715
            break;
2716

    
2717
        case Types.VARCHAR:
2718
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2719

    
2720
            break;
2721

    
2722
        case Types.LONGVARCHAR:
2723
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2724

    
2725
            break;
2726
        }
2727

    
2728
        return aux;
2729
    }
2730

    
2731
    // -----------------------------------------------------------
2732
    // -----------------------------------------------------------
2733
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2734
        return "DROP TABLE " + dbLayerDef.getTableName() +
2735
        " CASCADE CONSTRAINTS";
2736
    }
2737

    
2738
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2739
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2740

    
2741
        String type = "";
2742
        String name = "";
2743

    
2744
        String resp = "CREATE TABLE " + dbLayerDef.getTableName() + " ( ";
2745

    
2746
        for (int i = 0; i < flds.length; i++) {
2747
            name = flds[i].getFieldName();
2748

    
2749
            // -------------- FORBIDDEN FIELD NAMES -----------------
2750
            if (!isOracleAllowedFieldname(name)) {
2751
                continue;
2752
            }
2753

    
2754
            // ------------------------------------------------------
2755
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
2756
            }
2757
            else {
2758
                name = getValidOracleID(name, i);
2759
                resp = resp + "\"" + name + "\" ";
2760
                type = fieldTypeToSqlStringType(flds[i]);
2761
                resp = resp + type + ", ";
2762
            }
2763
        }
2764

    
2765
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2766
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2767
        resp = resp + ", ";
2768

    
2769
        String pk = "CONSTRAINT " + getDerivedNAme(dbLayerDef.getTableName(), "PK") +
2770
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD +
2771
            "\") ENABLE";
2772

    
2773
        resp = resp + pk + " )";
2774

    
2775
        return resp;
2776
    }
2777
    
2778
    private static String getDerivedNAme(String tname, String suffix) {
2779
            
2780
            int ind = tname.lastIndexOf("."); 
2781
            if (ind == -1) {
2782
                    
2783
                    int l = Math.min(28, tname.length());
2784
                    return tname.substring(0, l) + "_" + suffix;
2785

    
2786
            } else {
2787
                    
2788
                    String pre = tname.substring(0, ind);
2789
                    String post = tname.substring(ind + 1, tname.length());
2790
                    int lpost = Math.min(24, post.length());
2791
                    int lpre = Math.min(3, pre.length());
2792
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
2793
            }
2794
            
2795
    }
2796

    
2797
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2798
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
2799
            " ON " + dbLayerDef.getTableName() + " (\"" +
2800
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
2801
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2802

    
2803
        return resp;
2804
    }
2805

    
2806
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2807
            
2808
            String tname = dbLayerDef.getTableName();
2809
            int ind = tname.lastIndexOf(".");
2810
            if (ind != -1) {
2811
                    String schema = tname.substring(0, ind);
2812
                    tname = tname.substring(ind + 1, tname.length());
2813
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2814
            " WHERE TABLE_NAME = '" + tname + "' AND OWNER = '" + schema + "'";
2815
                     
2816
            } else{
2817
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2818
            " WHERE TABLE_NAME = '" + tname + "'";
2819
            }
2820
    }
2821

    
2822
    /**
2823
     * UTility method to get the SQL sentence needed to update the geographic metadata table
2824
     * with a new bounding box and SRS
2825
     *
2826
     * @param tName table name
2827
     * @param ora_srid new SRS
2828
     * @param bbox new bounding box
2829
     * @param dim geometries dimension
2830
     * @param withsrid False if the SRS is set to NULL. True otherwise.
2831
     * @return the SQL sentence to perform the update
2832
     */
2833
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
2834
        Rectangle2D bbox, int dim, boolean withsrid) {
2835
        String[] dim_name = new String[dim];
2836
        double tolerance = 0.5;
2837

    
2838
        if (ora_srid.compareTo(GEODETIC_SRID) == 0) {
2839
            dim_name[0] = "LONGITUDE";
2840
            dim_name[1] = "LATITUDE";
2841
        }
2842
        else {
2843
            dim_name[0] = "X";
2844
            dim_name[1] = "Y";
2845

    
2846
            if (dim > 2) {
2847
                dim_name[2] = "Z";
2848

    
2849
                if (dim > 3) {
2850
                    dim_name[3] = "T";
2851
                }
2852
            }
2853
        }
2854

    
2855
        String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " " +
2856
            " ( OWNER, TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
2857
            + "'" + schema + "', "
2858
            + "'" + tName + "', "
2859
            + "'" + DEFAULT_GEO_FIELD + "', " +
2860
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2861
            bbox.getMinX() + ", " + bbox.getMaxX() + ", " + tolerance + " ), " +
2862
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + bbox.getMinY() + ", " +
2863
            bbox.getMaxY() + ", " + tolerance + " ))";
2864

    
2865
        if (dim > 2) {
2866
            resp = resp.substring(0, resp.length() - 1) + ",";
2867
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
2868
                "', 0.0, 100.0, " + tolerance + " ))";
2869

    
2870
            if (dim > 3) {
2871
                resp = resp.substring(0, resp.length() - 1) + ",";
2872
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
2873
                    "', 0.0, 100.0, " + tolerance + " ))";
2874
            }
2875
        }
2876

    
2877
        if (withsrid) {
2878
            resp = resp + ", " + ora_srid + " )";
2879
        }
2880
        else {
2881
            resp = resp + ", NULL )";
2882
        }
2883

    
2884
        return resp;
2885
    }
2886

    
2887
    /**
2888
     * Gets the SQL sentence to perform an insertion.
2889
     *
2890
     * @param feat feature to be added
2891
     * @param dbLayerDef layer definition
2892
     * @param rowInd row index
2893
     * @param _geoColName geometry field name
2894
     * @return the SQL sentence to perform the insertion
2895
     */
2896
    public static String getRowInsertSql(IFeature feat,
2897
        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2898
        String name = "";
2899
        int ftype = -1;
2900
        String aux_orig = "";
2901
        String aux_limited = "";
2902
        String aux_quotes_ok = "";
2903

    
2904
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2905

    
2906
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
2907

    
2908
        for (int i = 0; i < fieldsDescr.length; i++) {
2909
            name = fieldsDescr[i].getFieldName();
2910
            ftype = fieldsDescr[i].getFieldType();
2911

    
2912
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2913
            if (!isOracleAllowedFieldname(name)) continue;
2914
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2915
            // ------------------------------------------------------
2916
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2917
            }
2918
            else {
2919
                name = getValidOracleID(name, i);
2920
                resp = resp + "\"" + name + "\"" + " , ";
2921
            }
2922
        }
2923

    
2924
        resp = resp + _geoColName + " ) VALUES ( ";
2925

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

    
2930
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2931
            if (!isOracleAllowedFieldname(name)) continue;
2932
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2933
            // ------------------------------------------------------
2934
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2935

    
2936
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2937
            }
2938
            else {
2939
                if (name.compareToIgnoreCase(
2940
                            OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2941
                    resp = resp + rowInd + " , ";
2942
                }
2943
                else {
2944
                    Value attValue = feat.getAttribute(i);
2945

    
2946
                    if (attValue.toString() == null) {
2947
                        resp = resp + "NULL , ";
2948
                    }
2949
                    else {
2950
                        if (sur.length() > 0) {
2951
                            aux_orig = attValue.toString();
2952
                            aux_limited = cropStringValue(aux_orig, i,
2953
                                    fieldsDescr);
2954
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2955

    
2956
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2957
                        }
2958
                        else {
2959
                            String _aux = attValue.toString();
2960

    
2961
                            if (_aux.length() == 0) {
2962
                                _aux = "NULL";
2963
                            }
2964

    
2965
                            resp = resp + _aux + " , ";
2966
                        }
2967
                    }
2968
                }
2969
            }
2970
        }
2971

    
2972
        resp = resp + " ? )";
2973
        /*
2974
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
2975
                        + "2002, NULL, NULL,"
2976
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
2977
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
2978
                        + "), ? )";
2979

2980
        resp = resp + " " + test + " )";
2981
        */
2982
        return resp;
2983
    }
2984

    
2985
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
2986
            
2987
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
2988
                    return true;
2989
            }
2990
            
2991
            if ((ftype == Types.BINARY)
2992
                || (ftype == Types.ARRAY)
2993
                || (ftype == Types.BLOB)
2994
                || (ftype == Types.CLOB)
2995
                || (ftype == Types.STRUCT)
2996
            ) {
2997
                    return false;
2998
            }
2999
                return true;
3000
        }
3001

    
3002
        /**
3003
     * Gets the SQL sentence to perform an update.
3004
     *
3005
     * @param feat feature to be updated
3006
     * @param dbLayerDef layer definition
3007
     * @param rowInd row index
3008
     * @param geoFieldName geometry field name
3009
     * @return the SQL sentence to perform the update
3010
     */
3011
    public static String getRowUpdateSql(IFeature feat,
3012
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
3013
        String name = "";
3014
        String aux_orig = "";
3015
        String aux_limited = "";
3016
        String aux_quotes_ok = "";
3017

    
3018
        Value[] atts = feat.getAttributes();
3019
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
3020

    
3021
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
3022

    
3023
        for (int i = 0; i < _fieldsDescr.length; i++) {
3024
            name = _fieldsDescr[i].getFieldName();
3025

    
3026
            // -------------- FORBIDDEN FIELD NAMES -----------------
3027
            if (!isOracleAllowedFieldname(name)) {
3028
                logger.info("Field: " + name + " will not be updated.");
3029
                continue;
3030
            }
3031

    
3032
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
3033
                        geoFieldName)) {
3034
                logger.info("Field: " + name + " will not be updated (it's a struct).");
3035
                continue;
3036
            }
3037

    
3038
            // ------------------------------------------------------
3039
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
3040
                // resp = resp + "\"" + name + "\"" + " = ?, ";
3041
            }
3042
            else {
3043
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
3044
                aux_orig = atts[i].toString();
3045
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
3046
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
3047
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
3048
                    sur + ", ";
3049
            }
3050
        }
3051

    
3052
        resp = resp + "\"" + geoFieldName + "\" = ?";
3053
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
3054

    
3055
        return resp;
3056
    }
3057

    
3058
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
3059
        String geoname) {
3060
        if (ftype == Types.STRUCT) {
3061
            if (fldname.compareToIgnoreCase(geoname) != 0) {
3062
                return true;
3063
            }
3064
        }
3065

    
3066
        return false;
3067
    }
3068

    
3069
    /**
3070
     * Gets the SQL sentence to perform a deletion.
3071
     *
3072
     * @param dbLayerDef layer definition
3073
     * @param id ROWID of the record to be deleted
3074
     * @return the SQL sentence to perform the deletion
3075
     */
3076
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
3077
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
3078
        resp = resp + " WHERE ROWID ='" + id + "'";
3079

    
3080
        return resp;
3081
    }
3082

    
3083
    private static String cropStringValue(String orig_val, int i,
3084
        FieldDescription[] _flds) {
3085
        if (orig_val == null) {
3086
            return "NULL";
3087
        }
3088

    
3089
        int tpe = _flds[i].getFieldType();
3090
        int max_size = maxSizeForFieldType(tpe);
3091

    
3092
        if (max_size == -1) {
3093
            return orig_val;
3094
        }
3095

    
3096
        int or_size = orig_val.length();
3097

    
3098
        if (or_size <= max_size) {
3099
            return orig_val;
3100
        }
3101

    
3102
        return orig_val.substring(0, max_size);
3103
    }
3104

    
3105
    private static String avoidQuoteProblem(String str) {
3106
        return str.replaceAll("'", "''");
3107
    }
3108

    
3109
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3110
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3111
            return "";
3112
        }
3113

    
3114
        return "'";
3115
    }
3116

    
3117
    /**
3118
     * Utility function to translate a SRS code from EPSG to Oracle.
3119
     * Uses a datasource based on a DBF file.
3120
     *
3121
     * @param epsg the EPSG code
3122
     * @return the Oracle code
3123
     */
3124
    public static String epsgSridToOracleSrid(String epsg) throws Exception {
3125
        String resp = "8307";
3126

    
3127
        // --------------------------------------------
3128
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3129
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3130
        DataSource ds = null;
3131

    
3132
        try {
3133
            ds = LayerFactory.getDataSourceFactory()
3134
                             .executeSQL(sql,
3135
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3136

    
3137
            if (ds.getRowCount() == 0) {
3138
                logger.error("EPSG code not found in table: " + epsg);
3139
                throw new Exception("Unknown EPSG: " + epsg);
3140
            }
3141

    
3142
            if (ds.getRowCount() > 1) {
3143
                logger.error("===============");
3144
                logger.error(
3145
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
3146
                    epsg);
3147

    
3148
                for (int i = 0; i < ds.getRowCount(); i++) {
3149
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3150

    
3151
                    if (i == 0) {
3152
                        resp = "" + aux;
3153
                    }
3154

    
3155
                    logger.error("" + aux);
3156
                }
3157

    
3158
                logger.error("===============");
3159

    
3160
                return resp;
3161
            }
3162

    
3163
            resp = "" +
3164
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3165
        }
3166
        catch (Exception pe) {
3167
            logger.error("Error with SQL statement. " + pe.getMessage());
3168
        }
3169

    
3170
        return resp;
3171
    }
3172

    
3173
    /**
3174
     * Utility function to translate a SRS code from Oracle to EPSG.
3175
     * Uses a datasource based on a DBF file.
3176
     *
3177
     * @param ora the Oracle code
3178
     * @return the EPSG code
3179
     */
3180
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3181
        String resp = "4326";
3182

    
3183
        // --------------------------------------------
3184
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3185
            " where ORACLE = " + ora + ";";
3186
        DataSource ds = null;
3187

    
3188
        try {
3189
            ds = LayerFactory.getDataSourceFactory()
3190
                             .executeSQL(sql,
3191
                    DataSourceFactory.AUTOMATIC_OPENING);
3192

    
3193
            if (ds.getRowCount() == 0) {
3194
                logger.error("Oracle Spatial code not found in table: " + ora);
3195
                throw new Exception("Unknown Oracle code: " + ora);
3196
            }
3197

    
3198
            if (ds.getRowCount() > 1) {
3199
                logger.error("===============");
3200
                logger.error(
3201
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3202
                    ora);
3203

    
3204
                for (int i = 0; i < ds.getRowCount(); i++) {
3205
                    String aux = "" +
3206
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3207

    
3208
                    if (i == 0) {
3209
                        resp = aux;
3210
                    }
3211

    
3212
                    logger.error("" + aux);
3213
                }
3214

    
3215
                logger.error("===============");
3216

    
3217
                return resp;
3218
            }
3219

    
3220
            resp = "" +
3221
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3222
        }
3223
        catch (Exception pe) {
3224
            logger.error("Error with SQL statement. " + pe.getMessage());
3225
        }
3226

    
3227
        return resp;
3228
    }
3229

    
3230
    /**
3231
     * This methos creates the datasource used to translate the SRS codes:
3232
     * EPSG <--> Oracle.
3233
     *
3234
     * It's called from several places, so checks that the datasource does not exist.
3235
     */
3236

    
3237

    
3238
    /**
3239
     * Utility method to get a valid Oracle identifier (in terms of length)
3240
     *
3241
     * @param str Proposed string
3242
     * @param ind field index of the given field name (used by the method to
3243
     * improve the renaming)
3244
     * @return an acceptable oracle identifier.
3245
     */
3246
    public static String getValidOracleID(String str, int ind) {
3247
        if (str.length() <= MAX_ID_LENGTH) {
3248
            return str;
3249
        }
3250

    
3251
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3252
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3253
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3254
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3255
        resp = resp + "_" + (ind % 1000);
3256

    
3257
        return resp;
3258
    }
3259

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

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

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

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

    
3278
                return resp;
3279
            }
3280

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

    
3284
                return ensureSensibleShell(cc);
3285
            }
3286

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

    
3292
            return cc;
3293
        }
3294
    }
3295

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

    
3303
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3304
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3305
                resp.add(newcoo);
3306

    
3307
                newcoo = new Coordinate((Coordinate) cc.get(0));
3308
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3309
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3310
                resp.add(newcoo);
3311

    
3312
                resp.add(cc.get(0));
3313

    
3314
                return resp;
3315
            }
3316

    
3317
            if (cc.size() == 3) {
3318
                cc.remove(1);
3319

    
3320
                return ensureSensibleHole(cc);
3321
            }
3322

    
3323
            return cc;
3324
        }
3325
        else {
3326
            cc.add(cc.get(0));
3327

    
3328
            return cc;
3329
        }
3330
    }
3331

    
3332
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
3333
        if (cc.size() == 2) {
3334
            if (sameCoordinate((Coordinate) cc.get(0),
3335
                        (Coordinate) cc.get(cc.size() - 1))) {
3336
                ArrayList resp = new ArrayList();
3337
                resp.add(cc.get(0));
3338

    
3339
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3340
                newc.x = newc.x + IRRELEVANT_DISTANCE;
3341
                resp.add(newc);
3342

    
3343
                return resp;
3344
            }
3345
        }
3346

    
3347
        return cc;
3348
    }
3349

    
3350
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3351
        if (c1.x != c2.x) {
3352
            return false;
3353
        }
3354

    
3355
        if (c1.y != c2.y) {
3356
            return false;
3357
        }
3358

    
3359
        return true;
3360
    }
3361

    
3362
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3363
        if (cc.size() == 2) {
3364
            return null;
3365
        }
3366

    
3367
        if (cc.size() == 3) {
3368
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3369
                return null;
3370
            }
3371

    
3372
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3373
                return null;
3374
            }
3375

    
3376
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3377
                return null;
3378
            }
3379

    
3380
            cc.add(cc.get(0));
3381

    
3382
            return cc;
3383
        }
3384

    
3385
        if (!sameCoordinate((Coordinate) cc.get(0),
3386
                    (Coordinate) cc.get(cc.size() - 1))) {
3387
            cc.add(cc.get(0));
3388
        }
3389

    
3390
        return cc;
3391
    }
3392

    
3393
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3394
        Coordinate[] p = new Coordinate[4];
3395
        p[0] = c;
3396

    
3397
        Coordinate nc = new Coordinate(c);
3398
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3399

    
3400
        Coordinate nc2 = new Coordinate(nc);
3401
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3402
        p[1] = nc;
3403
        p[2] = nc2;
3404
        p[3] = new Coordinate(c);
3405

    
3406
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3407
        LinearRing ls = new LinearRing(cs, geomFactory);
3408
        Polygon po = new Polygon(ls, null, geomFactory);
3409
        Polygon[] pos = new Polygon[1];
3410
        pos[0] = po;
3411

    
3412
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3413

    
3414
        return mpo;
3415
    }
3416

    
3417
    public String getSourceProjection() {
3418
        // TODO Auto-generated method stub
3419
        if (tableHasSrid) {
3420
            return epsgSRID;
3421
        }
3422

    
3423
        return destProj;
3424
    }
3425

    
3426
    public String getDestProjection() {
3427
        return destProj;
3428
    }
3429

    
3430
    public void setDestProjection(String toEPSG) {
3431
        destProj = toEPSG;
3432
        try {
3433
                        destProjOracle = epsgSridToOracleSrid(destProj);
3434
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3435
                        
3436
                } catch (Exception e) {
3437
                        logger.error("Unknown EPSG code: " + destProj);
3438
                        destProjOracle = oracleSRID;
3439
                        isDestGeogCS = false;
3440
                }
3441
        
3442
    }
3443
    
3444
    public String getDestProjectionOracleCode() {
3445
            return destProjOracle;
3446
    }
3447
    
3448
    public boolean getIsDestProjectionGeog() {
3449
            return isDestGeogCS;
3450
    }
3451
    
3452
    public String getTableProjectionOracleCode() {
3453
            return oracleSRID;
3454
    }
3455

    
3456
    public boolean canReproject(String toEPSGdestinyProjection) {
3457
        return false;
3458
    }
3459

    
3460
    /**
3461
     * Utility function. Says whether a given field name can be a user field name
3462
     * or not (for example, "ROWID" is not a valid one because it's a system
3463
     * reserved word).
3464
     *
3465
     * @param str proposed firld name
3466
     * @return whether it is valid or not for Oracle databases
3467
     */
3468
    private static boolean isOracleAllowedFieldname(String str) {
3469
        if (str.compareToIgnoreCase("rowid") == 0) {
3470
            return false;
3471
        }
3472

    
3473
        if (str.compareToIgnoreCase("rownum") == 0) {
3474
            return false;
3475
        }
3476

    
3477
        return true;
3478
    }
3479

    
3480
    public Hashtable getHashRelate() {
3481
        return hashRelate;
3482
    }
3483

    
3484
    public void setHashRelate(Hashtable m) {
3485
        hashRelate = m;
3486
    }
3487

    
3488
    public void setNumReg(int n) {
3489
        numReg = n;
3490
    }
3491

    
3492
    private int[] getRandomSample(int maxn_one_based, int n) {
3493
        int[] resp = new int[n];
3494

    
3495
        if (maxn_one_based <= n) {
3496
            resp = new int[maxn_one_based];
3497

    
3498
            for (int i = 0; i < maxn_one_based; i++) {
3499
                resp[i] = i;
3500
            }
3501
        }
3502
        else {
3503
            Random rnd = new Random();
3504

    
3505
            for (int i = 0; i < n; i++) {
3506
                resp[i] = rnd.nextInt(maxn_one_based);
3507
            }
3508
        }
3509

    
3510
        return resp;
3511
    }
3512

    
3513
    private String getRowIdRestrictionCondition(int nrecords) {
3514
        int[] zero_based_rows = getRandomSample(nrecords,
3515
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3516
        String resp = "(";
3517
        Object aux = "";
3518
        ROWID riaux = null;
3519

    
3520
        for (int i = 0; i < zero_based_rows.length; i++) {
3521
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3522
            riaux = (ROWID) aux;
3523
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3524
        }
3525

    
3526
        resp = resp.substring(0, resp.length() - 4);
3527
        resp = resp + ")";
3528

    
3529
        return resp;
3530
    }
3531

    
3532
    private Rectangle2D getBoundingFromSample(int n_max) {
3533
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3534
            " WHERE " + getRowIdRestrictionCondition(n_max);
3535
        STRUCT auxstr = null;
3536
        IGeometry theGeom = null;
3537
        Rectangle2D resp = null;
3538

    
3539
        try {
3540
            Statement st = conn.createStatement();
3541
            ResultSet rs = st.executeQuery(_qry);
3542

    
3543
            if (rs.next()) {
3544
                auxstr = (STRUCT) rs.getObject(1);
3545

    
3546
                if (auxstr != null) {
3547
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3548

    
3549
                    if (resp == null) {
3550
                        resp = theGeom.getBounds2D();
3551
                    }
3552
                    else {
3553
                        resp.add(theGeom.getBounds2D());
3554
                    }
3555
                }
3556

    
3557
                while (rs.next()) {
3558
                    auxstr = (STRUCT) rs.getObject(1);
3559

    
3560
                    if (auxstr != null) {
3561
                        theGeom = getGeometryUsing(auxstr, use_geotools);
3562

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

    
3572
                rs.close();
3573
                st.close();
3574
            }
3575
            else {
3576
                throw new SQLException("Empty resultset from this query: " +
3577
                    _qry);
3578
            }
3579
        }
3580
        catch (SQLException se) {
3581
            System.err.println("Error while getting sample full extent: " +
3582
                se.getMessage());
3583
        }
3584

    
3585
        if (resp == null) {
3586
            logger.warn(
3587
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3588

    
3589
            return new Rectangle2D.Double(-180, -90, 360, 180);
3590
        }
3591

    
3592
        return resp;
3593
    }
3594

    
3595
    /**
3596
     * Does what it says, puts the LinearRing in counter clock wise
3597
     * order.
3598
     * @param ls The ring to set.
3599
     * @param gf a GeometryFactory object
3600
     * @return A new ring in CCW order.
3601
     *
3602
     */
3603
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3604
        Coordinate[] cc = ls.getCoordinates();
3605

    
3606
        if (CGAlgorithms.isCCW(cc)) {
3607
            return gf.createLinearRing(cc);
3608
        }
3609
        else {
3610
            if (ls instanceof LinearRing) {
3611
                return reverseRing((LinearRing) ls, gf);
3612
            }
3613
            else {
3614
                return reverseLineString(ls, gf);
3615
            }
3616
        }
3617
    }
3618

    
3619
    /**
3620
     * Does what it says, reverses the order of the Coordinates in the ring.
3621
     * @param lr The ring to reverse.
3622
     * @return A new ring with the reversed Coordinates.
3623
     *
3624
     */
3625
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3626
        int numPoints = lr.getNumPoints() - 1;
3627
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3628

    
3629
        for (int t = numPoints; t >= 0; t--) {
3630
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3631
        }
3632

    
3633
        return gf.createLinearRing(newCoords);
3634
    }
3635

    
3636
    /**
3637
     * Does what it says, reverses the order of the Coordinates in the linestring.
3638
     * @param ls The ls to reverse.
3639
     * @param gf a GeometryFactory object 
3640
     * @return A new ls with the reversed Coordinates.
3641
     *
3642
     */
3643
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3644
        int numPoints = ls.getNumPoints() - 1;
3645
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3646

    
3647
        for (int t = numPoints; t >= 0; t--) {
3648
            newCoords[t] = ls.getCoordinateN(numPoints - t);
3649
        }
3650

    
3651
        return gf.createLinearRing(newCoords);
3652
    }
3653

    
3654
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3655
        if (ge instanceof MultiPolygon) {
3656
            MultiPolygon mp = (MultiPolygon) ge;
3657
            int size = ge.getNumGeometries();
3658
            Polygon[] pols = new Polygon[size];
3659

    
3660
            for (int i = 0; i < size; i++)
3661
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3662
                        gf);
3663

    
3664
            return new MultiPolygon(pols, gf);
3665
        }
3666
        else {
3667
            if (ge instanceof Polygon) {
3668
                Polygon p = (Polygon) ge;
3669
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3670
                int nholes = p.getNumInteriorRing();
3671

    
3672
                if (nholes > 0) {
3673
                    LinearRing[] holes = new LinearRing[nholes];
3674

    
3675
                    for (int i = 0; i < nholes; i++) {
3676
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3677
                    }
3678

    
3679
                    return gf.createPolygon(exterior, holes);
3680
                }
3681
                else {
3682
                    return gf.createPolygon(exterior, null);
3683
                }
3684
            }
3685
            else {
3686
                return ge;
3687
            }
3688
        }
3689
    }
3690

    
3691
    /**
3692
     * Converts from IGeometry to STRUCT
3693
     *
3694
     * @param ig the geometry to convert
3695
     * @param _forced_type forced type to use
3696
     * @param _conn connection
3697
     * @param _o_srid  SRS (oracle code)
3698
     * @param withSrid whether this STRUCT has a non-NULL SRS
3699
     * @param agu_bien whether or not to check the correctness of the holes
3700
     * @param _isGeoCS whether the SRS is geodetic or not
3701
     * @return the generated STRUCT
3702
     */
3703
    public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
3704
        Connection _conn, String _o_srid, boolean withSrid, boolean agu_bien,
3705
        boolean _isGeoCS) {
3706
        if (ig instanceof FGeometryCollection) {
3707
            FGeometryCollection coll = (FGeometryCollection) ig;
3708

    
3709
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3710
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3711

    
3712
            // logger.error("Collections no soportadas por ahora.");
3713
            // return null;
3714
        }
3715
        else {
3716
            Shape shp = ig.getInternalShape();
3717

    
3718
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3719
                agu_bien, false, _isGeoCS);
3720
        }
3721
    }
3722

    
3723
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3724
        boolean agu_bien, boolean isView) {
3725
            
3726
            if (shp == null) return null; 
3727
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3728
            agu_bien, isView, isGeogCS);
3729
    }
3730

    
3731
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3732
        Connection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3733
        boolean isView, boolean _isGeoCS) {
3734
        int _srid = -1;
3735

    
3736
        if (o_srid.length() > 0) {
3737
            _srid = Integer.parseInt(o_srid);
3738
        }
3739

    
3740
        if (shp == null) {
3741
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3742

    
3743
            return null;
3744
        }
3745

    
3746
        if (shp instanceof Rectangle2D) {
3747
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3748
                _isGeoCS, o_srid, _conn);
3749
        }
3750

    
3751
        try {
3752
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3753
                    _srid, agu_bien, hasSrid);
3754

    
3755
            return the_struct;
3756
        }
3757
        catch (SQLException ex) {
3758
            logger.error("While creating STRUCT: " + ex.getMessage());
3759

    
3760
            return null;
3761
        }
3762
    }
3763

    
3764
    // -------------------------- not ready yet ----------------
3765
    public int getRowIndexByFID(IFeature _fid) {
3766
        if (isNotAvailableYet) {
3767
            return -1;
3768
        }
3769
        else {
3770
            return super.getRowIndexByFID(_fid);
3771
        }
3772
    }
3773

    
3774
    public int getShapeCount() throws IOException {
3775
        if (isNotAvailableYet) {
3776
            return 0;
3777
        }
3778
        else {
3779
            return numReg;
3780
        }
3781
    }
3782

    
3783
    public void setNotAvailableYet(boolean nav) {
3784
        isNotAvailableYet = nav;
3785
    }
3786

    
3787
    // -------------------------------------------------------
3788
    // -------------------------------------------------------
3789
    public String[] getTableNames(Connection conn, String catalog)
3790
        throws SQLException {
3791
        DatabaseMetaData dbmd = conn.getMetaData();
3792
        String[] types = { "TABLE", "VIEW" };
3793
        // String[] types = { "VIEW" };
3794

    
3795
        ResultSet rs = null;
3796
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3797
                    ORACLE_GEOMETADATA_VIEW, types), conn);
3798
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3799
//                          ORACLE_GEOMETADATA_VIEW, types);
3800
        TreeMap ret = new TreeMap();
3801

    
3802
        while (rs.next()) {
3803
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
3804
            ret.put(nomCompleto, nomCompleto);
3805
        }
3806

    
3807
        return (String[]) ret.keySet().toArray(new String[0]);
3808
    }
3809

    
3810
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3811
        throws SQLException {
3812
        String tablename = "";
3813
        
3814
        
3815

    
3816
        if (res.next()) {
3817
            tablename = res.getString("TABLE_NAME");
3818
            
3819
            // debug 
3820
            writeMetaTableToLog(con, tablename);
3821

    
3822
            Statement __st = con.createStatement();
3823

    
3824
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3825
                "union (select VIEW_NAME from USER_VIEWS)) " +
3826
                "intersect (select TABLE_NAME from " + tablename + ")";
3827
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
3828
            ResultSet rs = __st.executeQuery(sql);
3829

    
3830
            return rs;
3831
        }
3832
        else {
3833
            logger.error("Error while getting geometry tables.");
3834

    
3835
            return null;
3836
        }
3837
    }
3838

    
3839
    private void writeMetaTableToLog(Connection con, String tname) {
3840
            
3841
            logger.debug("======================================================");
3842
            logger.debug("=     " + ORACLE_GEOMETADATA_VIEW + "     =====================");
3843
            logger.debug("======================================================");
3844

    
3845
            try {
3846
            Statement _stmt = con.createStatement();
3847
            String sql = "SELECT * FROM " + tname;
3848
            ResultSet res = _stmt.executeQuery(sql);
3849
            while (res.next()) {
3850
                    logger.debug("======================================================");
3851
                    logger.debug("OWNER: " + res.getString("OWNER"));
3852
                    logger.debug("TABLE_NAME: " + res.getString("TABLE_NAME"));
3853
                    logger.debug("COLUMN_NAME: " + res.getString("COLUMN_NAME"));
3854
                    logger.debug("SRID: " + res.getString("SRID"));
3855
                    
3856
                    ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3857
                    String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3858
                    logger.debug("DIMINFO: " + dinfo);
3859
                    logger.debug("======================================================");
3860
                    
3861
            }
3862
            } catch (Throwable th) {
3863
                    
3864
            }
3865
            
3866
            
3867
            
3868
            
3869
            
3870
                // TODO Auto-generated method stub
3871
                
3872
        }
3873

    
3874
        /**
3875
     * Gets the field names that can act as row id (always ROWID)
3876
     */
3877
    public String[] getIdFieldsCandidates(Connection conn, String table_name)
3878
        throws SQLException {
3879
            
3880
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
3881
            Statement _st = conn.createStatement();
3882
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3883
            _rs.close();
3884
            _st.close();
3885

    
3886
            String[] resp = { "ROWID" };
3887
        return resp;
3888
    }
3889

    
3890
    /**
3891
     * Gets the field names that can act as geometry fields
3892
     * (queries the user's geographic metadata).
3893
     */
3894
    public String[] getGeometryFieldsCandidates(Connection conn,
3895
        String table_name) throws SQLException {
3896
            
3897
        Statement _st = conn.createStatement();
3898
        String[] tokens = table_name.split("\\u002E", 2);
3899
        String qry;
3900
        if (tokens.length > 1)
3901
        {
3902
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3903
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" + 
3904
            tokens[1] + "'";
3905
        }
3906
        else
3907
        {
3908
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3909
            " where TABLE_NAME = " + "'" + table_name + "'";
3910

    
3911
        }
3912
        ResultSet _rs = _st.executeQuery(qry);
3913

    
3914
        ArrayList aux = new ArrayList();
3915

    
3916
        while (_rs.next()) {
3917
            String _geo = _rs.getString("COLUMN_NAME");
3918
            aux.add(_geo);
3919
        }
3920

    
3921
        _rs.close();
3922
        _st.close();
3923

    
3924
        String[] resp = (String[]) aux.toArray(new String[0]); 
3925
        
3926
        return checkIndexes(conn, resp, table_name);
3927
    }
3928

    
3929
    private String[] checkIndexes(Connection c, String[] all, String __t) throws SQLException {
3930

    
3931
            ArrayList good_ones = new ArrayList();
3932
            String t = __t;
3933
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
3934

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

    
3967
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
3968
            String p = getPointConstructor(dims, _srid);
3969
            String qry = "SELECT * FROM " + _t.toUpperCase() + " WHERE (ROWNUM = 1)";
3970
            qry = "SELECT * FROM (" + qry + ") WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'";
3971

    
3972
            try {
3973
                        Statement _st = c.createStatement();
3974
                        ResultSet _rs = _st.executeQuery(qry);
3975
                        _rs.close();
3976
                        _st.close();
3977
                } catch (Exception ex) {
3978
                        return false;
3979
                }
3980
                return true;
3981
        }
3982

    
3983
        private String getPointConstructor(int dims, String _srid) {
3984
                
3985
                String coord = "";
3986
                for (int i=0; i<dims; i++) coord = coord + "0, ";
3987
                coord = coord.substring(0, coord.length() - 2);
3988
                
3989
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
3990
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
3991
        }
3992

    
3993
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
3994
            
3995
            if (l == null) return false;
3996
            if (str == null) return false;
3997
            
3998
            String item = "";
3999
            for (int i=0; i<l.size(); i++) {
4000
                    if (l.get(i) instanceof String) {
4001
                            item = (String) l.get(i);
4002
                            if (item.compareToIgnoreCase(str) == 0) return true;
4003
                    }
4004
            }
4005
            return false;
4006
    }
4007

    
4008
        /**
4009
     * Utility method to check if a given table is empty.
4010
     */
4011
    public boolean isEmptyTable(Connection conn, String tableName) {
4012
        boolean res = true;
4013

    
4014
        try {
4015
            Statement st = conn.createStatement();
4016
            ResultSet rs = null;
4017
            rs = st.executeQuery("select * from " + tableName +
4018
                    " where rownum = 1");
4019
            res = !rs.next();
4020
            rs.close();
4021
            st.close();
4022
        }
4023
        catch (Exception ex) {
4024
            res = true;
4025
        }
4026

    
4027
        return res;
4028
    }
4029

    
4030
    /**
4031
     * Gets all the fields from a table name.
4032
     */
4033
    public String[] getAllFields(Connection conn, String table_name)
4034
        throws SQLException {
4035
        Statement st = conn.createStatement();
4036
        ResultSet rs = st.executeQuery("select * from " + table_name +
4037
                " where rownum = 1");
4038
        ResultSetMetaData rsmd = rs.getMetaData();
4039
        String[] ret = new String[rsmd.getColumnCount()];
4040

    
4041
        for (int i = 0; i < ret.length; i++) {
4042
            ret[i] = rsmd.getColumnName(i + 1);
4043
        }
4044

    
4045
        rs.close();
4046
        st.close();
4047

    
4048
        return ret;
4049
    }
4050

    
4051
    /**
4052
     * Gets all field type names from a table.
4053
     */
4054
    public String[] getAllFieldTypeNames(Connection conn, String table_name)
4055
        throws SQLException {
4056
        Statement st = conn.createStatement();
4057
        ResultSet rs = st.executeQuery("select * from " + table_name +
4058
                " where rownum = 1");
4059
        ResultSetMetaData rsmd = rs.getMetaData();
4060
        String[] ret = new String[rsmd.getColumnCount()];
4061

    
4062
        for (int i = 0; i < ret.length; i++) {
4063
            ret[i] = rsmd.getColumnTypeName(i + 1);
4064
        }
4065

    
4066
        rs.close();
4067
        st.close();
4068

    
4069
        close();
4070

    
4071
        return ret;
4072
    }
4073

    
4074
    /**
4075
     * Gets Oracle's specific connection string for the given parameters.
4076
     */
4077
    public String getConnectionString(String host, String port, String dbname,
4078
        String user, String pw) {
4079
        String _pw = pw;
4080

    
4081
        if (_pw == null) {
4082
            _pw = "null";
4083
        }
4084

    
4085
        String fullstr = CONN_STR_BEGIN;
4086
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
4087
        fullstr = fullstr + "@" + host.toLowerCase();
4088
        fullstr = fullstr + ":" + port;
4089
        fullstr = fullstr + ":" + dbname.toLowerCase();
4090

    
4091
        return fullstr;
4092
    }
4093

    
4094
    /**
4095
     * Gets the Pracle geometries writer associated with this driver.
4096
     */
4097
    public IWriter getWriter() {
4098
        // on(VectorialEditableDBAdapter.java:290)
4099
        if (writer == null) {
4100
            writer = new OracleSpatialWriter(getRowCount());
4101
            writer.setDriver(this);
4102
            writer.setLyrShapeType(getShapeType());
4103
            writer.setGeoCS(isGeogCS());
4104
            writer.setGeoColName(geoColName);
4105
            writer.setSRID(oracleSRID);
4106

    
4107
            try {
4108
                writer.initialize(getLyrDef());
4109
            }
4110
            catch (EditionException e) {
4111
                logger.error("While initializing OS Writer: " + e.getMessage(),
4112
                    e);
4113
            }
4114

    
4115
            writer.setStoreWithSrid(tableHasSrid);
4116
        }
4117

    
4118
        return writer;
4119
    }
4120

    
4121
    /**
4122
     * Tells whether the SRS is geodetic or not
4123
     * @return whether the SRS is geodetic or not
4124
     */
4125
    public boolean isGeogCS() {
4126
        return isGeogCS;
4127
    }
4128

    
4129
    /**
4130
     * Adds a row id to the inner set od IDs.
4131
     * @param id
4132
     */
4133
    public void addRow(String id) {
4134
        Value aux = ValueFactory.createValue(id);
4135
        Integer intobj = new Integer(numReg);
4136
        hashRelate.put(aux, intobj);
4137
        rowToId.put(intobj, id);
4138

    
4139
        numReg++;
4140
    }
4141

    
4142
    /**
4143
     * Removes a row id to the inner set od IDs.
4144
     * @param id
4145
     */
4146
    public void deleteRow(String id) {
4147
        Value aux = ValueFactory.createValue(id);
4148
        Integer intobj = (Integer) hashRelate.get(aux);
4149
        hashRelate.remove(aux);
4150
        rowToId.remove(intobj);
4151

    
4152
        numReg--;
4153
    }
4154

    
4155
    private String getStandardSelectExpression() {
4156
        if (standardSelectExpressionFalse == null) {
4157
            standardSelectExpressionFalse = "";
4158

    
4159
            String[] flds = getLyrDef().getFieldNames();
4160
            int size = flds.length;
4161

    
4162
            for (int i = 0; i < size; i++) {
4163
                if (i > 0) {
4164
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4165
                        "c.\"" + flds[i] + "\", ";
4166
                }
4167
                else {
4168
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4169
                        flds[i] + ", ";
4170
                }
4171
            }
4172

    
4173
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4174
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4175
                    standardSelectExpressionFalse.length() - 2);
4176
        }
4177

    
4178
        return standardSelectExpressionFalse;
4179
    }
4180

    
4181
    /**
4182
     * Allows the method to decide what to do with the geometry field name
4183
     * (remove/add it from the user selected fields).
4184
     *
4185
     * @param flds
4186
     * @param geof
4187
     * @return the possibly modified field names
4188
     */
4189
    public String[] manageGeometryField(String[] flds, String geof) {
4190
        return addEndIfNotContained(flds, geof);
4191
    }
4192

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

    
4205
    private String[] addEndIfNotContained(String[] arr, String item) {
4206
        if (contains(arr, item)) {
4207
            return arr;
4208
        }
4209
        else {
4210
            int size = arr.length;
4211
            String[] resp = new String[size + 1];
4212

    
4213
            for (int i = 0; i < size; i++) {
4214
                resp[i] = arr[i];
4215
            }
4216

    
4217
            resp[size] = item;
4218

    
4219
            return resp;
4220
        }
4221
    }
4222

    
4223
    private String[] addStartIfNotContained(String[] arr, String item) {
4224
        if (contains(arr, item)) {
4225
            return arr;
4226
        }
4227
        else {
4228
            int size = arr.length;
4229
            String[] resp = new String[size + 1];
4230

    
4231
            for (int i = 1; i <= size; i++) {
4232
                resp[i] = arr[i];
4233
            }
4234

    
4235
            resp[0] = item;
4236

    
4237
            return resp;
4238
        }
4239
    }
4240

    
4241
    private boolean contains(String[] arr, String item) {
4242
        for (int i = 0; i < arr.length; i++) {
4243
            if (arr[i].compareTo(item) == 0) {
4244
                return true;
4245
            }
4246
        }
4247

    
4248
        return false;
4249
    }
4250

    
4251
    /**
4252
     * This method is called when the user removes the layer from the view.
4253
     * If the IDs were being loaded, the driver will check this field and will
4254
     * let the thread 'die' quietly.
4255
     *
4256
     */
4257
    public void remove() {
4258
        cancelIDLoad = true;
4259
    }
4260
    
4261
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4262
            // if (!isgeodetic) return true;
4263
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true; 
4264
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true; 
4265
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true; 
4266
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true; 
4267
            return false;
4268
    }
4269
    
4270
    private Rectangle2D getFastEstimatedGeodeticExtent(
4271
                    String tname, String gfield, Connection c, int sample_size, double enlargement) {
4272

    
4273
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4274
            Rectangle2D resp_aux = null;
4275
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4276
            ResultSet _rs = null;
4277

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

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

    
4395
    public static final int JGeometry_GTYPE_COLLECTION = 4;
4396
    public static final int JGeometry_GTYPE_CURVE = 2;
4397
    public static final int JGeometry_GTYPE_MULTICURVE = 6;
4398
    public static final int JGeometry_GTYPE_MULTIPOINT = 5;
4399
    public static final int JGeometry_GTYPE_MULTIPOLYGON = 7;
4400
    public static final int JGeometry_GTYPE_POINT = 1;
4401
    public static final int JGeometry_GTYPE_POLYGON = 3;
4402

    
4403
}