Statistics
| Revision:

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

History | View | Annotate | Download (128 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 Prodevelop and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *   Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *   +34 963862235
28
 *   gvsig@gva.es
29
 *   www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   Prodevelop Integraci?n de Tecnolog?as SL
34
 *   Conde Salvatierra de ?lava , 34-10
35
 *   46004 Valencia
36
 *   Spain
37
 *
38
 *   +34 963 510 612
39
 *   +34 963 510 968
40
 *   gis@prodevelop.es
41
 *   http://www.prodevelop.es
42
 */
43
package es.prodevelop.cit.gvsig.fmap.drivers.jdbc.oracle;
44

    
45
import com.hardcode.driverManager.IDelayedDriver;
46

    
47
import com.hardcode.gdbms.engine.data.DataSource;
48
import com.hardcode.gdbms.engine.data.DataSourceFactory;
49
import com.hardcode.gdbms.engine.data.SourceInfo;
50
import com.hardcode.gdbms.engine.data.edition.DataWare;
51
import com.hardcode.gdbms.engine.data.file.FileSourceInfo;
52
import com.hardcode.gdbms.engine.spatial.fmap.FShapeGeneralPathX;
53
import com.hardcode.gdbms.engine.values.DoubleValue;
54
import com.hardcode.gdbms.engine.values.Value;
55
import com.hardcode.gdbms.engine.values.ValueFactory;
56

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

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

    
99
import oracle.jdbc.OracleConnection;
100

    
101
import oracle.spatial.geometry.JGeometry;
102

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

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

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

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

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

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

    
133
import java.text.ParseException;
134

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

    
142

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

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

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

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

    
198
    private OracleSpatialWriter writer = null;
199

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
304
        setLyrDef(lyrDef);
305

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

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

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

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

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

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

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

    
364

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

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

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

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

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

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

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

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

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

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

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

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

    
417
        return false;
418
    }
419

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

    
425
        HashMap m = new HashMap();
426

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

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

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

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

    
441
        return iter.hasNext();
442
    }
443

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

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

    
452
            return ASSUMED_ORACLE_SRID;
453
        }
454

    
455
        return obj.toString();
456
    }
457

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

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

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

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

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

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

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

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

    
498
                return null;
499

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

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

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

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

    
529
                isGeogCS = getIsGCS(oracleSRID, tableHasSrid);
530

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

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

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

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

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

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

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

    
592
        return resp;
593
    }
594

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

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

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

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

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

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

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

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

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

    
632
            getIdFieldNames();
633

    
634
            adjustLyrDef();
635

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

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

    
650
        case 2:
651
            return FShape.LINE;
652

    
653
        case 3:
654
            return FShape.POLYGON;
655

    
656
        case 4:
657
            return FShape.MULTI;
658

    
659
        case 5:
660
            return FShape.MULTIPOINT;
661

    
662
        case 6:
663
            return FShape.LINE;
664

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

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

    
671
        return FShape.NULL;
672
    }
673

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

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

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

    
688
        return idFieldNames;
689
    }
690

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

    
695
        return _res;
696
    }
697

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

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

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

    
718
        singleCachedFeatureRowNum = -1;
719

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

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

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

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

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

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

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

    
758
        singleCachedFeatureRowNum = -1;
759

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

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

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

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

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

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

    
786
        singleCachedFeatureRowNum = -1;
787

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

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

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

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

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

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

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

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

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

    
823
            ResultSet _res = ps.getResultSet();
824

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

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

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

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

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

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

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

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

    
865
        java.sql.PreparedStatement ps = null;
866

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

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

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

    
883
            ROWID ri = null;
884

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

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

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

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

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

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

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

    
916
                        return;
917
                    }
918

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

    
924
                row++;
925

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

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

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

    
942
                // --------------------------------------- types end
943
            }
944

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

    
950
            needsCollectionLayer = hasSeveralGeometryTypes(types, false);
951

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

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

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

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

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

    
989
        return strAux;
990
    }
991

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1068
        return -1;
1069
    }
1070

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

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

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

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

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

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

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

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

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

    
1138
            return null;
1139
        }
1140

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

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

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

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

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

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

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

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

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

    
1211
            return null;
1212
        }
1213

    
1214
        return res;
1215
    }
1216
    
1217

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

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

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

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

    
1238
        return i;
1239
    }
1240

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1335
        return _igeom;
1336
    }
1337

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

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

    
1348
        switch (jgtype) {
1349
        case JGeometry.GTYPE_COLLECTION:
1350

    
1351
            int srid = jg.getSRID();
1352
            ig = getFMapGeometryCollection(jg, dim, srid);
1353

    
1354
            break;
1355

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

    
1360
            break;
1361

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

    
1366
            break;
1367

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

    
1372
            break;
1373
        }
1374

    
1375
        return ig;
1376
    }
1377

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

    
1386
        Datum[] all_info_array = null;
1387
        Object[] elems_info_aray = null;
1388
        Datum[] all_ords = null;
1389

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

    
1404

    
1405
        for (int i = 0; i < elems_info_aray.length; i++) {
1406
            _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1407
        }
1408

    
1409
        // _elems_info_aray, ords_of_groups
1410
        int no_of_elems = ords_of_groups.length;
1411
        IGeometry[] geoms = new IGeometry[no_of_elems];
1412

    
1413
        for (int i = 0; i < no_of_elems; i++) {
1414
            Datum[] item_info_array = null;
1415
            Datum[] item_ords = null;
1416
            NUMBER gtype = null;
1417

    
1418
            try {
1419
                item_info_array = (Datum[]) _elems_info_aray[i];
1420
                item_ords = (Datum[]) ords_of_groups[i];
1421

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

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

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

    
1448
            geoms[i] = getFMapGeometry(itemst, true);
1449
        }
1450

    
1451
        return new FGeometryCollection(geoms);
1452
    }
1453

    
1454
    /**
1455
     * Utility method to transform a struct into a IGeometry.
1456
     *
1457
     * @param st the struct to be converted
1458
     * @param force_not_collection t5his parameter is currently ignored
1459
     * @return the IGeometry
1460
     */
1461
    public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1462
        Datum[] the_data = null;
1463

    
1464
        try {
1465
            the_data = st.getOracleAttributes();
1466

    
1467
            int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1468
            jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1469

    
1470
            int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1471

    
1472
            if (dim < 2) {
1473
                dim = 2;
1474
            }
1475

    
1476
            IGeometry ig = null;
1477

    
1478
            if (isActuallyACollection(the_data)) {
1479
                jgtype = FShape.MULTI;
1480
            }
1481

    
1482
            switch (jgtype) {
1483
            case FShape.MULTI:
1484

    
1485
                // int srid = ((NUMBER) the_data[1]).intValue();
1486
                ig = getFMapGeometryCollection(the_data, dim);
1487

    
1488
                break;
1489

    
1490
            case FShape.POINT:
1491
                ig = getFMapGeometryPoint(the_data, dim);
1492

    
1493
                break;
1494

    
1495
            case FShape.LINE:
1496
                ig = getFMapGeometryMultiLineString(the_data, dim);
1497

    
1498
                break;
1499

    
1500
            case FShape.POLYGON:
1501
                ig = getFMapGeometryMultipolygon(the_data, dim);
1502

    
1503
                break;
1504
            }
1505

    
1506
            return ig;
1507
        }
1508
        catch (SQLException e) {
1509
            logger.error(e);
1510
        }
1511

    
1512
        return null;
1513
    }
1514

    
1515
    private double[] getIndDoublesModule(double[] input, int ind, int n) {
1516
        int size = input.length / n;
1517
        double[] resp = new double[size];
1518

    
1519
        for (int i = 0; i < size; i++) {
1520
            resp[i] = input[(i * n) + ind];
1521
        }
1522

    
1523
        return resp;
1524
    }
1525

    
1526
    private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1527
        int size = input.length / n;
1528
        double[] resp = new double[size];
1529

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

    
1534
        return resp;
1535
    }
1536

    
1537
    private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1538
        IGeometry ig = null;
1539

    
1540
        if (jg.isCircle()) {
1541
            ig = getCircleFromJGeometry(jg);
1542
        }
1543
        else {
1544
            Shape shape = jg.createShape();
1545
            GeneralPathX gpx = new GeneralPathX(shape);
1546

    
1547
            if (dim == 2) {
1548
                ig = ShapeFactory.createPolygon2D(gpx);
1549
            }
1550
            else {
1551
                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1552
                ig = ShapeFactory.createPolygon3D(gpx, z);
1553
            }
1554
        }
1555

    
1556
        return ig;
1557
    }
1558

    
1559
    private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1560
        IGeometry ig = null;
1561

    
1562
        if (OracleSpatialUtils.isCircle(the_data)) {
1563
            ig = getCircleFromStruct(the_data);
1564
        }
1565
        else {
1566
            GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1567

    
1568
            if (dim == 2) {
1569
                ig = ShapeFactory.createPolygon2D(gpx);
1570
            }
1571
            else {
1572
                double[] ords = null;
1573

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

    
1582
                double[] z = getIndBigDecimalModule(ords, 2, dim);
1583
                ig = ShapeFactory.createPolygon3D(gpx, z);
1584
            }
1585
        }
1586

    
1587
        return ig;
1588
    }
1589

    
1590
    private IGeometry getCircleFromJGeometry(JGeometry jg) {
1591
        double[] threep = jg.getOrdinatesArray();
1592
        Point2D[] three = new Point2D.Double[3];
1593
        three[0] = new Point2D.Double(threep[0], threep[1]);
1594
        three[1] = new Point2D.Double(threep[2], threep[3]);
1595
        three[2] = new Point2D.Double(threep[4], threep[5]);
1596

    
1597
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1598

    
1599
        Point2D cent = (Point2D) cent_rad[0];
1600
        double radius = ((Double) cent_rad[1]).doubleValue();
1601

    
1602
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1603

    
1604
        return circ;
1605
    }
1606

    
1607
    private IGeometry getCircleFromStruct(Datum[] the_data) {
1608
        double[] threep = null;
1609

    
1610
        try {
1611
            threep = ((ARRAY) the_data[4]).getDoubleArray();
1612
        }
1613
        catch (SQLException se) {
1614
            logger.error("While getting ords from struct: " + se.getMessage(),
1615
                se);
1616

    
1617
            return new FNullGeometry();
1618
        }
1619

    
1620
        Point2D[] three = new Point2D.Double[3];
1621
        three[0] = new Point2D.Double(threep[0], threep[1]);
1622
        three[1] = new Point2D.Double(threep[2], threep[3]);
1623
        three[2] = new Point2D.Double(threep[4], threep[5]);
1624

    
1625
        Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1626

    
1627
        Point2D cent = (Point2D) cent_rad[0];
1628
        double radius = ((Double) cent_rad[1]).doubleValue();
1629

    
1630
        IGeometry circ = ShapeFactory.createCircle(cent, radius);
1631

    
1632
        return circ;
1633
    }
1634

    
1635
    private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1636
        Shape shape = jg.createShape();
1637
        GeneralPathX gpx = new GeneralPathX(shape);
1638
        IGeometry ig = null;
1639

    
1640
        if (dim == 2) {
1641
            ig = ShapeFactory.createPolyline2D(gpx);
1642
        }
1643
        else {
1644
            double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1645
            ig = ShapeFactory.createPolyline3D(gpx, z);
1646
        }
1647

    
1648
        return ig;
1649
    }
1650

    
1651
    private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1652
        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1653
        IGeometry ig = null;
1654
        double[] ords = null;
1655

    
1656
        if (dim == 2) {
1657
            ig = ShapeFactory.createPolyline2D(gpx);
1658
        }
1659
        else {
1660
            ords = OracleSpatialUtils.getOrds(the_data);
1661

    
1662
            double[] z = getIndBigDecimalModule(ords, 2, dim);
1663
            ig = ShapeFactory.createPolyline3D(gpx, z);
1664
        }
1665

    
1666
        return ig;
1667
    }
1668

    
1669
    private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1670
        if (jg_point.getOrdinatesArray() == null) { // sdo_point
1671

    
1672
            return getFMapGeometrySdoPoint(jg_point, dim);
1673
        }
1674

    
1675
        IGeometry ig = null;
1676
        int total_size = jg_point.getOrdinatesArray().length;
1677
        int no_po = total_size / dim;
1678
        double[] x = new double[no_po];
1679
        double[] y = new double[no_po];
1680
        double[] z = new double[no_po];
1681

    
1682
        for (int i = 0; i < no_po; i++) {
1683
            x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1684
            y[i] = jg_point.getOrdinatesArray()[(i * dim) + 1];
1685

    
1686
            if (dim >= 3) {
1687
                z[i] = jg_point.getOrdinatesArray()[(i * dim) + 2];
1688
            }
1689
        }
1690

    
1691
        if (dim == 2) {
1692
            if (no_po == 1) {
1693
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1694
            }
1695
            else {
1696
                ig = ShapeFactory.createMultipoint2D(x, y);
1697
            }
1698
        }
1699
        else {
1700
            if (no_po == 1) {
1701
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1702
            }
1703
            else {
1704
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1705
            }
1706
        }
1707

    
1708
        return ig;
1709
    }
1710

    
1711
    private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1712
        double[] ords = OracleSpatialUtils.getOrds(the_data);
1713

    
1714
        if (ords == null) { // sdo_point
1715

    
1716
            return getFMapGeometrySdoPoint(the_data, dim);
1717
        }
1718

    
1719
        IGeometry ig = null;
1720
        int total_size = ords.length;
1721
        int no_po = total_size / dim;
1722
        double[] x = new double[no_po];
1723
        double[] y = new double[no_po];
1724
        double[] z = new double[no_po];
1725

    
1726
        for (int i = 0; i < no_po; i++) {
1727
            x[i] = ords[i * dim]; // pp[i].getX();
1728
            y[i] = ords[(i * dim) + 1];
1729

    
1730
            if (dim >= 3) {
1731
                z[i] = ords[(i * dim) + 2];
1732
            }
1733
        }
1734

    
1735
        if (dim == 2) {
1736
            if (no_po == 1) {
1737
                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1738
            }
1739
            else {
1740
                ig = ShapeFactory.createMultipoint2D(x, y);
1741
            }
1742
        }
1743
        else {
1744
            if (no_po == 1) {
1745
                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1746
            }
1747
            else {
1748
                ig = ShapeFactory.createMultipoint3D(x, y, z);
1749
            }
1750
        }
1751

    
1752
        return ig;
1753
    }
1754

    
1755
    private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1756
        double[] p = jgp.getPoint();
1757
        IGeometry ig = null;
1758

    
1759
        if (d == 2) {
1760
            ig = ShapeFactory.createPoint2D(p[0], p[1]);
1761
        }
1762
        else {
1763
            ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1764
        }
1765

    
1766
        return ig;
1767
    }
1768

    
1769
    private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1770
        double x = 0;
1771
        double y = 0;
1772
        double z = 0;
1773

    
1774
        try {
1775
            Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1776
            x = ((NUMBER) aux[0]).doubleValue();
1777
            y = ((NUMBER) aux[1]).doubleValue();
1778

    
1779
            if (d > 2) {
1780
                z = ((NUMBER) aux[2]).doubleValue();
1781
            }
1782
        }
1783
        catch (SQLException se) {
1784
            logger.error("While getting sdo point ordinates: " +
1785
                se.getMessage(), se);
1786
        }
1787

    
1788
        IGeometry ig = null;
1789

    
1790
        if (d == 2) {
1791
            ig = ShapeFactory.createPoint2D(x, y);
1792
        }
1793
        else {
1794
            ig = ShapeFactory.createPoint3D(x, y, z);
1795
        }
1796

    
1797
        return ig;
1798
    }
1799

    
1800
    private boolean isActuallyACollection(JGeometry jg) {
1801
        int[] info = jg.getElemInfo();
1802

    
1803
        if (info == null) {
1804
            return false; // sdo_point
1805
        }
1806

    
1807
        int size = info.length / 3;
1808

    
1809
        if (size == 1) {
1810
            return false;
1811
        }
1812

    
1813
        if (size == 2) {
1814
            return ((info[1] % 1000) != (info[4] % 1000));
1815
        }
1816

    
1817
        int second = info[4] % 1000;
1818

    
1819
        for (int i = 2; i < size; i++) {
1820
            if ((info[(i * 3) + 1] % 1000) != second) {
1821
                return true;
1822
            }
1823
        }
1824

    
1825
        return false;
1826
    }
1827

    
1828
    private boolean isActuallyACollection(Datum[] the_data) {
1829
        int[] info = null;
1830

    
1831
        try {
1832
            ARRAY aux = (ARRAY) the_data[3];
1833

    
1834
            if (aux == null) {
1835
                return false;
1836
            }
1837

    
1838
            info = aux.getIntArray();
1839
        }
1840
        catch (SQLException se) {
1841
            logger.error("While checking collection: " + se.getMessage());
1842

    
1843
            return false;
1844
        }
1845

    
1846
        if (info == null) {
1847
            return false; // sdo_point
1848
        }
1849

    
1850
        int size = info.length / 3;
1851

    
1852
        if (size == 1) {
1853
            return false;
1854
        }
1855

    
1856
        if (size == 2) {
1857
            return ((info[1] % 1000) != (info[4] % 1000));
1858
        }
1859

    
1860
        int second = info[4] % 1000;
1861

    
1862
        for (int i = 2; i < size; i++) {
1863
            if ((info[(i * 3) + 1] % 1000) != second) {
1864
                return true;
1865
            }
1866
        }
1867

    
1868
        return false;
1869
    }
1870

    
1871
    private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1872
        int main_type = jg.getType();
1873

    
1874
        int[] all_info_array = jg.getElemInfo();
1875
        Object[] elems_info_aray = groupByElement(all_info_array);
1876
        double[] all_ords = jg.getOrdinatesArray();
1877
        Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1878
        Object[] _elems_info_aray = new Object[elems_info_aray.length];
1879

    
1880
        for (int i = 0; i < elems_info_aray.length; i++) {
1881
            _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1882
        }
1883

    
1884
        // _elems_info_aray, ords_of_groups
1885
        int no_of_elems = ords_of_groups.length;
1886
        IGeometry[] geoms = new IGeometry[no_of_elems];
1887

    
1888
        for (int i = 0; i < no_of_elems; i++) {
1889
            int[] item_info_array = (int[]) _elems_info_aray[i];
1890
            double[] item_ords = (double[]) ords_of_groups[i];
1891
            int gtype = (dim * 1000) + (item_info_array[1] % 1000);
1892

    
1893
            // if it's the first geometry, the type is the collection's main type (no?)
1894
            if (i == 0) {
1895
                gtype = main_type;
1896
            }
1897

    
1898
            JGeometry itemjg = null;
1899

    
1900
            if (tableHasSrid) {
1901
                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1902
            }
1903
            else {
1904
                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1905
            }
1906

    
1907
            geoms[i] = getFMapGeometry(itemjg, true);
1908
        }
1909

    
1910
        return new FGeometryCollection(geoms);
1911
    }
1912

    
1913
    private Datum[] updateIndexes(Datum[] info) {
1914
        int size = info.length / 3;
1915
        NUMBER[] resp = new NUMBER[3 * size];
1916

    
1917
        try {
1918
            int rest = info[0].intValue() - 1;
1919

    
1920
            for (int i = 0; i < size; i++) {
1921
                resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1922
                resp[(3 * i) + 1] = new NUMBER(info[(3 * i) + 1].intValue());
1923
                resp[(3 * i) + 2] = new NUMBER(info[(3 * i) + 2].intValue());
1924
            }
1925
        }
1926
        catch (SQLException se) {
1927
            logger.error("Unexpected error: " + se.getMessage());
1928
        }
1929

    
1930
        return resp;
1931
    }
1932

    
1933
    private int[] updateIndexes(int[] info) {
1934
        int size = info.length / 3;
1935
        int[] resp = new int[3 * size];
1936
        int rest = info[0] - 1;
1937

    
1938
        for (int i = 0; i < size; i++) {
1939
            resp[3 * i] = info[3 * i] - rest;
1940
            resp[(3 * i) + 1] = info[(3 * i) + 1];
1941
            resp[(3 * i) + 2] = info[(3 * i) + 2];
1942
        }
1943

    
1944
        return resp;
1945
    }
1946

    
1947
    private int[] appendIntArrays(int[] head, int[] tail) {
1948
        int[] resp = new int[head.length + tail.length];
1949
        int hsize = head.length;
1950

    
1951
        for (int i = 0; i < hsize; i++) {
1952
            resp[i] = head[i];
1953
        }
1954

    
1955
        for (int i = 0; i < tail.length; i++) {
1956
            resp[hsize + i] = tail[i];
1957
        }
1958

    
1959
        return resp;
1960
    }
1961

    
1962
    private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
1963
        Datum[] resp = new Datum[head.length + tail.length];
1964
        int hsize = head.length;
1965

    
1966
        for (int i = 0; i < hsize; i++) {
1967
            resp[i] = head[i];
1968
        }
1969

    
1970
        for (int i = 0; i < tail.length; i++) {
1971
            resp[hsize + i] = tail[i];
1972
        }
1973

    
1974
        return resp;
1975
    }
1976

    
1977
    private int[] getNthGroupOfThree(int[] list, int n) {
1978
        int[] resp = new int[3];
1979
        resp[0] = list[3 * n];
1980
        resp[1] = list[(3 * n) + 1];
1981
        resp[2] = list[(3 * n) + 2];
1982

    
1983
        return resp;
1984
    }
1985

    
1986
    private Datum[] getNthGroupOfThree(Datum[] list, int n) {
1987
        Datum[] resp = new Datum[3];
1988
        resp[0] = list[3 * n];
1989
        resp[1] = list[(3 * n) + 1];
1990
        resp[2] = list[(3 * n) + 2];
1991

    
1992
        return resp;
1993
    }
1994

    
1995
    private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
1996
        Datum[] resp = new Datum[last_inc - first_inc + 1];
1997

    
1998
        for (int i = first_inc; i <= last_inc; i++) {
1999
            resp[i - first_inc] = all[i];
2000
        }
2001

    
2002
        return resp;
2003
    }
2004

    
2005
    private double[] getSubSet(double[] all, int first_inc, int last_inc) {
2006
        double[] resp = new double[last_inc - first_inc + 1];
2007

    
2008
        for (int i = first_inc; i <= last_inc; i++) {
2009
            resp[i - first_inc] = all[i];
2010
        }
2011

    
2012
        return resp;
2013
    }
2014

    
2015
    private Object[] getOrdOfGroups(Datum[] all, Object[] groups) throws SQLException {
2016
        Object[] resp = new Object[groups.length];
2017

    
2018
        if (resp.length == 1) {
2019
            resp[0] = all;
2020

    
2021
            return resp;
2022
        }
2023

    
2024
        int ind = 0;
2025
        Datum[] aux = (Datum[]) groups[1];
2026
        int _end = aux[0].intValue() - 2;
2027
        Datum[] ord_aux = getSubSet(all, 0, _end);
2028

    
2029
        int _start = _end + 1;
2030
        resp[ind] = ord_aux;
2031
        ind++;
2032

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

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

    
2047
        return resp;
2048
    }
2049

    
2050
    private Object[] getOrdOfGroups(double[] all, Object[] groups) {
2051
        Object[] resp = new Object[groups.length];
2052

    
2053
        if (resp.length == 1) {
2054
            resp[0] = all;
2055

    
2056
            return resp;
2057
        }
2058

    
2059
        int ind = 0;
2060
        int[] aux = (int[]) groups[1];
2061
        int _end = aux[0] - 2;
2062
        double[] ord_aux = getSubSet(all, 0, _end);
2063

    
2064
        int _start = _end + 1;
2065
        resp[ind] = ord_aux;
2066
        ind++;
2067

    
2068
        for (int i = 2; i < groups.length; i++) {
2069
            aux = (int[]) groups[i];
2070
            _end = aux[0] - 2;
2071
            ord_aux = getSubSet(all, _start, _end);
2072
            resp[ind] = ord_aux;
2073
            ind++;
2074
            _start = _end + 1;
2075
        }
2076

    
2077
        // last
2078
        _end = all.length - 1;
2079
        ord_aux = getSubSet(all, _start, _end);
2080
        resp[groups.length - 1] = ord_aux;
2081

    
2082
        return resp;
2083
    }
2084

    
2085
    private Object[] groupByElement(int[] all_elem) {
2086
        ArrayList resp = new ArrayList();
2087

    
2088
        int size = all_elem.length / 3;
2089

    
2090
        int[] aux = getNthGroupOfThree(all_elem, 0);
2091

    
2092
        int[] newaux;
2093
        int i = 1;
2094

    
2095
        while (i < size) {
2096
            newaux = getNthGroupOfThree(all_elem, i);
2097

    
2098
            if (newaux[0] == aux[0]) {
2099
                // aux[2] says how many components
2100
                for (int j = 0; j < aux[2]; j++) {
2101
                    aux = appendIntArrays(aux,
2102
                            getNthGroupOfThree(all_elem, j + i));
2103
                }
2104

    
2105
                resp.add(aux);
2106
                i = i + aux[2];
2107
                aux = getNthGroupOfThree(all_elem, i);
2108
            }
2109
            else {
2110
                if (newaux[1] == 2003) {
2111
                    aux = appendIntArrays(aux, newaux);
2112
                }
2113
                else {
2114
                    resp.add(aux);
2115
                    aux = getNthGroupOfThree(all_elem, i);
2116
                }
2117
            }
2118

    
2119
            i++;
2120
        }
2121

    
2122
        resp.add(aux);
2123

    
2124
        return resp.toArray();
2125
    }
2126

    
2127
    private Object[] groupByElement(Datum[] all_elem) {
2128
        ArrayList resp = new ArrayList();
2129

    
2130
        int size = all_elem.length / 3;
2131

    
2132
        Datum[] aux = getNthGroupOfThree(all_elem, 0);
2133

    
2134
        Datum[] newaux;
2135
        int i = 1;
2136

    
2137
        try {
2138
            while (i < size) {
2139
                newaux = getNthGroupOfThree(all_elem, i);
2140

    
2141
                if (newaux[0] == aux[0]) {
2142
                    // aux[2] says how many components
2143
                    for (int j = 0; j < ((NUMBER) aux[2]).intValue(); j++) {
2144
                        aux = appendDatArrays(aux,
2145
                                getNthGroupOfThree(all_elem, j + i));
2146
                    }
2147

    
2148
                    resp.add(aux);
2149
                    i = i + ((NUMBER) aux[2]).intValue();
2150
                    aux = getNthGroupOfThree(all_elem, i);
2151
                }
2152
                else {
2153
                    if (((NUMBER) newaux[1]).intValue() == 2003) {
2154
                        aux = appendDatArrays(aux, newaux);
2155
                    }
2156
                    else {
2157
                        resp.add(aux);
2158
                        aux = getNthGroupOfThree(all_elem, i);
2159
                    }
2160
                }
2161

    
2162
                i++;
2163
            }
2164
        }
2165
        catch (SQLException se) {
2166
            logger.error("Unexpected error: " + se.getMessage());
2167
        }
2168

    
2169
        resp.add(aux);
2170

    
2171
        return resp.toArray();
2172
    }
2173

    
2174
    private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2175
        Point2D p = _jgeom.getJavaPoint();
2176
        IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2177

    
2178
        return ig;
2179
    }
2180

    
2181
    private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2182
        Point2D[] pp = _jgeom.getJavaPoints();
2183
        int l = pp.length;
2184
        double[] x = new double[l];
2185
        double[] y = new double[l];
2186

    
2187
        for (int i = 0; i < l; i++) {
2188
            x[i] = pp[i].getX();
2189
            y[i] = pp[i].getY();
2190
        }
2191

    
2192
        IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2193

    
2194
        return ig;
2195
    }
2196

    
2197
    private IGeometry getJGeometryOther(JGeometry _jgeom) {
2198
        int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2199
        Shape shape = _jgeom.createShape();
2200
        GeneralPathX gpx = new GeneralPathX(shape);
2201
        IGeometry ig = null;
2202

    
2203
        switch (type) {
2204
        case FShape.LINE:
2205

    
2206
            FPolyline2D fpl = new FPolyline2D(gpx);
2207
            ig = ShapeFactory.createPolyline2D(gpx);
2208

    
2209
            break;
2210

    
2211
        case FShape.POLYGON:
2212

    
2213
            FPolygon2D fpg = new FPolygon2D(gpx);
2214
            ig = ShapeFactory.createPolygon2D(gpx);
2215

    
2216
            break;
2217
        }
2218

    
2219
        return ig;
2220
    }
2221

    
2222
//    private IGeometry getGeotoolsIGeometry(oracle.sql.STRUCT _struct) {
2223
//        Geometry geo_jts = null;
2224
//
2225
//        try {
2226
//            geo_jts = geotools_conv.asGeometry(_struct);
2227
//        }
2228
//        catch (SQLException e) {
2229
//            System.err.println("While using geotools converter: " +
2230
//                e.getMessage());
2231
//        }
2232
//
2233
//        IGeometry ig = FConverter.jts_to_igeometry(geo_jts);
2234
//
2235
//        return ig;
2236
//    }
2237

    
2238
    private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
2239
        /*
2240
         * Tipos en Oracle Spatial usando JGeometry
2241
         *
2242
         * GTYPE_COLLECTION collection geometry type
2243
         * GTYPE_CURVE curve geoemtry type
2244
         * GTYPE_MULTICURVE multi-curve geometry type
2245
         * GTYPE_MULTIPOINT multi-point geometry type
2246
         * GTYPE_MULTIPOLYGON multi-polygon geometry type
2247
         * GTYPE_POINT point geometry type
2248
         * GTYPE_POLYGON  polygon geometry type
2249
         *
2250
         * Tipos gvSIG FShape
2251
         *
2252
         * NULL = 0;
2253
         * POINT = 1;
2254
         * LINE = 2;
2255
         * POLYGON = 4;
2256
         * TEXT = 8;
2257
         * MULTI = 16;
2258
         * MULTIPOINT = 32;
2259
         * CIRCLE = 64;
2260
         * ARC = 128;
2261
         * ELLIPSE=256;
2262
         * Z=512
2263
         */
2264
        switch (type) {
2265
        case JGeometry.GTYPE_POLYGON:
2266
        case JGeometry.GTYPE_MULTIPOLYGON:
2267
            return FShape.POLYGON;
2268

    
2269
        case JGeometry.GTYPE_CURVE:
2270
        case JGeometry.GTYPE_MULTICURVE:
2271
            return FShape.LINE;
2272
        }
2273

    
2274
        System.err.println("Unhandled Oracle Spatial geometry type: " + type +
2275
            " (conversion returned FShape.NULL)");
2276

    
2277
        return FShape.NULL;
2278
    }
2279

    
2280
    private void cleanWhereClause() {
2281
        emptyWhereClause = false;
2282

    
2283
        String aux = getWhereClauseWithoutWhere();
2284

    
2285
        for (int i = 0; i < aux.length(); i++)
2286
            if (aux.substring(i, i + 1).compareTo(" ") != 0) {
2287
                return;
2288
            }
2289

    
2290
        getLyrDef().setWhereClause("");
2291
        emptyWhereClause = true;
2292
    }
2293
    
2294
    private String getValidViewConstructor(
2295
                    STRUCT _st,
2296
                    String ora_srid,
2297
                    boolean _hassrid,
2298
                    boolean _isgeocs) {
2299
            
2300
            String sdo = getSdoConstructor(_st, _hassrid, _isgeocs);
2301
            String resp = "";
2302
            if ((_hassrid) && (_isgeocs)) {
2303
                    resp = "SDO_CS.VIEWPORT_TRANSFORM( " + sdo + " , " + ora_srid + ")";
2304
            } else {
2305
                    resp = sdo;
2306
            }
2307
             
2308
            return resp;
2309
    }
2310

    
2311
    private String getMainSelect(String viewsdo, String idsLoadWhere) {
2312
        String resp = "";
2313

    
2314
        if (isGeogCS) {
2315
            String vport = "sdo_filter(" + geoColName +
2316
                ", SDO_CS.VIEWPORT_TRANSFORM(" + viewsdo + ", " + oracleSRID +
2317
                "), 'querytype=window') = 'TRUE'";
2318

    
2319
                resp = "select " + getStandardSelectExpression() + ", c." +
2320
                    geoColName + " from " + getTableName() + " c where ";
2321
                if (idsLoadWhere.length() > 0) {
2322
                        resp = resp + " (" + idsLoadWhere + ") AND "; 
2323
                }
2324
                resp = resp + "(" + vport + ")";
2325
        }
2326
        else {
2327
                resp = "select " + getStandardSelectExpression() + ", c." +
2328
                    geoColName + " from " + getTableName() + " c where ";
2329
                if (idsLoadWhere.length() > 0) {
2330
                        resp = resp + " (" + idsLoadWhere + ") AND "; 
2331
                }
2332
                resp = resp + "(" + "sdo_relate(" + geoColName + ", " + viewsdo +
2333
                ", 'mask=anyinteract querytype=window') = 'TRUE')";
2334
        }
2335
        
2336
//        return "select " + getStandardSelectExpression() + ", c." +
2337
//        geoColName + " from " + getTableName() + " c";
2338
        return resp;
2339
    }
2340

    
2341
    public void setWorkingArea(Rectangle2D rect) {
2342
    }
2343

    
2344
    private void setWAStructt() {
2345
    }
2346

    
2347
    private Geometry shapeToGeometry(Shape shp) {
2348
        if (shp == null) {
2349
            return null;
2350
        }
2351

    
2352
        int type = FShape.POLYGON;
2353

    
2354
        if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D))) {
2355
            type = FShape.LINE;
2356
        }
2357

    
2358
        if (shp instanceof FPoint2D) {
2359
            type = FShape.POINT;
2360
        }
2361

    
2362
        if (shp instanceof FMultiPoint2D) {
2363
            type = FShape.MULTIPOINT;
2364
        }
2365

    
2366
        GeneralPathX wagp = new GeneralPathX(shp);
2367
        FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2368

    
2369
        return FConverter.java2d_to_jts(fwagp);
2370
    }
2371

    
2372
    public static Rectangle2D getBoundingBox(JGeometry _jg) {
2373
        Shape shape = _jg.createShape();
2374

    
2375
        return shape.getBounds2D();
2376
    }
2377

    
2378
    private void printStruct(STRUCT st) {
2379
        System.out.println("----------------------------------------------");
2380

    
2381
        try {
2382
            Object[] att = st.getAttributes();
2383
            int l = att.length;
2384

    
2385
            for (int i = 0; i < l; i++) {
2386
                System.out.println("ATT " + i + ": " + att[i].toString());
2387
            }
2388
        }
2389
        catch (Exception ex) {
2390
            System.out.println(
2391
                "- Error ---------------------------------------");
2392
        }
2393

    
2394
        System.out.println("----------------------------------------------");
2395
    }
2396

    
2397
    private static STRUCT rectangleToStruct(Rectangle2D r, boolean hasSrid,
2398
        boolean isView, boolean _isGeogCS, String _oracleSRID, Connection __conn) {
2399
        Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2400
        Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2401

    
2402
        if ((_isGeogCS) && (isView)) {
2403
            c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2404
            c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2405
        }
2406

    
2407
        STRUCT resp = null;
2408

    
2409
        try {
2410
            // System.out.println("ABIERTA: " + (!conn.isClosed()));
2411
            // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2412
            // Object[] old_obj = resp.getAttributes();
2413
            int size = 5;
2414
            Object[] new_obj = new Object[size];
2415

    
2416
            // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2417
            new_obj[0] = new NUMBER(2003);
2418

    
2419
            if (hasSrid) {
2420
                new_obj[1] = new NUMBER(_oracleSRID);
2421
            }
2422
            else {
2423
                new_obj[1] = null;
2424
            }
2425

    
2426
            new_obj[2] = null;
2427

    
2428
            NUMBER[] elem_info = new NUMBER[3];
2429
            elem_info[0] = new NUMBER(1);
2430
            elem_info[1] = new NUMBER(1003);
2431
            elem_info[2] = new NUMBER(3);
2432
            new_obj[3] = elem_info;
2433

    
2434
            NUMBER[] ords = null;
2435
            ords = new NUMBER[4];
2436
            ords[0] = new NUMBER(c1.getX());
2437
            ords[1] = new NUMBER(c1.getY());
2438
            ords[2] = new NUMBER(c2.getX());
2439
            ords[3] = new NUMBER(c2.getY());
2440
            new_obj[4] = ords;
2441

    
2442
            // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2443
            StructDescriptor dsc = StructDescriptor.createDescriptor("MDSYS.SDO_GEOMETRY",
2444
                    __conn);
2445

    
2446
            resp = new STRUCT(dsc, __conn, new_obj);
2447
        }
2448
        catch (Exception ex) {
2449
            logger.error("Error while creating rect struct: " +
2450
                ex.getMessage(), ex);
2451
        }
2452

    
2453
        return resp;
2454
    }
2455

    
2456
    private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2457
        boolean hasSrid) throws DriverException {
2458
        String sdo_intersect = getSdoConstructor(geoStruct, hasSrid, isGeogCS);
2459
        String main_sel = "";
2460

    
2461
        if (fixsql == null) {
2462
            // main_sel = getMainSelect3(var_name);
2463
                String idswhere = getIdsQueryWhereClause(false);
2464
            main_sel = getMainSelect(sdo_intersect, idswhere);
2465
        }
2466
        else {
2467
            main_sel = fixsql;
2468
        }
2469

    
2470
        logger.debug("MAIN SEL = " + main_sel);
2471

    
2472
        ResultSet _rs = null;
2473
        Statement _stmnt = null;
2474
        Object[] _resp = new Object[2];
2475

    
2476
        try {
2477
            _stmnt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
2478
                    ResultSet.CONCUR_READ_ONLY);
2479
            _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2480
            _stmnt.setFetchSize(FETCH_SIZE);
2481

    
2482
            _rs = _stmnt.executeQuery(main_sel);
2483

    
2484
            // stmnt.close();
2485
        }
2486
        catch (SQLException se) {
2487
            logger.error("Tablename: " + getTableName() + ". Error while getting main cursor: " + se.getMessage(),
2488
                se);
2489
            throw new DriverException(se);
2490
        }
2491

    
2492
        // this method returns the statement too, so that it can be closed afterwards
2493
        _resp[0] = _rs;
2494
        _resp[1] = _stmnt;
2495

    
2496
        return _resp;
2497
    }
2498

    
2499
    private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid, boolean _isGeogCS) {
2500
        String resp = "";
2501

    
2502
        try {
2503
            String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2504
            String mdsys_sdo_ordinate_array = "";
2505
            Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2506

    
2507
            for (int i = 0; i < vertices.length; i++) {
2508
                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array +
2509
                    vertices[i].doubleValue() + ", ";
2510
            }
2511

    
2512
            mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2513
                    mdsys_sdo_ordinate_array.length() - 2);
2514
            mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array(" +
2515
                mdsys_sdo_ordinate_array + ")";
2516

    
2517
            String aux = "";
2518

    
2519
            if (hasSrid) {
2520
                aux = oracleSRID;
2521

    
2522
                if (_isGeogCS) {
2523
                    aux = "0";
2524
                }
2525
            }
2526
            else {
2527
                aux = "null";
2528
            }
2529

    
2530
            resp = "mdsys.sdo_geometry(2003, " + aux + ", null, " +
2531
                mdsys_sdo_elem_info_array + ", " + mdsys_sdo_ordinate_array +
2532
                ")";
2533
        }
2534
        catch (Exception ex) {
2535
            System.err.println("Error while getting sdo contructor: " +
2536
                ex.getMessage());
2537
        }
2538

    
2539
        return resp;
2540
    }
2541
    
2542
    private String getIdsQueryWhereClause(boolean with_where) {
2543
                String resp = "";
2544
                
2545
                String _where = "";
2546
                if (with_where) _where = " where ";
2547

    
2548
                if (workingAreaInTablesCSStruct == null) {
2549
                        if (emptyWhereClause) {
2550
                                // return "select rowid from " + getTableName();
2551
                        } else {
2552
                                resp = resp + _where + "(" + getWhereClauseWithoutWhere()
2553
                                                + ")";
2554
                        }
2555
                } else {
2556
                        String waqry = getValidViewConstructor(workingAreaInTablesCSStruct,
2557
                                        oracleSRID, tableHasSrid, isGeogCS);
2558

    
2559
                        if (emptyWhereClause) {
2560
                                resp = resp + _where + "(sdo_relate(" + geoColName + ", " + waqry
2561
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2562
                        } else {
2563
                                resp = resp + _where + "((" + getWhereClauseWithoutWhere()
2564
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + waqry
2565
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2566
                        }
2567
                }
2568

    
2569
                // resp = resp + " order by rowid";
2570
                return resp;
2571
        }
2572

    
2573
    public String getIdAndElemInfoFullResulltSetQuery() {
2574
        String resp = "select rowid, c." + geoColName + ".SDO_ELEM_INFO from " +
2575
            getTableName() + " c";
2576
        
2577
        resp = resp + getIdsQueryWhereClause(true);
2578
        return resp;
2579
    }
2580

    
2581
    private String getSearchId() {
2582
        if (emptyWhereClause) {
2583
            return "select " + getStandardSelectExpression() + ", c." +
2584
            geoColName + " from " + getTableName() + " c where rowid = ?";
2585
        }
2586
        else {
2587
            return "select " + getStandardSelectExpression() + ", c." +
2588
            geoColName + " from " + getTableName() + " c " + " where " + "((" +
2589
            getWhereClauseWithoutWhere() + ") and (rowid = ?))";
2590
        }
2591
    }
2592

    
2593
    public int getShapeType() {
2594
        return shapeType;
2595
    }
2596

    
2597
    private String getWhereClauseWithoutWhere() {
2598
        String resp = "";
2599
        String old = getLyrDef().getWhereClause();
2600
        resp = old;
2601

    
2602
        if (old.length() <= 6) {
2603
            return old;
2604
        }
2605

    
2606
        if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2607
            resp = resp.substring(6, resp.length());
2608
        }
2609

    
2610
        return resp;
2611
    }
2612

    
2613
    private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2614
        if (r1.getMaxX() <= r2.getMinX()) {
2615
            return null;
2616
        }
2617

    
2618
        if (r2.getMaxX() <= r1.getMinX()) {
2619
            return null;
2620
        }
2621

    
2622
        if (r1.getMaxY() <= r2.getMinY()) {
2623
            return null;
2624
        }
2625

    
2626
        if (r2.getMaxY() <= r1.getMinY()) {
2627
            return null;
2628
        }
2629

    
2630
        double minx = Math.max(r1.getMinX(), r2.getMinX());
2631
        double miny = Math.max(r1.getMinY(), r2.getMinY());
2632
        double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2633
        double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2634

    
2635
        double w = maxx - minx;
2636
        double h = maxy - miny;
2637

    
2638
        return new Rectangle2D.Double(minx, miny, w, h);
2639
    }
2640

    
2641
    private static int maxSizeForFieldType(int _type) {
2642
        switch (_type) {
2643
        case Types.VARCHAR:
2644
            return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2645

    
2646
        case Types.LONGVARCHAR:
2647
            return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2648
        }
2649

    
2650
        return -1;
2651
    }
2652

    
2653
    public static String fieldTypeToSqlStringType(FieldDescription fieldDesc) {
2654
        String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2655

    
2656
        switch (fieldDesc.getFieldType()) {
2657
        case Types.SMALLINT:
2658
            aux = "NUMBER(5, 0)";
2659

    
2660
            break;
2661

    
2662
        case Types.INTEGER:
2663
            aux = "NUMBER(10, 0)";
2664

    
2665
            break;
2666

    
2667
        case Types.BIGINT:
2668
            aux = "NUMBER(38, 0)";
2669

    
2670
            break;
2671

    
2672
        case Types.BOOLEAN:
2673
            aux = "NUMBER(1, 0)";
2674

    
2675
            break;
2676

    
2677
        case Types.DECIMAL:
2678
            aux = "NUMBER";
2679

    
2680
            break;
2681

    
2682
        case Types.NUMERIC:
2683
            aux = "NUMBER";
2684

    
2685
            break;
2686

    
2687
        case Types.DOUBLE:
2688
            aux = "FLOAT";
2689

    
2690
            break;
2691

    
2692
        case Types.FLOAT:
2693
            aux = "FLOAT";
2694

    
2695
            break;
2696

    
2697
        case Types.CHAR:
2698
            aux = "CHAR(1 BYTE)";
2699

    
2700
            break;
2701

    
2702
        case Types.VARCHAR:
2703
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2704

    
2705
            break;
2706

    
2707
        case Types.LONGVARCHAR:
2708
            aux = "NVARCHAR2(" + fieldDesc.getFieldLength() + ")";
2709

    
2710
            break;
2711
        }
2712

    
2713
        return aux;
2714
    }
2715

    
2716
    // -----------------------------------------------------------
2717
    // -----------------------------------------------------------
2718
    public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2719
        return "DROP TABLE " + dbLayerDef.getTableName() +
2720
        " CASCADE CONSTRAINTS";
2721
    }
2722

    
2723
    public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2724
        FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2725

    
2726
        String type = "";
2727
        String name = "";
2728

    
2729
        String resp = "CREATE TABLE " + dbLayerDef.getTableName() + " ( ";
2730

    
2731
        for (int i = 0; i < flds.length; i++) {
2732
            name = flds[i].getFieldName();
2733

    
2734
            // -------------- FORBIDDEN FIELD NAMES -----------------
2735
            if (!isOracleAllowedFieldname(name)) {
2736
                continue;
2737
            }
2738

    
2739
            // ------------------------------------------------------
2740
            if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
2741
            }
2742
            else {
2743
                name = getValidOracleID(name, i);
2744
                resp = resp + "\"" + name + "\" ";
2745
                type = fieldTypeToSqlStringType(flds[i]);
2746
                resp = resp + type + ", ";
2747
            }
2748
        }
2749

    
2750
        resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2751
        resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2752
        resp = resp + ", ";
2753

    
2754
        String pk = "CONSTRAINT " + getDerivedNAme(dbLayerDef.getTableName(), "PK") +
2755
            " PRIMARY KEY (\"" + OracleSpatialDriver.DEFAULT_ID_FIELD +
2756
            "\") ENABLE";
2757

    
2758
        resp = resp + pk + " )";
2759

    
2760
        return resp;
2761
    }
2762
    
2763
    private static String getDerivedNAme(String tname, String suffix) {
2764
            
2765
            int ind = tname.lastIndexOf("."); 
2766
            if (ind == -1) {
2767
                    
2768
                    int l = Math.min(28, tname.length());
2769
                    return tname.substring(0, l) + "_" + suffix;
2770

    
2771
            } else {
2772
                    
2773
                    String pre = tname.substring(0, ind);
2774
                    String post = tname.substring(ind + 1, tname.length());
2775
                    int lpost = Math.min(24, post.length());
2776
                    int lpre = Math.min(3, pre.length());
2777
                    return pre.substring(0, lpre) + "_" + post.substring(0, lpost) + "_" + suffix;
2778
            }
2779
            
2780
    }
2781

    
2782
    public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2783
        String resp = "CREATE INDEX " + getDerivedNAme(dbLayerDef.getTableName(), "SX") +
2784
            " ON " + dbLayerDef.getTableName() + " (\"" +
2785
            OracleSpatialDriver.DEFAULT_GEO_FIELD +
2786
            "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2787

    
2788
        return resp;
2789
    }
2790

    
2791
    public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2792
            
2793
            String tname = dbLayerDef.getTableName();
2794
            int ind = tname.lastIndexOf(".");
2795
            if (ind != -1) {
2796
                    String schema = tname.substring(0, ind);
2797
                    tname = tname.substring(ind + 1, tname.length());
2798
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2799
            " WHERE TABLE_NAME = '" + tname + "' AND OWNER = '" + schema + "'";
2800
                     
2801
            } else{
2802
            return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW +
2803
            " WHERE TABLE_NAME = '" + tname + "'";
2804
            }
2805
    }
2806

    
2807
    /**
2808
     * UTility method to get the SQL sentence needed to update the geographic metadata table
2809
     * with a new bounding box and SRS
2810
     *
2811
     * @param tName table name
2812
     * @param ora_srid new SRS
2813
     * @param bbox new bounding box
2814
     * @param dim geometries dimension
2815
     * @param withsrid False if the SRS is set to NULL. True otherwise.
2816
     * @return the SQL sentence to perform the update
2817
     */
2818
    public static String getMetadataUpdateSql(String schema, String tName, String ora_srid,
2819
        Rectangle2D bbox, int dim, boolean withsrid) {
2820
        String[] dim_name = new String[dim];
2821
        double tolerance = 0.5;
2822

    
2823
        if (ora_srid.compareTo(GEODETIC_SRID) == 0) {
2824
            dim_name[0] = "LONGITUDE";
2825
            dim_name[1] = "LATITUDE";
2826
        }
2827
        else {
2828
            dim_name[0] = "X";
2829
            dim_name[1] = "Y";
2830

    
2831
            if (dim > 2) {
2832
                dim_name[2] = "Z";
2833

    
2834
                if (dim > 3) {
2835
                    dim_name[3] = "T";
2836
                }
2837
            }
2838
        }
2839

    
2840
        String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " " +
2841
            " ( OWNER, TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
2842
            + "'" + schema + "', "
2843
            + "'" + tName + "', "
2844
            + "'" + DEFAULT_GEO_FIELD + "', " +
2845
            "MDSYS.SDO_DIM_ARRAY( " + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[0] + "', " +
2846
            bbox.getMinX() + ", " + bbox.getMaxX() + ", " + tolerance + " ), " +
2847
            "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + bbox.getMinY() + ", " +
2848
            bbox.getMaxY() + ", " + tolerance + " ))";
2849

    
2850
        if (dim > 2) {
2851
            resp = resp.substring(0, resp.length() - 1) + ",";
2852
            resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[2] +
2853
                "', 0.0, 100.0, " + tolerance + " ))";
2854

    
2855
            if (dim > 3) {
2856
                resp = resp.substring(0, resp.length() - 1) + ",";
2857
                resp = resp + "MDSYS.SDO_DIM_ELEMENT ('" + dim_name[3] +
2858
                    "', 0.0, 100.0, " + tolerance + " ))";
2859
            }
2860
        }
2861

    
2862
        if (withsrid) {
2863
            resp = resp + ", " + ora_srid + " )";
2864
        }
2865
        else {
2866
            resp = resp + ", NULL )";
2867
        }
2868

    
2869
        return resp;
2870
    }
2871

    
2872
    /**
2873
     * Gets the SQL sentence to perform an insertion.
2874
     *
2875
     * @param feat feature to be added
2876
     * @param dbLayerDef layer definition
2877
     * @param rowInd row index
2878
     * @param _geoColName geometry field name
2879
     * @return the SQL sentence to perform the insertion
2880
     */
2881
    public static String getRowInsertSql(IFeature feat,
2882
        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2883
        String name = "";
2884
        int ftype = -1;
2885
        String aux_orig = "";
2886
        String aux_limited = "";
2887
        String aux_quotes_ok = "";
2888

    
2889
        FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2890

    
2891
        String resp = "INSERT INTO " + dbLayerDef.getTableName() + " ( ";
2892

    
2893
        for (int i = 0; i < fieldsDescr.length; i++) {
2894
            name = fieldsDescr[i].getFieldName();
2895
            ftype = fieldsDescr[i].getFieldType();
2896

    
2897
            // -------------- FORBIDDEN FIELD NAMES & TYPES ---------
2898
            if (!isOracleAllowedFieldname(name)) continue;
2899
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2900
            // ------------------------------------------------------
2901
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2902
            }
2903
            else {
2904
                name = getValidOracleID(name, i);
2905
                resp = resp + "\"" + name + "\"" + " , ";
2906
            }
2907
        }
2908

    
2909
        resp = resp + _geoColName + " ) VALUES ( ";
2910

    
2911
        for (int i = 0; i < fieldsDescr.length; i++) {
2912
            name = fieldsDescr[i].getFieldName();
2913
            ftype = fieldsDescr[i].getFieldType();
2914

    
2915
            // -------------- FORBIDDEN FIELD NAMES/Types -----------
2916
            if (!isOracleAllowedFieldname(name)) continue;
2917
            if (!isUserEditableType(ftype, name, _geoColName)) continue;
2918
            // ------------------------------------------------------
2919
            String sur = getValueSurroundFromType(fieldsDescr[i]);
2920

    
2921
            if (name.compareToIgnoreCase(_geoColName) == 0) {
2922
            }
2923
            else {
2924
                if (name.compareToIgnoreCase(
2925
                            OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2926
                    resp = resp + rowInd + " , ";
2927
                }
2928
                else {
2929
                    Value attValue = feat.getAttribute(i);
2930

    
2931
                    if (attValue.toString() == null) {
2932
                        resp = resp + "NULL , ";
2933
                    }
2934
                    else {
2935
                        if (sur.length() > 0) {
2936
                            aux_orig = attValue.toString();
2937
                            aux_limited = cropStringValue(aux_orig, i,
2938
                                    fieldsDescr);
2939
                            aux_quotes_ok = avoidQuoteProblem(aux_limited);
2940

    
2941
                            resp = resp + sur + aux_quotes_ok + sur + " , ";
2942
                        }
2943
                        else {
2944
                            String _aux = attValue.toString();
2945

    
2946
                            if (_aux.length() == 0) {
2947
                                _aux = "NULL";
2948
                            }
2949

    
2950
                            resp = resp + _aux + " , ";
2951
                        }
2952
                    }
2953
                }
2954
            }
2955
        }
2956

    
2957
        resp = resp + " ? )";
2958
        /*
2959
        String test = "SDO_UTIL.APPEND(SDO_GEOMETRY("
2960
                        + "2002, NULL, NULL,"
2961
                        + "SDO_ELEM_INFO_ARRAY(1, 2, 2),"
2962
                        + "SDO_ORDINATE_ARRAY(500000, 4000000, 1000000, 5000000, 500000, 5000000)"
2963
                        + "), ? )";
2964

2965
        resp = resp + " " + test + " )";
2966
        */
2967
        return resp;
2968
    }
2969

    
2970
    private static boolean isUserEditableType(int ftype, String item_name, String geo_name) {
2971
            
2972
            if (item_name.compareToIgnoreCase(geo_name) == 0) {
2973
                    return true;
2974
            }
2975
            
2976
            if ((ftype == Types.BINARY)
2977
                || (ftype == Types.ARRAY)
2978
                || (ftype == Types.BLOB)
2979
                || (ftype == Types.CLOB)
2980
                || (ftype == Types.STRUCT)
2981
            ) {
2982
                    return false;
2983
            }
2984
                return true;
2985
        }
2986

    
2987
        /**
2988
     * Gets the SQL sentence to perform an update.
2989
     *
2990
     * @param feat feature to be updated
2991
     * @param dbLayerDef layer definition
2992
     * @param rowInd row index
2993
     * @param geoFieldName geometry field name
2994
     * @return the SQL sentence to perform the update
2995
     */
2996
    public static String getRowUpdateSql(IFeature feat,
2997
        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
2998
        String name = "";
2999
        String aux_orig = "";
3000
        String aux_limited = "";
3001
        String aux_quotes_ok = "";
3002

    
3003
        Value[] atts = feat.getAttributes();
3004
        FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
3005

    
3006
        String resp = "UPDATE " + dbLayerDef.getTableName() + " SET ";
3007

    
3008
        for (int i = 0; i < _fieldsDescr.length; i++) {
3009
            name = _fieldsDescr[i].getFieldName();
3010

    
3011
            // -------------- FORBIDDEN FIELD NAMES -----------------
3012
            if (!isOracleAllowedFieldname(name)) {
3013
                logger.info("Field: " + name + " will not be updated.");
3014
                continue;
3015
            }
3016

    
3017
            if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name,
3018
                        geoFieldName)) {
3019
                logger.info("Field: " + name + " will not be updated (it's a struct).");
3020
                continue;
3021
            }
3022

    
3023
            // ------------------------------------------------------
3024
            if (name.compareToIgnoreCase(geoFieldName) == 0) {
3025
                // resp = resp + "\"" + name + "\"" + " = ?, ";
3026
            }
3027
            else {
3028
                String sur = getValueSurroundFromType(_fieldsDescr[i]);
3029
                aux_orig = atts[i].toString();
3030
                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
3031
                aux_quotes_ok = avoidQuoteProblem(aux_limited);
3032
                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok +
3033
                    sur + ", ";
3034
            }
3035
        }
3036

    
3037
        resp = resp + "\"" + geoFieldName + "\" = ?";
3038
        resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
3039

    
3040
        return resp;
3041
    }
3042

    
3043
    private static boolean isStructAndNotGeoField(int ftype, String fldname,
3044
        String geoname) {
3045
        if (ftype == Types.STRUCT) {
3046
            if (fldname.compareToIgnoreCase(geoname) != 0) {
3047
                return true;
3048
            }
3049
        }
3050

    
3051
        return false;
3052
    }
3053

    
3054
    /**
3055
     * Gets the SQL sentence to perform a deletion.
3056
     *
3057
     * @param dbLayerDef layer definition
3058
     * @param id ROWID of the record to be deleted
3059
     * @return the SQL sentence to perform the deletion
3060
     */
3061
    public static String getRowDeleteSql(DBLayerDefinition dbLayerDef, String id) {
3062
        String resp = "DELETE FROM " + dbLayerDef.getTableName();
3063
        resp = resp + " WHERE ROWID ='" + id + "'";
3064

    
3065
        return resp;
3066
    }
3067

    
3068
    private static String cropStringValue(String orig_val, int i,
3069
        FieldDescription[] _flds) {
3070
        if (orig_val == null) {
3071
            return "NULL";
3072
        }
3073

    
3074
        int tpe = _flds[i].getFieldType();
3075
        int max_size = maxSizeForFieldType(tpe);
3076

    
3077
        if (max_size == -1) {
3078
            return orig_val;
3079
        }
3080

    
3081
        int or_size = orig_val.length();
3082

    
3083
        if (or_size <= max_size) {
3084
            return orig_val;
3085
        }
3086

    
3087
        return orig_val.substring(0, max_size);
3088
    }
3089

    
3090
    private static String avoidQuoteProblem(String str) {
3091
        return str.replaceAll("'", "''");
3092
    }
3093

    
3094
    private static String getValueSurroundFromType(FieldDescription fieldDesc) {
3095
        if (NumberUtilities.isNumeric(fieldDesc.getFieldType())) {
3096
            return "";
3097
        }
3098

    
3099
        return "'";
3100
    }
3101

    
3102
    /**
3103
     * Utility function to translate a SRS code from EPSG to Oracle.
3104
     * Uses a datasource based on a DBF file.
3105
     *
3106
     * @param epsg the EPSG code
3107
     * @return the Oracle code
3108
     */
3109
    public static String epsgSridToOracleSrid(String epsg) throws Exception {
3110
        String resp = "8307";
3111

    
3112
        // --------------------------------------------
3113
        String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME +
3114
            " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
3115
        DataSource ds = null;
3116

    
3117
        try {
3118
            ds = LayerFactory.getDataSourceFactory()
3119
                             .executeSQL(sql,
3120
                    DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
3121

    
3122
            if (ds.getRowCount() == 0) {
3123
                logger.error("EPSG code not found in table: " + epsg);
3124
                throw new Exception("Unknown EPSG: " + epsg);
3125
            }
3126

    
3127
            if (ds.getRowCount() > 1) {
3128
                logger.error("===============");
3129
                logger.error(
3130
                    "DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: " +
3131
                    epsg);
3132

    
3133
                for (int i = 0; i < ds.getRowCount(); i++) {
3134
                    int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3135

    
3136
                    if (i == 0) {
3137
                        resp = "" + aux;
3138
                    }
3139

    
3140
                    logger.error("" + aux);
3141
                }
3142

    
3143
                logger.error("===============");
3144

    
3145
                return resp;
3146
            }
3147

    
3148
            resp = "" +
3149
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3150
        }
3151
        catch (Exception pe) {
3152
            logger.error("Error with SQL statement. " + pe.getMessage());
3153
        }
3154

    
3155
        return resp;
3156
    }
3157

    
3158
    /**
3159
     * Utility function to translate a SRS code from Oracle to EPSG.
3160
     * Uses a datasource based on a DBF file.
3161
     *
3162
     * @param ora the Oracle code
3163
     * @return the EPSG code
3164
     */
3165
    public static String oracleSridToEpsgSrid(String ora) throws Exception {
3166
        String resp = "4326";
3167

    
3168
        // --------------------------------------------
3169
        String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME +
3170
            " where ORACLE = " + ora + ";";
3171
        DataSource ds = null;
3172

    
3173
        try {
3174
            ds = LayerFactory.getDataSourceFactory()
3175
                             .executeSQL(sql,
3176
                    DataSourceFactory.AUTOMATIC_OPENING);
3177

    
3178
            if (ds.getRowCount() == 0) {
3179
                logger.error("Oracle Spatial code not found in table: " + ora);
3180
                throw new Exception("Unknown Oracle code: " + ora);
3181
            }
3182

    
3183
            if (ds.getRowCount() > 1) {
3184
                logger.error("===============");
3185
                logger.error(
3186
                    "DBF file is wrong: More than one EPSG code found for Oracle Spatial code: " +
3187
                    ora);
3188

    
3189
                for (int i = 0; i < ds.getRowCount(); i++) {
3190
                    String aux = "" +
3191
                        Math.round(((DoubleValue) ds.getRow(i)[0]).doubleValue());
3192

    
3193
                    if (i == 0) {
3194
                        resp = aux;
3195
                    }
3196

    
3197
                    logger.error("" + aux);
3198
                }
3199

    
3200
                logger.error("===============");
3201

    
3202
                return resp;
3203
            }
3204

    
3205
            resp = "" +
3206
                Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
3207
        }
3208
        catch (Exception pe) {
3209
            logger.error("Error with SQL statement. " + pe.getMessage());
3210
        }
3211

    
3212
        return resp;
3213
    }
3214

    
3215
    /**
3216
     * This methos creates the datasource used to translate the SRS codes:
3217
     * EPSG <--> Oracle.
3218
     *
3219
     * It's called from several places, so checks that the datasource does not exist.
3220
     */
3221

    
3222

    
3223
    /**
3224
     * Utility method to get a valid Oracle identifier (in terms of length)
3225
     *
3226
     * @param str Proposed string
3227
     * @param ind field index of the given field name (used by the method to
3228
     * improve the renaming)
3229
     * @return an acceptable oracle identifier.
3230
     */
3231
    public static String getValidOracleID(String str, int ind) {
3232
        if (str.length() <= MAX_ID_LENGTH) {
3233
            return str;
3234
        }
3235

    
3236
        String resp = str.substring(0, MAX_ID_LENGTH - 7);
3237
        resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3238
        resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3239
        resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3240
        resp = resp + "_" + (ind % 1000);
3241

    
3242
        return resp;
3243
    }
3244

    
3245
    private static ArrayList ensureSensibleShell(ArrayList cc) {
3246
        if (sameCoordinate((Coordinate) cc.get(0),
3247
                    (Coordinate) cc.get(cc.size() - 1))) {
3248
            if (cc.size() == 2) {
3249
                ArrayList resp = new ArrayList();
3250
                resp.add(cc.get(0));
3251

    
3252
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3253
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3254
                resp.add(newcoo);
3255

    
3256
                newcoo = new Coordinate((Coordinate) cc.get(0));
3257
                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3258
                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
3259
                resp.add(newcoo);
3260

    
3261
                resp.add(cc.get(0));
3262

    
3263
                return resp;
3264
            }
3265

    
3266
            if (cc.size() == 3) {
3267
                cc.remove(1);
3268

    
3269
                return ensureSensibleShell(cc);
3270
            }
3271

    
3272
            return cc;
3273
        }
3274
        else {
3275
            cc.add(cc.get(0));
3276

    
3277
            return cc;
3278
        }
3279
    }
3280

    
3281
    private static ArrayList ensureSensibleHole(ArrayList cc) {
3282
        if (sameCoordinate((Coordinate) cc.get(0),
3283
                    (Coordinate) cc.get(cc.size() - 1))) {
3284
            if (cc.size() == 2) {
3285
                ArrayList resp = new ArrayList();
3286
                resp.add(cc.get(0));
3287

    
3288
                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3289
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3290
                resp.add(newcoo);
3291

    
3292
                newcoo = new Coordinate((Coordinate) cc.get(0));
3293
                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3294
                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3295
                resp.add(newcoo);
3296

    
3297
                resp.add(cc.get(0));
3298

    
3299
                return resp;
3300
            }
3301

    
3302
            if (cc.size() == 3) {
3303
                cc.remove(1);
3304

    
3305
                return ensureSensibleHole(cc);
3306
            }
3307

    
3308
            return cc;
3309
        }
3310
        else {
3311
            cc.add(cc.get(0));
3312

    
3313
            return cc;
3314
        }
3315
    }
3316

    
3317
    private static ArrayList ensureSensibleLineString(ArrayList cc) {
3318
        if (cc.size() == 2) {
3319
            if (sameCoordinate((Coordinate) cc.get(0),
3320
                        (Coordinate) cc.get(cc.size() - 1))) {
3321
                ArrayList resp = new ArrayList();
3322
                resp.add(cc.get(0));
3323

    
3324
                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3325
                newc.x = newc.x + IRRELEVANT_DISTANCE;
3326
                resp.add(newc);
3327

    
3328
                return resp;
3329
            }
3330
        }
3331

    
3332
        return cc;
3333
    }
3334

    
3335
    private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3336
        if (c1.x != c2.x) {
3337
            return false;
3338
        }
3339

    
3340
        if (c1.y != c2.y) {
3341
            return false;
3342
        }
3343

    
3344
        return true;
3345
    }
3346

    
3347
    private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3348
        if (cc.size() == 2) {
3349
            return null;
3350
        }
3351

    
3352
        if (cc.size() == 3) {
3353
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1))) {
3354
                return null;
3355
            }
3356

    
3357
            if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2))) {
3358
                return null;
3359
            }
3360

    
3361
            if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2))) {
3362
                return null;
3363
            }
3364

    
3365
            cc.add(cc.get(0));
3366

    
3367
            return cc;
3368
        }
3369

    
3370
        if (!sameCoordinate((Coordinate) cc.get(0),
3371
                    (Coordinate) cc.get(cc.size() - 1))) {
3372
            cc.add(cc.get(0));
3373
        }
3374

    
3375
        return cc;
3376
    }
3377

    
3378
    private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3379
        Coordinate[] p = new Coordinate[4];
3380
        p[0] = c;
3381

    
3382
        Coordinate nc = new Coordinate(c);
3383
        nc.x = nc.x + IRRELEVANT_DISTANCE;
3384

    
3385
        Coordinate nc2 = new Coordinate(nc);
3386
        nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3387
        p[1] = nc;
3388
        p[2] = nc2;
3389
        p[3] = new Coordinate(c);
3390

    
3391
        CoordinateArraySequence cs = new CoordinateArraySequence(p);
3392
        LinearRing ls = new LinearRing(cs, geomFactory);
3393
        Polygon po = new Polygon(ls, null, geomFactory);
3394
        Polygon[] pos = new Polygon[1];
3395
        pos[0] = po;
3396

    
3397
        MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3398

    
3399
        return mpo;
3400
    }
3401

    
3402
    public String getSourceProjection() {
3403
        // TODO Auto-generated method stub
3404
        if (tableHasSrid) {
3405
            return epsgSRID;
3406
        }
3407

    
3408
        return destProj;
3409
    }
3410

    
3411
    public String getDestProjection() {
3412
        return destProj;
3413
    }
3414

    
3415
    public void setDestProjection(String toEPSG) {
3416
        destProj = toEPSG;
3417
        try {
3418
                        destProjOracle = epsgSridToOracleSrid(destProj);
3419
                        isDestGeogCS = getIsGCS(destProjOracle, true);
3420
                        
3421
                } catch (Exception e) {
3422
                        logger.error("Unknown EPSG code: " + destProj);
3423
                        destProjOracle = oracleSRID;
3424
                        isDestGeogCS = false;
3425
                }
3426
        
3427
    }
3428
    
3429
    public String getDestProjectionOracleCode() {
3430
            return destProjOracle;
3431
    }
3432
    
3433
    public boolean getIsDestProjectionGeog() {
3434
            return isDestGeogCS;
3435
    }
3436
    
3437
    public String getTableProjectionOracleCode() {
3438
            return oracleSRID;
3439
    }
3440

    
3441
    public boolean canReproject(String toEPSGdestinyProjection) {
3442
        return false;
3443
    }
3444

    
3445
    /**
3446
     * Utility function. Says whether a given field name can be a user field name
3447
     * or not (for example, "ROWID" is not a valid one because it's a system
3448
     * reserved word).
3449
     *
3450
     * @param str proposed firld name
3451
     * @return whether it is valid or not for Oracle databases
3452
     */
3453
    private static boolean isOracleAllowedFieldname(String str) {
3454
        if (str.compareToIgnoreCase("rowid") == 0) {
3455
            return false;
3456
        }
3457

    
3458
        if (str.compareToIgnoreCase("rownum") == 0) {
3459
            return false;
3460
        }
3461

    
3462
        return true;
3463
    }
3464

    
3465
    public Hashtable getHashRelate() {
3466
        return hashRelate;
3467
    }
3468

    
3469
    public void setHashRelate(Hashtable m) {
3470
        hashRelate = m;
3471
    }
3472

    
3473
    public void setNumReg(int n) {
3474
        numReg = n;
3475
    }
3476

    
3477
    private int[] getRandomSample(int maxn_one_based, int n) {
3478
        int[] resp = new int[n];
3479

    
3480
        if (maxn_one_based <= n) {
3481
            resp = new int[maxn_one_based];
3482

    
3483
            for (int i = 0; i < maxn_one_based; i++) {
3484
                resp[i] = i;
3485
            }
3486
        }
3487
        else {
3488
            Random rnd = new Random();
3489

    
3490
            for (int i = 0; i < n; i++) {
3491
                resp[i] = rnd.nextInt(maxn_one_based);
3492
            }
3493
        }
3494

    
3495
        return resp;
3496
    }
3497

    
3498
    private String getRowIdRestrictionCondition(int nrecords) {
3499
        int[] zero_based_rows = getRandomSample(nrecords,
3500
                GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3501
        String resp = "(";
3502
        Object aux = "";
3503
        ROWID riaux = null;
3504

    
3505
        for (int i = 0; i < zero_based_rows.length; i++) {
3506
            aux = rowToId.get(new Integer(zero_based_rows[i]));
3507
            riaux = (ROWID) aux;
3508
            resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3509
        }
3510

    
3511
        resp = resp.substring(0, resp.length() - 4);
3512
        resp = resp + ")";
3513

    
3514
        return resp;
3515
    }
3516

    
3517
    private Rectangle2D getBoundingFromSample(int n_max) {
3518
        String _qry = "SELECT " + geoColName + " FROM " + getTableName() +
3519
            " WHERE " + getRowIdRestrictionCondition(n_max);
3520
        STRUCT auxstr = null;
3521
        IGeometry theGeom = null;
3522
        Rectangle2D resp = null;
3523

    
3524
        try {
3525
            Statement st = conn.createStatement();
3526
            ResultSet rs = st.executeQuery(_qry);
3527

    
3528
            if (rs.next()) {
3529
                auxstr = (STRUCT) rs.getObject(1);
3530

    
3531
                if (auxstr != null) {
3532
                    theGeom = getGeometryUsing(auxstr, use_geotools);
3533

    
3534
                    if (resp == null) {
3535
                        resp = theGeom.getBounds2D();
3536
                    }
3537
                    else {
3538
                        resp.add(theGeom.getBounds2D());
3539
                    }
3540
                }
3541

    
3542
                while (rs.next()) {
3543
                    auxstr = (STRUCT) rs.getObject(1);
3544

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

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

    
3557
                rs.close();
3558
                st.close();
3559
            }
3560
            else {
3561
                throw new SQLException("Empty resultset from this query: " +
3562
                    _qry);
3563
            }
3564
        }
3565
        catch (SQLException se) {
3566
            System.err.println("Error while getting sample full extent: " +
3567
                se.getMessage());
3568
        }
3569

    
3570
        if (resp == null) {
3571
            logger.warn(
3572
                "Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3573

    
3574
            return new Rectangle2D.Double(-180, -90, 360, 180);
3575
        }
3576

    
3577
        return resp;
3578
    }
3579

    
3580
    /**
3581
     * Does what it says, puts the LinearRing in counter clock wise
3582
     * order.
3583
     * @param ls The ring to set.
3584
     * @param gf a GeometryFactory object
3585
     * @return A new ring in CCW order.
3586
     *
3587
     */
3588
    public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3589
        Coordinate[] cc = ls.getCoordinates();
3590

    
3591
        if (CGAlgorithms.isCCW(cc)) {
3592
            return gf.createLinearRing(cc);
3593
        }
3594
        else {
3595
            if (ls instanceof LinearRing) {
3596
                return reverseRing((LinearRing) ls, gf);
3597
            }
3598
            else {
3599
                return reverseLineString(ls, gf);
3600
            }
3601
        }
3602
    }
3603

    
3604
    /**
3605
     * Does what it says, reverses the order of the Coordinates in the ring.
3606
     * @param lr The ring to reverse.
3607
     * @return A new ring with the reversed Coordinates.
3608
     *
3609
     */
3610
    public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3611
        int numPoints = lr.getNumPoints() - 1;
3612
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3613

    
3614
        for (int t = numPoints; t >= 0; t--) {
3615
            newCoords[t] = lr.getCoordinateN(numPoints - t);
3616
        }
3617

    
3618
        return gf.createLinearRing(newCoords);
3619
    }
3620

    
3621
    /**
3622
     * Does what it says, reverses the order of the Coordinates in the linestring.
3623
     * @param ls The ls to reverse.
3624
     * @param gf a GeometryFactory object 
3625
     * @return A new ls with the reversed Coordinates.
3626
     *
3627
     */
3628
    public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3629
        int numPoints = ls.getNumPoints() - 1;
3630
        Coordinate[] newCoords = new Coordinate[numPoints + 1];
3631

    
3632
        for (int t = numPoints; t >= 0; t--) {
3633
            newCoords[t] = ls.getCoordinateN(numPoints - t);
3634
        }
3635

    
3636
        return gf.createLinearRing(newCoords);
3637
    }
3638

    
3639
    private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3640
        if (ge instanceof MultiPolygon) {
3641
            MultiPolygon mp = (MultiPolygon) ge;
3642
            int size = ge.getNumGeometries();
3643
            Polygon[] pols = new Polygon[size];
3644

    
3645
            for (int i = 0; i < size; i++)
3646
                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i),
3647
                        gf);
3648

    
3649
            return new MultiPolygon(pols, gf);
3650
        }
3651
        else {
3652
            if (ge instanceof Polygon) {
3653
                Polygon p = (Polygon) ge;
3654
                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3655
                int nholes = p.getNumInteriorRing();
3656

    
3657
                if (nholes > 0) {
3658
                    LinearRing[] holes = new LinearRing[nholes];
3659

    
3660
                    for (int i = 0; i < nholes; i++) {
3661
                        holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3662
                    }
3663

    
3664
                    return gf.createPolygon(exterior, holes);
3665
                }
3666
                else {
3667
                    return gf.createPolygon(exterior, null);
3668
                }
3669
            }
3670
            else {
3671
                return ge;
3672
            }
3673
        }
3674
    }
3675

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

    
3694
            return OracleSpatialUtils.appendGeometriesInStruct(coll,
3695
                _forced_type, _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3696

    
3697
            // logger.error("Collections no soportadas por ahora.");
3698
            // return null;
3699
        }
3700
        else {
3701
            Shape shp = ig.getInternalShape();
3702

    
3703
            return shapeToStruct(shp, _forced_type, _conn, _o_srid, withSrid,
3704
                agu_bien, false, _isGeoCS);
3705
        }
3706
    }
3707

    
3708
    public STRUCT shapeToStruct(Shape shp, int force_type, boolean hasSrid,
3709
        boolean agu_bien, boolean isView) {
3710
            
3711
            if (shp == null) return null; 
3712
        return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid,
3713
            agu_bien, isView, isGeogCS);
3714
    }
3715

    
3716
    public static STRUCT shapeToStruct(Shape shp, int forced_type,
3717
        Connection _conn, String o_srid, boolean hasSrid, boolean agu_bien,
3718
        boolean isView, boolean _isGeoCS) {
3719
        int _srid = -1;
3720

    
3721
        if (o_srid.length() > 0) {
3722
            _srid = Integer.parseInt(o_srid);
3723
        }
3724

    
3725
        if (shp == null) {
3726
            logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3727

    
3728
            return null;
3729
        }
3730

    
3731
        if (shp instanceof Rectangle2D) {
3732
            return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3733
                _isGeoCS, o_srid, _conn);
3734
        }
3735

    
3736
        try {
3737
            STRUCT the_struct = OracleSpatialUtils.fShapeToSTRUCT(shp, _conn,
3738
                    _srid, agu_bien, hasSrid);
3739

    
3740
            return the_struct;
3741
        }
3742
        catch (SQLException ex) {
3743
            logger.error("While creating STRUCT: " + ex.getMessage());
3744

    
3745
            return null;
3746
        }
3747
    }
3748

    
3749
    // -------------------------- not ready yet ----------------
3750
    public int getRowIndexByFID(IFeature _fid) {
3751
        if (isNotAvailableYet) {
3752
            return -1;
3753
        }
3754
        else {
3755
            return super.getRowIndexByFID(_fid);
3756
        }
3757
    }
3758

    
3759
    public int getShapeCount() throws IOException {
3760
        if (isNotAvailableYet) {
3761
            return 0;
3762
        }
3763
        else {
3764
            return numReg;
3765
        }
3766
    }
3767

    
3768
    public void setNotAvailableYet(boolean nav) {
3769
        isNotAvailableYet = nav;
3770
    }
3771

    
3772
    // -------------------------------------------------------
3773
    // -------------------------------------------------------
3774
    public String[] getTableNames(Connection conn, String catalog)
3775
        throws SQLException {
3776
        DatabaseMetaData dbmd = conn.getMetaData();
3777
        String[] types = { "TABLE", "VIEW" };
3778
        // String[] types = { "VIEW" };
3779

    
3780
        ResultSet rs = null;
3781
        rs = getTableNamesFromTable(dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3782
                    ORACLE_GEOMETADATA_VIEW, types), conn);
3783
//        rs = dbmd.getTables(catalog, ORACLE_GEO_SCHEMA,
3784
//                          ORACLE_GEOMETADATA_VIEW, types);
3785
        TreeMap ret = new TreeMap();
3786

    
3787
        while (rs.next()) {
3788
                String nomCompleto = rs.getString("OWNER") + "." +rs.getString("TABLE_NAME");
3789
            ret.put(nomCompleto, nomCompleto);
3790
        }
3791

    
3792
        return (String[]) ret.keySet().toArray(new String[0]);
3793
    }
3794

    
3795
    private ResultSet getTableNamesFromTable(ResultSet res, Connection con)
3796
        throws SQLException {
3797
        String tablename = "";
3798
        
3799
        
3800

    
3801
        if (res.next()) {
3802
            tablename = res.getString("TABLE_NAME");
3803
            
3804
            // debug 
3805
            writeMetaTableToLog(con, tablename);
3806

    
3807
            Statement __st = con.createStatement();
3808

    
3809
            String sql = "(" + "(select TABLE_NAME from USER_TABLES) " +
3810
                "union (select VIEW_NAME from USER_VIEWS)) " +
3811
                "intersect (select TABLE_NAME from " + tablename + ")";
3812
            sql = "SELECT TABLE_NAME, OWNER FROM " + tablename + "";
3813
            ResultSet rs = __st.executeQuery(sql);
3814

    
3815
            return rs;
3816
        }
3817
        else {
3818
            logger.error("Error while getting geometry tables.");
3819

    
3820
            return null;
3821
        }
3822
    }
3823

    
3824
    private void writeMetaTableToLog(Connection con, String tname) {
3825
            
3826
            logger.debug("======================================================");
3827
            logger.debug("=     " + ORACLE_GEOMETADATA_VIEW + "     =====================");
3828
            logger.debug("======================================================");
3829

    
3830
            try {
3831
            Statement _stmt = con.createStatement();
3832
            String sql = "SELECT * FROM " + tname;
3833
            ResultSet res = _stmt.executeQuery(sql);
3834
            while (res.next()) {
3835
                    logger.debug("======================================================");
3836
                    logger.debug("OWNER: " + res.getString("OWNER"));
3837
                    logger.debug("TABLE_NAME: " + res.getString("TABLE_NAME"));
3838
                    logger.debug("COLUMN_NAME: " + res.getString("COLUMN_NAME"));
3839
                    logger.debug("SRID: " + res.getString("SRID"));
3840
                    
3841
                    ARRAY _aux = (ARRAY) res.getObject("DIMINFO");
3842
                    String dinfo = OracleSpatialUtils.getDimInfoAsString(_aux);
3843
                    logger.debug("DIMINFO: " + dinfo);
3844
                    logger.debug("======================================================");
3845
                    
3846
            }
3847
            } catch (Throwable th) {
3848
                    
3849
            }
3850
            
3851
            
3852
            
3853
            
3854
            
3855
                // TODO Auto-generated method stub
3856
                
3857
        }
3858

    
3859
        /**
3860
     * Gets the field names that can act as row id (always ROWID)
3861
     */
3862
    public String[] getIdFieldsCandidates(Connection conn, String table_name)
3863
        throws SQLException {
3864
            
3865
            String rowid_avail_test = "SELECT ROWID FROM " + table_name + " WHERE ROWNUM = 1";
3866
            Statement _st = conn.createStatement();
3867
            ResultSet _rs = _st.executeQuery(rowid_avail_test);
3868
            _rs.close();
3869
            _st.close();
3870

    
3871
            String[] resp = { "ROWID" };
3872
        return resp;
3873
    }
3874

    
3875
    /**
3876
     * Gets the field names that can act as geometry fields
3877
     * (queries the user's geographic metadata).
3878
     */
3879
    public String[] getGeometryFieldsCandidates(Connection conn,
3880
        String table_name) throws SQLException {
3881
            
3882
        Statement _st = conn.createStatement();
3883
        String[] tokens = table_name.split("\\u002E", 2);
3884
        String qry;
3885
        if (tokens.length > 1)
3886
        {
3887
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3888
            " where OWNER = '" + tokens[0] + "' AND TABLE_NAME = '" + 
3889
            tokens[1] + "'";
3890
        }
3891
        else
3892
        {
3893
                qry = "select * from " + ORACLE_GEOMETADATA_VIEW +
3894
            " where TABLE_NAME = " + "'" + table_name + "'";
3895

    
3896
        }
3897
        ResultSet _rs = _st.executeQuery(qry);
3898

    
3899
        ArrayList aux = new ArrayList();
3900

    
3901
        while (_rs.next()) {
3902
            String _geo = _rs.getString("COLUMN_NAME");
3903
            aux.add(_geo);
3904
        }
3905

    
3906
        _rs.close();
3907
        _st.close();
3908

    
3909
        String[] resp = (String[]) aux.toArray(new String[0]); 
3910
        
3911
        return checkIndexes(conn, resp, table_name);
3912
    }
3913

    
3914
    private String[] checkIndexes(Connection c, String[] all, String __t) throws SQLException {
3915

    
3916
            ArrayList good_ones = new ArrayList();
3917
            String t = __t;
3918
            if (t.lastIndexOf(".") != -1) t = t.substring(t.lastIndexOf(".") + 1, t.length());
3919

    
3920
            for (int i=0; i<all.length; i++) {
3921
                    
3922
                String qry = "SELECT SRID, DIMINFO FROM " + ORACLE_GEOMETADATA_VIEW +
3923
            " WHERE TABLE_NAME = " + "'" + t.toUpperCase() +
3924
            "' AND COLUMN_NAME = '" + all[i].toUpperCase() + "'";
3925
                
3926
                Statement _st = c.createStatement();
3927
                ResultSet _rs = _st.executeQuery(qry);
3928
                if (_rs.next()) {
3929
                        String _srid = toString((BigDecimal) _rs.getObject(1));
3930
                        ARRAY diminfo = (ARRAY) _rs.getObject(2);
3931
                        int len = diminfo.getOracleArray().length;
3932
                        if (allowsGeoQueries(c, t, all[i], _srid, len)) {
3933
                                good_ones.add(all[i]);
3934
                        }
3935
                }
3936
                _rs.close();
3937
                _st.close();
3938
            }
3939
            
3940
            if (good_ones.size() == 0) {
3941
                    throw new SQLException("no_indexes_on_declared_geo_fields");
3942
            }
3943
            return (String[]) good_ones.toArray(new String[0]);
3944
    }
3945
    
3946
    private String toString(BigDecimal number) {
3947
            
3948
            if (number == null) return "NULL";
3949
            return "" + number.intValue();
3950
        }
3951

    
3952
        private boolean allowsGeoQueries(Connection c, String _t, String gf, String _srid, int dims) {
3953
            String p = getPointConstructor(dims, _srid);
3954
            String qry = "SELECT * FROM " + _t.toUpperCase() + " WHERE (ROWNUM = 1)";
3955
            qry = "SELECT * FROM (" + qry + ") WHERE SDO_RELATE(" + "\"" + gf + "\", " + p + ", 'mask=TOUCH') = 'TRUE'";
3956

    
3957
            try {
3958
                        Statement _st = c.createStatement();
3959
                        ResultSet _rs = _st.executeQuery(qry);
3960
                        _rs.close();
3961
                        _st.close();
3962
                } catch (Exception ex) {
3963
                        return false;
3964
                }
3965
                return true;
3966
        }
3967

    
3968
        private String getPointConstructor(int dims, String _srid) {
3969
                
3970
                String coord = "";
3971
                for (int i=0; i<dims; i++) coord = coord + "0, ";
3972
                coord = coord.substring(0, coord.length() - 2);
3973
                
3974
                return "MDSYS.SDO_GEOMETRY(" + (dims * 1000 + 1) + ", " + _srid + ", NULL, " +
3975
                "MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1), MDSYS.SDO_ORDINATE_ARRAY(" + coord + "))";
3976
        }
3977

    
3978
        private boolean stringInArrayListOfStrings(ArrayList l, String str) {
3979
            
3980
            if (l == null) return false;
3981
            if (str == null) return false;
3982
            
3983
            String item = "";
3984
            for (int i=0; i<l.size(); i++) {
3985
                    if (l.get(i) instanceof String) {
3986
                            item = (String) l.get(i);
3987
                            if (item.compareToIgnoreCase(str) == 0) return true;
3988
                    }
3989
            }
3990
            return false;
3991
    }
3992

    
3993
        /**
3994
     * Utility method to check if a given table is empty.
3995
     */
3996
    public boolean isEmptyTable(Connection conn, String tableName) {
3997
        boolean res = true;
3998

    
3999
        try {
4000
            Statement st = conn.createStatement();
4001
            ResultSet rs = null;
4002
            rs = st.executeQuery("select * from " + tableName +
4003
                    " where rownum = 1");
4004
            res = !rs.next();
4005
            rs.close();
4006
            st.close();
4007
        }
4008
        catch (Exception ex) {
4009
            res = true;
4010
        }
4011

    
4012
        return res;
4013
    }
4014

    
4015
    /**
4016
     * Gets all the fields from a table name.
4017
     */
4018
    public String[] getAllFields(Connection conn, String table_name)
4019
        throws SQLException {
4020
        Statement st = conn.createStatement();
4021
        ResultSet rs = st.executeQuery("select * from " + table_name +
4022
                " where rownum = 1");
4023
        ResultSetMetaData rsmd = rs.getMetaData();
4024
        String[] ret = new String[rsmd.getColumnCount()];
4025

    
4026
        for (int i = 0; i < ret.length; i++) {
4027
            ret[i] = rsmd.getColumnName(i + 1);
4028
        }
4029

    
4030
        rs.close();
4031
        st.close();
4032

    
4033
        return ret;
4034
    }
4035

    
4036
    /**
4037
     * Gets all field type names from a table.
4038
     */
4039
    public String[] getAllFieldTypeNames(Connection conn, String table_name)
4040
        throws SQLException {
4041
        Statement st = conn.createStatement();
4042
        ResultSet rs = st.executeQuery("select * from " + table_name +
4043
                " where rownum = 1");
4044
        ResultSetMetaData rsmd = rs.getMetaData();
4045
        String[] ret = new String[rsmd.getColumnCount()];
4046

    
4047
        for (int i = 0; i < ret.length; i++) {
4048
            ret[i] = rsmd.getColumnTypeName(i + 1);
4049
        }
4050

    
4051
        rs.close();
4052
        st.close();
4053

    
4054
        close();
4055

    
4056
        return ret;
4057
    }
4058

    
4059
    /**
4060
     * Gets Oracle's specific connection string for the given parameters.
4061
     */
4062
    public String getConnectionString(String host, String port, String dbname,
4063
        String user, String pw) {
4064
        String _pw = pw;
4065

    
4066
        if (_pw == null) {
4067
            _pw = "null";
4068
        }
4069

    
4070
        String fullstr = CONN_STR_BEGIN;
4071
        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
4072
        fullstr = fullstr + "@" + host.toLowerCase();
4073
        fullstr = fullstr + ":" + port;
4074
        fullstr = fullstr + ":" + dbname.toLowerCase();
4075

    
4076
        return fullstr;
4077
    }
4078

    
4079
    /**
4080
     * Gets the Pracle geometries writer associated with this driver.
4081
     */
4082
    public IWriter getWriter() {
4083
        // on(VectorialEditableDBAdapter.java:290)
4084
        if (writer == null) {
4085
            writer = new OracleSpatialWriter(getRowCount());
4086
            writer.setDriver(this);
4087
            writer.setLyrShapeType(getShapeType());
4088
            writer.setGeoCS(isGeogCS());
4089
            writer.setGeoColName(geoColName);
4090
            writer.setSRID(oracleSRID);
4091

    
4092
            try {
4093
                writer.initialize(getLyrDef());
4094
            }
4095
            catch (EditionException e) {
4096
                logger.error("While initializing OS Writer: " + e.getMessage(),
4097
                    e);
4098
            }
4099

    
4100
            writer.setStoreWithSrid(tableHasSrid);
4101
        }
4102

    
4103
        return writer;
4104
    }
4105

    
4106
    /**
4107
     * Tells whether the SRS is geodetic or not
4108
     * @return whether the SRS is geodetic or not
4109
     */
4110
    public boolean isGeogCS() {
4111
        return isGeogCS;
4112
    }
4113

    
4114
    /**
4115
     * Adds a row id to the inner set od IDs.
4116
     * @param id
4117
     */
4118
    public void addRow(String id) {
4119
        Value aux = ValueFactory.createValue(id);
4120
        Integer intobj = new Integer(numReg);
4121
        hashRelate.put(aux, intobj);
4122
        rowToId.put(intobj, id);
4123

    
4124
        numReg++;
4125
    }
4126

    
4127
    /**
4128
     * Removes a row id to the inner set od IDs.
4129
     * @param id
4130
     */
4131
    public void deleteRow(String id) {
4132
        Value aux = ValueFactory.createValue(id);
4133
        Integer intobj = (Integer) hashRelate.get(aux);
4134
        hashRelate.remove(aux);
4135
        rowToId.remove(intobj);
4136

    
4137
        numReg--;
4138
    }
4139

    
4140
    private String getStandardSelectExpression() {
4141
        if (standardSelectExpressionFalse == null) {
4142
            standardSelectExpressionFalse = "";
4143

    
4144
            String[] flds = getLyrDef().getFieldNames();
4145
            int size = flds.length;
4146

    
4147
            for (int i = 0; i < size; i++) {
4148
                if (i > 0) {
4149
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4150
                        "c.\"" + flds[i] + "\", ";
4151
                }
4152
                else {
4153
                    standardSelectExpressionFalse = standardSelectExpressionFalse +
4154
                        flds[i] + ", ";
4155
                }
4156
            }
4157

    
4158
            // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
4159
            standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
4160
                    standardSelectExpressionFalse.length() - 2);
4161
        }
4162

    
4163
        return standardSelectExpressionFalse;
4164
    }
4165

    
4166
    /**
4167
     * Allows the method to decide what to do with the geometry field name
4168
     * (remove/add it from the user selected fields).
4169
     *
4170
     * @param flds
4171
     * @param geof
4172
     * @return the possibly modified field names
4173
     */
4174
    public String[] manageGeometryField(String[] flds, String geof) {
4175
        return addEndIfNotContained(flds, geof);
4176
    }
4177

    
4178
    /**
4179
     * Allows the method to decide what to do with the ID field name
4180
     * (remove/add it from the user selected fields).
4181
     *
4182
     * @param flds
4183
     * @param idf
4184
     * @return the possibly modified field names
4185
     */
4186
    public String[] manageIdField(String[] flds, String idf) {
4187
        return addStartIfNotContained(flds, idf);
4188
    }
4189

    
4190
    private String[] addEndIfNotContained(String[] arr, String item) {
4191
        if (contains(arr, item)) {
4192
            return arr;
4193
        }
4194
        else {
4195
            int size = arr.length;
4196
            String[] resp = new String[size + 1];
4197

    
4198
            for (int i = 0; i < size; i++) {
4199
                resp[i] = arr[i];
4200
            }
4201

    
4202
            resp[size] = item;
4203

    
4204
            return resp;
4205
        }
4206
    }
4207

    
4208
    private String[] addStartIfNotContained(String[] arr, String item) {
4209
        if (contains(arr, item)) {
4210
            return arr;
4211
        }
4212
        else {
4213
            int size = arr.length;
4214
            String[] resp = new String[size + 1];
4215

    
4216
            for (int i = 1; i <= size; i++) {
4217
                resp[i] = arr[i];
4218
            }
4219

    
4220
            resp[0] = item;
4221

    
4222
            return resp;
4223
        }
4224
    }
4225

    
4226
    private boolean contains(String[] arr, String item) {
4227
        for (int i = 0; i < arr.length; i++) {
4228
            if (arr[i].compareTo(item) == 0) {
4229
                return true;
4230
            }
4231
        }
4232

    
4233
        return false;
4234
    }
4235

    
4236
    /**
4237
     * This method is called when the user removes the layer from the view.
4238
     * If the IDs were being loaded, the driver will check this field and will
4239
     * let the thread 'die' quietly.
4240
     *
4241
     */
4242
    public void remove() {
4243
        cancelIDLoad = true;
4244
    }
4245
    
4246
    private boolean realiableExtent(Rectangle2D ext, boolean isgeodetic) {
4247
            // if (!isgeodetic) return true;
4248
            if ((ext.getMinX() > -179.9) || (ext.getMinX() < -180.1)) return true; 
4249
            if ((ext.getMinY() > -89.9) || (ext.getMinY() < -90.1)) return true; 
4250
            if ((ext.getWidth() < 359.9) || (ext.getWidth() > 360.1)) return true; 
4251
            if ((ext.getHeight() < 179.9) || (ext.getHeight() > 180.1)) return true; 
4252
            return false;
4253
    }
4254
    
4255
    private Rectangle2D getFastEstimatedGeodeticExtent(
4256
                    String tname, String gfield, Connection c, int sample_size, double enlargement) {
4257

    
4258
            Rectangle2D world = new Rectangle2D.Double(-180, -90, 360, 180);
4259
            Rectangle2D resp_aux = null;
4260
            String qry = "SELECT " + gfield + " FROM " + tname + " WHERE ROWNUM <= " + sample_size;
4261
            ResultSet _rs = null;
4262

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

    
4333
            try {
4334
                        PreparedStatement _st = c.prepareStatement(qry);
4335
                        _rs = _st.executeQuery();
4336
                        while (_rs.next()) {
4337
                                STRUCT aux = (STRUCT) _rs.getObject(1);
4338
                                IGeometry ig = getGeometryUsing(aux, false);
4339
                                
4340
                                if (ig == null) continue;
4341
                                
4342
                                if (resp_aux == null) {
4343
                                        resp_aux = ig.getBounds2D();
4344
                                } else {
4345
                                        resp_aux.add(ig.getBounds2D());
4346
                                }
4347
                                
4348
                        }
4349
                } catch (Exception ex) {
4350
                        logger.error("While getting random sample: " + ex.getMessage());
4351
                        return world;
4352
                }
4353
                
4354
                if (resp_aux == null) return world;
4355
                double w = resp_aux.getWidth();
4356
                double h = resp_aux.getHeight();
4357
                double x = resp_aux.getMinX();
4358
                double y = resp_aux.getMinY();
4359
                
4360
                // enlarge 10 times:
4361
                double newx = x - (0.5 * (enlargement - 1)) * w;
4362
                double newy = y - (0.5 * (enlargement - 1)) * w;
4363
                Rectangle2D resp_aux_large = new Rectangle2D.Double(newx, newy,
4364
                                enlargement * w,
4365
                                enlargement * h);
4366
                
4367
                
4368
                Rectangle2D.intersect(world, resp_aux_large, resp_aux);
4369
                return resp_aux;
4370
    }
4371
    
4372
    public void setUserName(String u) {
4373
            userName = u;
4374
    }
4375
    
4376
    public String getUserName() {
4377
            return userName;
4378
    }
4379
}