Statistics
| Revision:

svn-gvsig-desktop / branches / v10 / extensions / extJDBC / src / com / iver / cit / gvsig / fmap / drivers / jdbc / oracle / OracleSpatialDriver.java @ 10172

History | View | Annotate | Download (97.3 KB)

1
package com.iver.cit.gvsig.fmap.drivers.jdbc.oracle;
2

    
3
import java.awt.Shape;
4
import java.awt.geom.Point2D;
5
import java.awt.geom.Rectangle2D;
6
import java.io.File;
7
import java.io.IOException;
8
import java.sql.Connection;
9
import java.sql.DatabaseMetaData;
10
import java.sql.ResultSet;
11
import java.sql.ResultSetMetaData;
12
import java.sql.SQLException;
13
import java.sql.Statement;
14
import java.sql.Types;
15
import java.text.ParseException;
16
import java.util.ArrayList;
17
import java.util.HashMap;
18
import java.util.Hashtable;
19
import java.util.Iterator;
20
import java.util.Random;
21
import java.util.TreeMap;
22

    
23
import oracle.jdbc.OracleConnection;
24
import oracle.spatial.geometry.JGeometry;
25
import oracle.sql.ARRAY;
26
import oracle.sql.Datum;
27
import oracle.sql.NUMBER;
28
import oracle.sql.ROWID;
29
import oracle.sql.STRUCT;
30
import oracle.sql.StructDescriptor;
31

    
32
import org.apache.log4j.Logger;
33
import org.geotools.data.oracle.sdo.GeometryConverter;
34

    
35
import com.hardcode.gdbms.engine.data.DataSource;
36
import com.hardcode.gdbms.engine.data.DataSourceFactory;
37
import com.hardcode.gdbms.engine.data.SourceInfo;
38
import com.hardcode.gdbms.engine.data.edition.DataWare;
39
import com.hardcode.gdbms.engine.data.file.FileSourceInfo;
40
import com.hardcode.gdbms.engine.spatial.fmap.FShapeGeneralPathX;
41
import com.hardcode.gdbms.engine.values.DoubleValue;
42
import com.hardcode.gdbms.engine.values.Value;
43
import com.hardcode.gdbms.engine.values.ValueFactory;
44

    
45
import com.iver.cit.gvsig.fmap.DriverException;
46
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
47
import com.iver.cit.gvsig.fmap.core.FGeometryCollection;
48
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
49
import com.iver.cit.gvsig.fmap.core.FNullGeometry;
50
import com.iver.cit.gvsig.fmap.core.FPoint2D;
51
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
52
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
53
import com.iver.cit.gvsig.fmap.core.FShape;
54
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
55
import com.iver.cit.gvsig.fmap.core.ICanReproject;
56
import com.iver.cit.gvsig.fmap.core.IFeature;
57
import com.iver.cit.gvsig.fmap.core.IGeometry;
58
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
59
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
60
import com.iver.cit.gvsig.fmap.drivers.DBLayerDefinition;
61
import com.iver.cit.gvsig.fmap.drivers.DefaultDBDriver;
62
import com.iver.cit.gvsig.fmap.drivers.DriverAttributes;
63
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
64
import com.iver.cit.gvsig.fmap.drivers.IFeatureIterator;
65
import com.iver.cit.gvsig.fmap.drivers.dbf.DBFDriver;
66
import com.iver.cit.gvsig.fmap.edition.EditableAdapter;
67
import com.iver.cit.gvsig.fmap.edition.EditionException;
68
import com.iver.cit.gvsig.fmap.edition.IWriteable;
69
import com.iver.cit.gvsig.fmap.edition.IWriter;
70
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
71
import com.iver.cit.gvsig.fmap.layers.SelectableDataSource;
72
import com.iver.cit.gvsig.project.documents.table.ProjectTable;
73
import com.iver.cit.gvsig.project.documents.table.ProjectTableFactory;
74
import com.vividsolutions.jts.algorithm.CGAlgorithms;
75
import com.vividsolutions.jts.geom.Coordinate;
76
import com.vividsolutions.jts.geom.Geometry;
77
import com.vividsolutions.jts.geom.GeometryFactory;
78
import com.vividsolutions.jts.geom.LineString;
79
import com.vividsolutions.jts.geom.LinearRing;
80
import com.vividsolutions.jts.geom.MultiPolygon;
81
import com.vividsolutions.jts.geom.Polygon;
82
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
83

    
84
/**
85
 * Vectorial driver to access Oracle databases. Should work on Oracle Locator.
86
 * 
87
 * @author jldominguez
88
 *
89
 */
90
public class OracleSpatialDriver extends DefaultDBDriver implements
91
                ICanReproject, IWriteable {
92

    
93
        private static Logger logger = Logger.getLogger(OracleSpatialDriver.class.getName());
94
        
95
        private OracleSpatialWriter writer = null;
96
        
97
        private static double FLATNESS = 0.8;
98
        private static int FETCH_SIZE = 15000;
99

    
100
        // utility object to convert geometries.
101
        private GeometryConverter geotools_conv;
102
        // switch variable
103
        private boolean use_geotools = false;
104

    
105
        // constants 
106
        public static final int GEODETIC_FULLEXTENT_SAMPLE_SIZE = 50;
107
        public static final String GEODETIC_SRID = "8307";
108
        public static final String ASSUMED_ORACLE_SRID = "8307";
109
        private boolean tableHasSrid = true;
110
        
111
        // ------------------------------------------------
112
        private boolean isNotAvailableYet = true;
113
        private IGeometry nullGeom = new FNullGeometry();
114
        private Value nullVal = ValueFactory.createNullValue();
115
        private String nullSampleSqlCondition = "(ROWNUM = 1)";
116
        // private EmptyFeatureIterator emptyIt = new EmptyFeatureIterator();
117
        private IdLoaderThread idLoader;
118
//        private FLayer myLayer = null;
119
//        private TOC myTOC = null;
120
        // ------------------------------------------------
121
        
122
        public static final String NAME = "Oracle Spatial Database Driver";
123
        public static final int ID_COLUMN_INDEX = 1;
124
        public static final String ORACLE_GEOMETADATA_VIEW = "USER_SDO_GEOM_METADATA";
125
        public static final String ORACLE_EPSG_TABLE_NAME = "ORA_EPSG";
126
        public static final String ORACLE_EPSG_FILE_NAME = "ora_epsg.dbf";
127
        public static final String DEFAULT_GEO_FIELD = "GEOMETRY";
128
        public static final String ORACLE_ID_FIELD = "ROWID";
129
        public static final String DEFAULT_ID_FIELD = "GID";
130
        public static final String ORACLE_GEO_SCHEMA = "MDSYS";
131
        public static final String CONN_STR_BEGIN = "jdbc:oracle:thin:";
132
        public static final int VARCHAR2_STANDARD_SIZE = 80;
133
        public static final int VARCHAR2_LONG_SIZE = 256;
134
        public static final int MAX_ID_LENGTH = 30;
135
        private final static GeometryFactory geomFactory = new GeometryFactory();
136
        
137
        public static final double IRRELEVANT_DISTANCE = 0.00000001;
138
        private DriverAttributes drvAtts;
139
        private int[] pkOneBasedIndexes;
140
        private String[] fieldNames;
141
        private String not_restricted_sql = "";
142
        private Shape originalOracleWorkingArea;
143
        private STRUCT originalOracleWAStruct = null;
144
        private String idFieldNames;
145
        private int oneBasedGeoColInd = 0;
146
        private int shapeType = -1;
147
        private boolean needsCollectionLayer = true;
148

    
149
        // ----------------------------------------------
150
        // one feature is cached to avoid querying for each attribute request:
151
        private IFeature singleCachedFeature = null;
152
        private long singleCachedFeatureRowNum = -1;
153
        // ----------------------------------------------
154
        private boolean cancelIDLoad = false;
155
        // ----------------------------------------------
156

    
157
        private String geoColName = "";
158
        private String oracleSRID;
159
        private String epsgSRID;
160
        private String destProj = "";
161
        private Rectangle2D fullExtent = null;
162
        private boolean emptyWhereClause = true;
163
        
164
        private boolean isGeogCS = false;
165

    
166
        // new hash map to perform queries by row number:
167
        private HashMap rowToId = new HashMap();
168

    
169
        private String standardSelectExpressionTrue = null;
170
        private String standardSelectExpressionFalse = null;
171
        
172
        public OracleSpatialDriver() {
173
                drvAtts = new DriverAttributes();
174
                drvAtts.setLoadedInMemory(false);
175
                
176
        }
177

    
178
        public void setData(Object[] params) {
179
                createOracleEpsgTable();
180
                setData((Connection) params[0], (DBLayerDefinition) params[1]);
181
        }
182
        
183
        private void adjustLyrDef() throws SQLException {
184
                
185
                DBLayerDefinition ldef = getLyrDef();
186
                int cnt = metaData.getColumnCount();
187
                
188
                FieldDescription[] _new = new FieldDescription[cnt];
189
                for (int i=0; i<cnt; i++ ) {
190
                        _new[i] = new FieldDescription();
191
                        _new[i].setFieldName(metaData.getColumnName(i + 1));
192
                        _new[i].setDefaultValue(ValueFactory.createNullValue());
193
                        _new[i].setFieldAlias(_new[i].getFieldName());
194
                        _new[i].setFieldLength(getFieldWidth(i));
195
                        
196
                        int _type = metaData.getColumnType(i + 1);
197
                        _new[i].setFieldType(_type);
198
                        
199
                        if ((_type == Types.FLOAT)
200
                                        || (_type == Types.DOUBLE)
201
                                        || (_type == Types.DECIMAL)
202
                                        || (_type == Types.REAL)) {
203
                                _new[i].setFieldDecimalCount(6);
204
                        } else {
205
                                _new[i].setFieldDecimalCount(0);
206
                        }
207
                }
208
                ldef.setFieldsDesc(_new);
209
                setLyrDef(ldef);
210
        }
211
        
212
        public void setData(Connection _conn, DBLayerDefinition lyrDef) {
213
                
214
                createOracleEpsgTable();
215

    
216
                conn = _conn;
217

    
218
                geotools_conv = new GeometryConverter((OracleConnection) conn);
219
                lyrDef.setConnection(conn);
220
                
221
                setLyrDef(lyrDef);
222
                
223

    
224
                geoColName = lyrDef.getFieldGeometry();
225
                not_restricted_sql =
226
                        "select " + getStandardSelectExpression() + " from " + getTableName() + " c ";
227

    
228
                // various metadata settings
229
                // getMetaDataInThisThread();
230
                cleanWhereClause();
231
                loadSdoMetadata();
232
                oneRowMetadata();
233
                
234
                cancelIDLoad = false;
235
                idLoader = new IdLoaderThread(this);
236
                idLoader.start();
237
        }
238
        
239
        /**
240
         * Utility method to load IDs in a different thred, so that gvsig's gui
241
         * does not get blocked.
242
         *
243
         */
244
        public void getMetaDataInThisThread() {
245
                // PluginServices.getMDIManager().setWaitCursor();
246
                // String statustxt = PluginServices.getMainFrame().getStatusBar().getStatusText();
247
                setWAStruct();
248
                getMetadata();
249
                // PluginServices.getMainFrame().getStatusBar().setInfoText(statustxt);
250
                // PluginServices.getMDIManager().restoreCursor();
251
        }
252

    
253

    
254
        private void getMetadata() {
255

    
256
                setIdRowTable();
257
                
258
                if (cancelIDLoad) {
259
                        return;
260
                }
261

    
262
                originalOracleWorkingArea = getLyrDef().getWorkingArea();
263
                setWAStruct();
264
        }
265

    
266
        private boolean needsCollectionLayer() {
267
                try {
268
                        // SELECT DISTINCT(C.GEOM.SDO_GTYPE) FROM COMUICV C
269
                        // String qry = "select distinct(c."  + geoColName + ".SDO_GTYPE) from " + getTableName() + " c";
270
                        String qry = "select c."  + geoColName + ".SDO_ELEM_INFO from " + getTableName() + " c";
271
                        // SDO_ELEM_INFO
272
                        Statement _st = conn.createStatement();
273
                        ResultSet _rs = _st.executeQuery(qry);
274
                        
275
                        ArrayList types = new ArrayList();
276
                        int aux = 0;
277
                        
278
                        ARRAY info_aux;
279
                        int[] info_aux_int;
280
                        int size;
281

    
282
                        while (_rs.next()) {
283
                                // aux = _rs.getInt(1);
284
                                info_aux = (ARRAY) _rs.getObject(1);
285
                                info_aux_int = info_aux.getIntArray();
286
                                size = info_aux_int.length / 3;
287
                                for (int i=0; i<size; i++) {
288
                                        aux = info_aux_int[3 * i + 1];
289
                                }
290
                                types.add(new Integer(aux % 1000));
291
                                if ((aux % 1000) != 3) {
292
                                        System.err.println("x");
293
                                }
294
                        }
295
                        _rs.close();
296
                        _st.close();
297
                        boolean resp = hasSeveralGeometryTypes(types, false);
298
                        return resp;
299
                } catch (Exception se) {
300
                        System.err.println("Error while getting SDO metadata: "
301
                                        + se.getMessage());
302
                }
303
                return false;
304
        }
305

    
306
        private boolean hasSeveralGeometryTypes(ArrayList tt, boolean are_dims) {
307
                
308
                if (tt.size() == 0) {
309
                        return false;
310
                }
311
                HashMap m = new HashMap();
312
                for (int i=0; i<tt.size(); i++) {
313
                        Integer integ = (Integer) tt.get(i);
314
                        int val = integ.intValue(); 
315
                        if ((val == 4) && (! are_dims)) {
316
                                return true;
317
                        }
318
                        m.put("" + (val % 4), "a type");
319
                }
320
                Iterator iter = m.keySet().iterator();
321
                iter.next();
322
                return iter.hasNext();
323
        }
324

    
325
        private String getOracleSridFromCurrentRecord(ResultSet _rs)
326
                        throws SQLException {
327

    
328
                Object obj = _rs.getObject("SRID");
329
                if (obj == null) {
330
                        logger.warn("No SRID found for this table.");
331
                        tableHasSrid = false;
332
                        return ASSUMED_ORACLE_SRID;
333
                }
334
                return obj.toString();
335
        }
336

    
337
        private Rectangle2D getFullExtentFromCurrentRecord(ResultSet _rs)
338
                        throws SQLException {
339

    
340
                ARRAY dim_info_array = (ARRAY) _rs.getObject("DIMINFO");
341

    
342
                if (dim_info_array == null) {
343

    
344
                        // no full extent found:
345
                        return null;
346
                } else {
347
                        Datum[] da = dim_info_array.getOracleArray();
348

    
349
                        /*
350
                        if (da.length != 2) {
351
                                throw new SQLException(
352
                                                "Expected a 2-dimensional array, found: " + da.length);
353
                        }
354
                        */
355

    
356
                        STRUCT sx = (STRUCT) da[0];
357
                        STRUCT sy = (STRUCT) da[1];
358

    
359
                        try {
360
                                double minx = Double.parseDouble(sx.getAttributes()[1]
361
                                                .toString());
362
                                double maxx = Double.parseDouble(sx.getAttributes()[2]
363
                                                .toString());
364
                                double miny = Double.parseDouble(sy.getAttributes()[1]
365
                                                .toString());
366
                                double maxy = Double.parseDouble(sy.getAttributes()[2]
367
                                                .toString());
368
                                if (minx > maxx) {
369
                                        double aux = minx;
370
                                        minx = maxx;
371
                                        maxx = aux;
372
                                }
373
                                if (miny > maxy) {
374
                                        double aux = miny;
375
                                        miny = maxy;
376
                                        maxy = aux;
377
                                }
378
                                return getRectangle(minx, maxx, miny, maxy);
379
                                // fullExtentJTS = shapeToGeometry(fullExtent);
380
                        } catch (Exception ex) {
381
                                System.err
382
                                                .println("Error while getting full extent from metadata table.");
383
                                return null;
384
                                // fullExtentJTS = null;
385
                        }
386
                }
387
        }
388

    
389
        private void loadSdoMetadata() {
390

    
391
                try {
392
                        Statement _st = conn.createStatement();
393
                        String qry = "select * from " + ORACLE_GEOMETADATA_VIEW
394
                                        + " where TABLE_NAME = " + "'" + getTableName() + "'";
395
                        ResultSet _rs = _st.executeQuery(qry);
396

    
397
                        if (_rs.next()) {
398
                                oracleSRID = getOracleSridFromCurrentRecord(_rs);
399
                                
400
                                isGeogCS = getIsGCS(oracleSRID, tableHasSrid, conn);
401
                                
402
                                epsgSRID = oracleSridToEpsgSrid(oracleSRID);
403
                                geoColName = _rs.getString("COLUMN_NAME");
404
                                
405
                                fullExtent = getFullExtentFromCurrentRecord(_rs);
406

    
407
                                _rs.close();
408
                                _st.close();
409
                                
410
                        } else {
411
                                throw new SQLException("Empty resultset from this query: "
412
                                                + qry);
413
                        }
414
                } catch (SQLException se) {
415
                        System.err.println("Error while getting SDO metadata: "
416
                                        + se.getMessage());
417
                }
418

    
419
        }
420

    
421
        /**
422
         * Utilitu method to find out if a coordinate system is geodetic or not.
423
         * 
424
         * @param oracleSRID2 the coordinate system's oracle code
425
         * @param thas whether the table has a coordinate system set.
426
         * if not, the method returns false.
427
         * @param _conn conenction object
428
         * @return whether the coordinate system is geodetic or not.
429
         */
430
        public static boolean getIsGCS(String oracleSRID2, boolean thas, Connection _conn) {
431
                
432
                if (! thas) {
433
                        return false;
434
                }
435
                
436
                int ora_cs = -10;
437
                try {
438
                        ora_cs = Integer.parseInt(oracleSRID2);
439
                } catch (Exception ex) {
440
                        return false;
441
                }
442
                
443
                if (((ora_cs > 8000) && (ora_cs < 8999)) || (ora_cs == 524288)) {
444
                        return true;
445
                }
446
                
447
                String _sql = "SELECT WKTEXT FROM CS_SRS WHERE SRID = " + ora_cs;
448
                try {
449
                        java.sql.PreparedStatement _ps = _conn.prepareStatement(_sql,
450
                                        ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
451
                        _ps.execute();
452
                        ResultSet _rs = _ps.getResultSet();
453
                        _rs.next();
454
                        
455
                        String wkt = (String) _rs.getObject(1);
456
                        
457
                        wkt = wkt.substring(0, 6);
458
                        
459
                        _rs.close();
460
                        _ps.close();
461
                        return (wkt.compareToIgnoreCase("geogcs") == 0);
462
                        
463
                } catch (Exception se) {
464
                        logger.error("While getting SRID WKT: " + se.getMessage());
465
                }
466
                return false;
467
        }
468

    
469
        private Rectangle2D getFullExtentFromSample() {
470
                // numReg has a value
471
                
472
                if (numReg == 0) {
473
                        return null;
474
                } else {
475
                        return getBoundingFromSample(numReg);
476
                }
477
        }
478

    
479
        private Rectangle2D getRectangle(double minx, double maxx, double miny,
480
                        double maxy) {
481

    
482
                Rectangle2D resp = new Rectangle2D.Double(minx, miny, maxx - minx, maxy
483
                                - miny);
484
                return resp;
485
        }
486

    
487
        private void oneRowMetadata() {
488
                
489
                try {
490
                        String _sql = "select " + getStandardSelectExpression()
491
                        + ", c." + geoColName
492
                        + " from " + getTableName() + " c ";
493

    
494
                        st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
495
                                        ResultSet.CONCUR_READ_ONLY);
496
                        ResultSet _rs = st.executeQuery(_sql + " where (rownum = 1)");
497
                        if (_rs.next()) {
498
                                STRUCT sample_geo = (STRUCT) _rs.getObject(geoColName);
499
                                shapeType = getShapeTypeOfStruct(sample_geo);
500
                        } else {
501
                                shapeType = FShape.MULTI;
502
                        }
503
                        
504
                        // -----------------------
505
                        
506
                        _rs = st.executeQuery(not_restricted_sql + " where (rownum = 1)");
507
                        metaData = _rs.getMetaData();
508
                        // geoColInd = _rs.findColumn(geoColName);
509
                        oneBasedGeoColInd = metaData.getColumnCount() + 1;
510

    
511
                        DatabaseMetaData dbmd = conn.getMetaData();
512
                        pkOneBasedIndexes = getPKIndexes(dbmd, _rs);
513

    
514
                        int cnt = metaData.getColumnCount();
515
                        fieldNames = new String[cnt];
516
                        for (int i = 0; i < cnt; i++) {
517
                                fieldNames[i] = metaData.getColumnName(i + 1);
518
                        }
519
                        getIdFieldNames();
520
                        
521
                        adjustLyrDef();
522

    
523
                        _rs.close(); // st no debe cerrarse ya que las llamadas a metadata lo encesitan 
524
                        
525
                } catch (SQLException se) {
526
                        logger.error("While getting metadata. " + se.getMessage());
527
                }
528
        }
529

    
530
        private int getShapeTypeOfStruct(STRUCT sample) throws SQLException {
531

    
532
                int code = ((NUMBER) sample.getOracleAttributes()[0]).intValue() % 10;
533
                switch (code) {
534
                case 1:
535
                        return FShape.POINT;
536
                case 2:
537
                        return FShape.LINE;
538
                case 3:
539
                        return FShape.POLYGON;
540
                case 5:
541
                        return FShape.MULTIPOINT;
542
                case 6:
543
                        return FShape.LINE;
544
                case 7:
545
                        return FShape.POLYGON;
546
                }
547

    
548
                System.err.println("Unknown type");
549
                return FShape.NULL;
550
        }
551

    
552
        private String getIdFieldNames() {
553

    
554
                try {
555
                        idFieldNames = "";
556
                        for (int i = 0; i < pkOneBasedIndexes.length; i++) {
557
                                idFieldNames = idFieldNames
558
                                                + metaData.getColumnName(pkOneBasedIndexes[i]) + ", ";
559
                        }
560
                } catch (SQLException se) {
561

    
562
                }
563
                idFieldNames = idFieldNames.substring(0, idFieldNames.length() - 2);
564
                return idFieldNames;
565
        }
566

    
567
        private int[] getPKIndexes(DatabaseMetaData metaData, ResultSet table_rs) {
568

    
569
                int[] _res = new int[1];
570
                _res[0] = 1;
571
                return _res;
572
        }
573

    
574
        public String getSqlTotal() {
575
                // TODO Auto-generated method stub
576
                return "";
577
        }
578

    
579
        public String getCompleteWhere() {
580
                // TODO Auto-generated method stub
581
                return "";
582
        }
583

    
584
        public IFeatureIterator getFeatureIterator(String sql)
585
                        throws DriverException {
586
                
587
                if (isNotAvailableYet) {
588
                        return null;
589
                        // return emptyIt;
590
                }
591

    
592
                singleCachedFeatureRowNum = -1;
593
                Object[] rs_st = getViewResultSet(null, sql, tableHasSrid);
594
                
595
                ResultSet localrs = (ResultSet) rs_st[0];
596
                Statement _st = (Statement) rs_st[1];
597
                
598
                return new OracleSpatialFeatureIterator(
599
                                this, localrs, _st, oneBasedGeoColInd, use_geotools);
600
        }
601

    
602
        public String getConnectionStringBeginning() {
603
                // oracle
604
                return CONN_STR_BEGIN;
605
        }
606

    
607
        static {
608
                try {
609
                        Class.forName("oracle.jdbc.driver.OracleDriver");
610
                } catch (ClassNotFoundException e) {
611
                        throw new RuntimeException(e);
612
                }
613
        }
614

    
615
        public void open() throws DriverException {
616
        }
617

    
618
        public int getDefaultPort() {
619
                // oracle port
620
                return 1521;
621
        }
622

    
623
        public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG)
624
                        throws DriverException {
625
                
626
                if (isNotAvailableYet) {
627
                        return null;
628
                }
629

    
630
                singleCachedFeatureRowNum = -1;
631
                Shape wa_and_view = intersectWorkingAreaAndView(r);
632
                if (wa_and_view == null) {
633
                        return null; //;
634
                }
635
                STRUCT local_st = shapeToStruct(wa_and_view, FShape.NULL,
636
                                tableHasSrid, false, true);
637

    
638
                Object[] rs_st = getViewResultSet(local_st, null, tableHasSrid);
639
                
640
                ResultSet localrs = (ResultSet) rs_st[0];
641
                Statement _st = (Statement) rs_st[1];
642

    
643
                return new OracleSpatialFeatureIterator(
644
                                this, localrs, _st, oneBasedGeoColInd, use_geotools);
645
        }
646

    
647
        private Shape intersectWorkingAreaAndView(Rectangle2D r) {
648

    
649
                if (originalOracleWorkingArea == null) {
650
                        return r;
651
                }
652

    
653
                Rectangle2D res = null; // new Rectangle2D.Double();
654

    
655
                if (originalOracleWorkingArea instanceof Rectangle2D) {
656
                        res = doIntersect(r, (Rectangle2D) originalOracleWorkingArea);
657
                        // Rectangle2D.intersect(r, (Rectangle2D) originalOracleWorkingArea, res);
658
                } else {
659
                        // TODO
660
                        Rectangle2D aux = originalOracleWorkingArea.getBounds2D();
661
                        // res = r.createIntersection(aux);
662
                        res = doIntersect(r, aux);
663
                        // Rectangle2D.intersect(r, aux, res);
664
                }
665
                return res;
666
        }
667

    
668
        public IFeatureIterator getFeatureIterator(Rectangle2D r, String strEPSG,
669
                        String[] alphaNumericFieldsNeeded) throws DriverException {
670
                
671
                if (isNotAvailableYet) {
672
                        return null;
673
                        // return emptyIt;
674
                }
675

    
676
                singleCachedFeatureRowNum = -1;
677
                return getFeatureIterator(r, strEPSG);
678
        }
679

    
680
        public String getGeometryField(String fieldName) {
681
                return fieldName;
682
                // return "ASBINARY(" + fieldName + ")";
683
        }
684

    
685
        public DriverAttributes getDriverAttributes() {
686
                return drvAtts;
687
        }
688

    
689
        public IGeometry getShape(int _ind) throws IOException {
690
                
691
                if (isNotAvailableYet) {
692
                        return nullGeom;
693
                }
694

    
695
                ROWID r_id = (ROWID) rowToId.get(new Integer(_ind));
696

    
697
                String _sql = "select " + geoColName + " from " + getTableName()
698
                                + " where rowid = ?";
699

    
700
                try {
701

    
702
                        java.sql.PreparedStatement ps = conn.prepareStatement(_sql);
703
                        ps.setObject(1, r_id);
704
                        // Statement stmnt = conn.createStatement();
705
                        ps.execute();
706

    
707
                        ResultSet _res = ps.getResultSet();
708

    
709
                        if (_res.next()) {
710
                                
711
                                STRUCT _st = (oracle.sql.STRUCT) _res.getObject(1); // geocolind);
712
                                IGeometry theGeom = getGeometryUsing(_st, use_geotools);
713
                                _res.close();
714
                                ps.close();
715
                                return theGeom;
716

    
717
                        } else {
718

    
719
                                logger.error("Unable to get shape: " + _ind + " (probably due to edition)");
720
                                return nullGeom;
721
                                
722

    
723
                        }
724
                } catch (SQLException se) {
725
                        throw new IOException("SQLException: " + se.getMessage());
726
                }
727
        }
728

    
729
        public boolean isWritable() {
730
                return true;
731
        }
732

    
733
        public String getName() {
734
                return NAME;
735
        }
736

    
737
        public int[] getPrimaryKeys()
738
                        throws com.hardcode.gdbms.engine.data.driver.DriverException {
739

    
740
                return pkOneBasedIndexes;
741
        }
742

    
743
        public void write(DataWare dataWare)
744
                        throws com.hardcode.gdbms.engine.data.driver.DriverException {
745
        }
746

    
747
        private void setIdRowTable() {
748
                hashRelate = new Hashtable();
749
                java.sql.PreparedStatement ps = null;
750
                
751
                try {
752
                        String _sql = getIdAndElemInfoFullResulltSetQuery();
753
                        
754
                        logger.debug("SQL para leer ids: " + _sql);
755
                        
756
                        
757
                        ps = conn.prepareStatement(_sql,
758
                                                ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
759
                        ps.setFetchDirection(ResultSet.FETCH_FORWARD);
760
                        ps.setFetchSize(FETCH_SIZE);
761

    
762
                        // ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
763
                        // _st.setFetchDirection(ResultSet.FETCH_FORWARD);
764
                        // _st.setFetchSize(200);
765

    
766
                        if (originalOracleWAStruct != null) {
767
                                ps.setObject(1, originalOracleWAStruct);
768
                        }
769

    
770
                        ps.execute();
771
                        ResultSet _r = ps.getResultSet();
772
                        ROWID ri = null;
773

    
774
                        int row = 0;
775
                        String gid;
776
                        Value aux = null;
777
                        
778
                        // ----------------------------------- types init
779
                        ArrayList types = new ArrayList();
780
                        int types_aux = 0;
781
                        
782
                        ARRAY info_aux;
783
                        int[] info_aux_int;
784
                        int size;
785
                        // ----------------------------------- types init
786
                        
787
                        logger.debug("Beginning of result set:");
788

    
789
                        while (_r.next()) {
790
                                // ---------------------------------------
791
                                ri = (ROWID) _r.getObject(1);
792
                                gid = ri.stringValue();
793
                                aux = ValueFactory.createValue(gid);
794
                                Integer intobj = new Integer(row);
795
                                hashRelate.put(aux, intobj);
796
                                rowToId.put(intobj, ri);
797
                                
798
                                if ((row % 5000) == 0) {
799
                                        
800
                                        // ------------------------------------------- cancel load
801
                                        if (cancelIDLoad) {
802
                                                hashRelate.clear();
803
                                                rowToId.clear();
804
                                                return;
805
                                        }
806
                                        // -------------------------------------------
807

    
808
                                        String fmt = OracleSpatialUtils.getFormattedInteger(row); 
809
                                        logger.info("IDs read: " + fmt);
810
                                }
811
                                row++;
812
                                // --------------------------------------- types
813
                                
814
                                info_aux = (ARRAY) _r.getObject(2);
815
                                if (info_aux == null) {
816
                                        // logger.debug("NULL info array found in record: " + row);
817
                                } else {
818
                                        info_aux_int = info_aux.getIntArray();
819
                                        size = info_aux_int.length / 3;
820
                                        for (int i=0; i<size; i++) {
821
                                                types_aux = info_aux_int[3 * i + 1];
822
                                                types.add(new Integer(types_aux % 1000));
823
                                        }
824
                                }
825
                                // --------------------------------------- types end
826
                        }
827
                        _r.close();
828
                        ps.close();
829
                        numReg = row;
830
                        
831
                        needsCollectionLayer = hasSeveralGeometryTypes(types, false);
832
                        if (needsCollectionLayer) {
833
                                shapeType = FShape.MULTI;
834
                        }
835

    
836
                } catch (SQLException e) {
837
                        System.err.println("While setting id-row hashmap: " + e.getMessage());
838
                }
839
        }
840
        
841

    
842
        public int getFieldCount()
843
                        throws com.hardcode.gdbms.engine.data.driver.DriverException {
844
                try {
845
                        return metaData.getColumnCount();
846
                } catch (SQLException e) {
847
                        System.err.println("While getting field count: " + e.getMessage());
848
                        throw new com.hardcode.gdbms.engine.data.driver.DriverException(e
849
                                        .getMessage());
850
                }
851
        }
852

    
853
        public String[] getFieldNames() {
854
                return fieldNames;
855
        }
856

    
857
        public String getTotalFields() {
858
                String strAux = "";
859
                for (int i = 0; i < fieldNames.length; i++) {
860
                        if (i == 0) {
861
                                strAux = fieldNames[i];
862
                        } else {
863
                                strAux = strAux + ", " + fieldNames[i];
864
                        }
865
                }
866
                return strAux;
867
        }
868

    
869
        public int getFieldType(int idField)
870
                        throws com.hardcode.gdbms.engine.data.driver.DriverException {
871

    
872
                int i = 0;
873
                
874
                try {
875
                        i = idField + 1; // idField viene basado en 0
876
                        
877
//                        if (i == 0) {
878
//                                return Types.VARCHAR;
879
//                        }
880
                        
881
                        int __type = metaData.getColumnType(i);
882

    
883
                        // we must add this entry because we did not remove the 'geometry' column
884
                        if (__type == Types.STRUCT)
885
                                return Types.VARCHAR; // .STRUCT;
886
                        // ----------------------------------------------------------------------
887

    
888
                        if (__type == Types.VARCHAR)
889
                                return Types.VARCHAR;
890
                        if (__type == Types.FLOAT)
891
                                return Types.FLOAT;
892
                        if (__type == Types.DOUBLE)
893
                                return Types.DOUBLE;
894
                        if (__type == Types.INTEGER)
895
                                return Types.INTEGER;
896
                        if (__type == Types.SMALLINT)
897
                                return Types.SMALLINT;
898
                        if (__type == Types.TINYINT)
899
                                return Types.TINYINT;
900
                        if (__type == Types.BIGINT)
901
                                return Types.BIGINT;
902
                        if (__type == Types.BIT)
903
                                return Types.BIT;
904
                        if (__type == Types.DATE)
905
                                return Types.DATE;
906
                        if (__type == Types.DECIMAL)
907
                                return Types.DOUBLE;
908
                        if (__type == Types.NUMERIC)
909
                                return Types.DOUBLE;
910
                        if (__type == Types.DATE)
911
                                return Types.DATE;
912
                        if (__type == Types.TIME)
913
                                return Types.TIME;
914
                        if (__type == Types.TIMESTAMP)
915
                                return Types.TIMESTAMP;
916

    
917
                } catch (SQLException e) {
918
                        System.err.println("i = " + i);
919
                        throw new com.hardcode.gdbms.engine.data.driver.DriverException(e);
920
                }
921
                return -1;
922
        }
923

    
924
        public Value[] getAttributes(ResultSet rs) {
925

    
926
                Value[] res = null;
927

    
928
                try {
929
                        int fcount = rs.getMetaData().getColumnCount();
930
                        res = new Value[fcount];
931
                        for (int i = 0; i < fcount; i++) {
932

    
933
                                Object obj = rs.getObject(i + 1);
934
                                String objToString = null;
935
                                int _type = -1;
936

    
937
                                if (obj instanceof String) {
938
                                        objToString = (String) obj;
939
                                        _type = Types.VARCHAR;
940
                                } else {
941
                                        if (obj instanceof ROWID) {
942
                                                objToString = ((ROWID) obj).stringValue();
943
                                                _type = Types.VARCHAR;
944
                                        } else {
945
                                                if (obj instanceof STRUCT) {
946
                                                        objToString = "STRUCT";
947
                                                        _type = Types.VARCHAR;
948
                                                } else {
949
                                                        objToString = (obj == null) ? "NULL" : obj
950
                                                                        .toString();
951
                                                        _type = getFieldType(i);
952
                                                }
953
                                        }
954
                                }
955

    
956
                                // /*
957
                                if (_type == -1) {
958
                                        obj = null;
959
                                }
960
                                // */
961
                                if (obj == null) {
962
                                        res[i] = ValueFactory.createNullValue();
963
                                } else {
964
                                        if (_type == Types.DATE) {
965
                                                objToString = objToString.replace('-', '/');
966
                                        }
967
                                        res[i] = ValueFactory.createValueByType(objToString, _type);
968
                                }
969
                        }
970
                } catch (SQLException se) {
971
                        System.err.println("Error while getting attributes: "
972
                                        + se.getMessage());
973
                        return null;
974
                } catch (com.hardcode.gdbms.engine.data.driver.DriverException e) {
975
                        System.err.println("Error while getting attributes: "
976
                                        + e.getMessage());
977
                        return null;
978
                } catch (ParseException e) {
979
                        System.err.println("Error while getting attributes: "
980
                                        + e.getMessage());
981
                        return null;
982
                }
983
                return res;
984
        }
985

    
986
        public String getFieldName(int fieldId)
987
                        throws com.hardcode.gdbms.engine.data.driver.DriverException {
988
                return fieldNames[fieldId];
989
        }
990

    
991
        public int getFieldWidth(int fieldId) {
992
                int i = -1;
993
                try {
994
                        int aux = fieldId + 1; // fieldId viene basado en 0
995
                        i = metaData.getColumnDisplaySize(aux);
996
                } catch (SQLException e) {
997
                        System.err.println("While getting field width: " + e.getMessage());
998
                }
999
                // SUN define que getColumnDisplaySize devuelve numeros negativos cuando el campo es de tipo Text o Vartext
1000
                // sin ancho. Nosotros vamos a devolver 255 para que fucione, por lo menos al exportar a DBF.
1001
                // Nota: Si se truncan cadenas, este es el sitio que lo provoca.
1002
                if (i < 0)
1003
                        i = 255;
1004
                return i;
1005
        }
1006

    
1007
        public Value getFieldValue(long rowIndex, int field_Id)
1008
                        throws com.hardcode.gdbms.engine.data.driver.DriverException {
1009

    
1010
                if (isNotAvailableYet) {
1011
                        return nullVal;
1012
                }
1013
                
1014
                
1015
                // if it is cached, return the value 
1016
                if ((singleCachedFeature != null)
1017
                                && (rowIndex == singleCachedFeatureRowNum)) {
1018
                        return singleCachedFeature.getAttributes()[field_Id];
1019
                }
1020

    
1021
                // return ValueFactory.createNullValue();
1022
                ResultSet _r = null;
1023
                java.sql.PreparedStatement ps = null;
1024

    
1025
                try {
1026
                        String rnq = getSearchId();
1027
                        ROWID _id = (ROWID) rowToId.get(new Integer((int) rowIndex));
1028

    
1029
                        // String rnq = getSearchRowNumQuery((int) rowIndex);
1030
                        ps = conn.prepareStatement(rnq);
1031

    
1032
                        // if (originalOracleWAStruct != null) {
1033
                        ps.setObject(1, _id);
1034
                        // }
1035

    
1036
                        ps.execute();
1037
                        _r = ps.getResultSet();
1038
                        _r.next();
1039

    
1040
                } catch (SQLException se) {
1041
                        throw new com.hardcode.gdbms.engine.data.driver.DriverException(se
1042
                                        .getMessage());
1043
                }
1044

    
1045
                IFeature ife = null;
1046
                Value[] atts = null;
1047

    
1048
                try {
1049
                        ROWID ri = (ROWID) _r.getObject(1);
1050
                        atts = getAttributes(_r);
1051
                        String gid = ri.stringValue();
1052
                        STRUCT _st = (oracle.sql.STRUCT) _r.getObject(oneBasedGeoColInd);
1053
                        IGeometry theGeom = getGeometryUsing(_st, use_geotools);
1054
                        ife = new DefaultFeature(theGeom, atts, gid);
1055
                        _r.close();
1056
                        ps.close();
1057
                } catch (SQLException se) {
1058
                        logger.error("Error while doing next(): " + se.getMessage(), se);
1059
                }
1060

    
1061
                // -------------------------------
1062
                singleCachedFeature = ife;
1063
                singleCachedFeatureRowNum = rowIndex;
1064
                // -------------------------------
1065
                if (atts == null) {
1066
                        return ValueFactory.createNullValue();
1067
                } else {
1068
                        return atts[field_Id];
1069
                }
1070

    
1071
        }
1072

    
1073
        public static void showMemory() {
1074
                Runtime r = Runtime.getRuntime();
1075
                long mem = r.totalMemory() - r.freeMemory();
1076
                System.err.println("Memoria total: " + mem);
1077
        }
1078

    
1079
        public Rectangle2D getFullExtent() {
1080
                // SELECT SDO_AGGR_MBR(GEOMETRY1) FROM HOJAS_25000 WHERE
1081
                return fullExtent;
1082
        }
1083

    
1084
        public IGeometry getGeometryUsing(STRUCT theStruct, boolean use_gtools)
1085
                        throws SQLException {
1086
                IGeometry _igeom = null;
1087
                
1088
                if (theStruct == null) {
1089
                        return nullGeom;
1090
                }
1091

    
1092
                if (use_gtools) { // geotools
1093

    
1094
                        _igeom = getGeotoolsIGeometry(theStruct);
1095

    
1096
                } else { // jgeometry
1097

    
1098
                        // System.err.println(System.currentTimeMillis());
1099
                        // JGeometry j_geom = JGeometry.load(theStruct);
1100
                        // _igeom = getFMapGeometry(j_geom, false);
1101
                        _igeom = getFMapGeometry(theStruct, false);
1102
                        // System.err.println(System.currentTimeMillis());
1103
                }
1104

    
1105
                return _igeom;
1106
        }
1107
        
1108
        private IGeometry getFMapGeometry(JGeometry jg, boolean force_not_collection) {
1109
                
1110
                int jgtype = jg.getType();
1111
                int dim = jg.getDimensions();
1112
                IGeometry ig = null; 
1113
                
1114
                if ((jgtype != JGeometry.GTYPE_COLLECTION) && (isActuallyACollection(jg))) {
1115
                        jgtype = JGeometry.GTYPE_COLLECTION;
1116
                }
1117
                
1118
                switch (jgtype) {
1119
                
1120
                case JGeometry.GTYPE_COLLECTION:
1121
                        int srid = jg.getSRID();
1122
                        ig = getFMapGeometryCollection(jg, dim, srid);
1123
                        break;
1124

    
1125
                case JGeometry.GTYPE_POINT:
1126
                case JGeometry.GTYPE_MULTIPOINT:
1127
                        ig = getFMapGeometryPoint(jg, dim);
1128
                        break;
1129

    
1130
                case JGeometry.GTYPE_CURVE:
1131
                case JGeometry.GTYPE_MULTICURVE:
1132
                        ig = getFMapGeometryMultiLineString(jg, dim);
1133
                        break;
1134

    
1135
                case JGeometry.GTYPE_POLYGON:
1136
                case JGeometry.GTYPE_MULTIPOLYGON:
1137
                        ig = getFMapGeometryMultipolygon(jg, dim);
1138
                        break;
1139
                }
1140
                
1141
                return ig;
1142
        }
1143
        private IGeometry getFMapGeometryCollection(Datum[] the_data, int dim, int __srid) {
1144
                
1145
//                Connection conn = null;
1146
//                
1147
//                try {
1148
//                        conn = st.getOracleConnection();
1149
//                } catch (SQLException se) {
1150
//                        logger.error("Unexpected error: " + se.getMessage());
1151
//                }
1152

    
1153
                NUMBER main_type = new NUMBER(dim * 1000 + OracleSpatialUtils.getStructType(the_data));
1154
                NUMBER _srid = new NUMBER(__srid);
1155
                
1156
                Datum[] all_info_array = null;
1157
                Object[] elems_info_aray = null;
1158
                Datum[] all_ords = null;
1159
                
1160
                        try {
1161
                                all_info_array = ((ARRAY) the_data[3]).getOracleArray();
1162
                                // iadesc = ((ARRAY) st.getOracleAttributes()[3]).getDescriptor();
1163
                                
1164
                                elems_info_aray = groupByElement(all_info_array);
1165
                                
1166
                                all_ords = ((ARRAY) the_data[4]).getOracleArray();
1167
                                // oadesc = ((ARRAY) st.getOracleAttributes()[4]).getDescriptor();
1168
                                
1169
                        } catch (SQLException e) {
1170
                                logger.error("Unexpected error: " + e.getMessage());
1171
                        }
1172

    
1173
                Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1174
                Object[] _elems_info_aray = new Object[elems_info_aray.length];
1175
                for (int i=0; i<elems_info_aray.length; i++) {
1176
                        _elems_info_aray[i] = updateIndexes((Datum[]) elems_info_aray[i]);
1177
                }
1178
                
1179
                // _elems_info_aray, ords_of_groups
1180
                int no_of_elems = ords_of_groups.length;
1181
                IGeometry[] geoms = new IGeometry[no_of_elems];
1182
                for (int i=0; i<no_of_elems; i++) {
1183
                        
1184
                        Datum[] item_info_array = null;
1185
                        Datum[] item_ords = null;
1186
                        NUMBER gtype = null;
1187
                        
1188
                        try {
1189
                                item_info_array = (Datum[]) _elems_info_aray[i];
1190
                                item_ords = (Datum[]) ords_of_groups[i];
1191
                                
1192
                                gtype = new NUMBER(dim * 1000 + item_info_array[1].intValue() % 1000);
1193
                        } catch (SQLException se) {
1194
                                logger.error("Unexpected error: " + se.getMessage());
1195
                        }
1196
                        
1197
                        // if it's the first geometry, the type is the collection's main type (no?)
1198
                        if (i==0) {
1199
                                gtype = main_type;
1200
                        }
1201

    
1202
                        STRUCT itemst = null;
1203
                        if (tableHasSrid) {
1204
                                itemst = OracleSpatialUtils.createStruct(
1205
                                                gtype, _srid, item_info_array, item_ords, conn);
1206
                        } else {
1207
                                itemst = OracleSpatialUtils.createStruct(
1208
                                                gtype, null, item_info_array, item_ords, conn);
1209
                        }
1210
                        geoms[i] = getFMapGeometry(itemst, true);
1211
                }
1212
                return new FGeometryCollection(geoms);
1213
        }
1214
        
1215
        public IGeometry getFMapGeometry(STRUCT st, boolean force_not_collection) {
1216
                // FJP: Esto es para evitar hacer esta llamada varias veces,
1217
                // que consume bastante tiempo.
1218
                Datum[] the_data = null;
1219
                try
1220
                {
1221
                        the_data = st.getOracleAttributes();
1222
                        // Evitamos getOracleAttributes
1223
                        // int jgtype = OracleSpatialUtils.getStructType(st);
1224
                        int jgtype = ((NUMBER) the_data[0]).intValue() % 1000;
1225
                        
1226
                        jgtype = OracleSpatialUtils.oracleGTypeToFShapeType(jgtype);
1227
                        
1228
                        // int dim = OracleSpatialUtils.getStructDimensions(st);
1229
                        int dim = ((NUMBER) the_data[0]).intValue() / 1000;
1230
                        if (dim < 2) dim = 2; 
1231
                        
1232
                        IGeometry ig = null; 
1233
                        
1234
                        if (isActuallyACollection(the_data)) {
1235
                                jgtype = FShape.MULTI;
1236
                        }
1237

    
1238
                        switch (jgtype) {
1239
                        
1240
                        case FShape.MULTI:
1241
                                // idem
1242
                                // int srid = OracleSpatialUtils.getStructSRID(st);
1243
                                int srid = ((NUMBER) the_data[1]).intValue();
1244
                                ig = getFMapGeometryCollection(the_data, dim, srid);
1245
                                break;
1246

    
1247
                        case FShape.POINT:
1248
                                ig = getFMapGeometryPoint(the_data, dim);
1249
                                break;
1250

    
1251
                        case FShape.LINE:
1252
                                ig = getFMapGeometryMultiLineString(the_data, dim);
1253
                                break;
1254

    
1255
                        case FShape.POLYGON:
1256
                                ig = getFMapGeometryMultipolygon(the_data, dim);
1257
                                break;
1258
                        }
1259
                        return ig;                        
1260
                }
1261
                catch (SQLException e)
1262
                {
1263
                        logger.error(e);                        
1264
                }
1265
                return null;
1266
        }
1267
        
1268
        
1269
        private double[] getIndDoublesModule(double[] input, int ind, int n) {
1270
                int size = input.length / n;
1271
                double[] resp = new double[size];
1272
                for (int i=0; i<size; i++) {
1273
                        resp[i] = input[ (i * n) + ind ];
1274
                }
1275
                return resp;
1276
        }
1277

    
1278
        private double[] getIndBigDecimalModule(double[] input, int ind, int n) {
1279
                int size = input.length / n;
1280
                double[] resp = new double[size];
1281
                for (int i=0; i<size; i++) {
1282
                        resp[i] = input[ (i * n) + ind ];
1283
                }
1284
                return resp;
1285
        }
1286

    
1287
        private IGeometry getFMapGeometryMultipolygon(JGeometry jg, int dim) {
1288
                
1289
                IGeometry ig = null;
1290
                
1291
                if (jg.isCircle()) {
1292
                        
1293
                        ig = getCircleFromJGeometry(jg);
1294
                        
1295
                } else {
1296

    
1297
                        Shape shape = jg.createShape();
1298
                        GeneralPathX gpx = new GeneralPathX(shape);
1299

    
1300
                        if (dim == 2) {
1301
                                ig = ShapeFactory.createPolygon2D(gpx);
1302
                        } else {
1303
                                double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1304
                                ig = ShapeFactory.createPolygon3D(gpx, z);
1305
                        }
1306
                }
1307
                return ig;
1308
        }
1309
        
1310
        private IGeometry getFMapGeometryMultipolygon(Datum[] the_data, int dim) {
1311
                
1312
                IGeometry ig = null;
1313
                
1314
                if (OracleSpatialUtils.isCircle(the_data)) {
1315
                        
1316
                        ig = getCircleFromStruct(the_data);
1317
                        
1318
                } else {
1319

    
1320
                        GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1321

    
1322
                        if (dim == 2) {
1323
                                ig = ShapeFactory.createPolygon2D(gpx);
1324
                        } else {
1325
                                double[] ords = null;
1326
                                try {
1327
                                        ords = ((ARRAY) the_data[4]).getDoubleArray();        
1328
                                } catch (SQLException se) {
1329
                                        logger.error("While getting ordinates: " + se.getMessage(), se);
1330
                                }
1331
                                double[] z = getIndBigDecimalModule(ords, 2, dim);
1332
                                ig = ShapeFactory.createPolygon3D(gpx, z);
1333
                        }
1334
                }
1335
                return ig;
1336
        }
1337

    
1338
        
1339

    
1340
        private IGeometry getCircleFromJGeometry(JGeometry jg) {
1341
                double[] threep = jg.getOrdinatesArray();
1342
                Point2D[] three = new Point2D.Double[3];
1343
                three[0] = new Point2D.Double(threep[0], threep[1]);
1344
                three[1] = new Point2D.Double(threep[2], threep[3]);
1345
                three[2] = new Point2D.Double(threep[4], threep[5]);
1346
                
1347
                Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1348
                
1349
                Point2D cent = (Point2D) cent_rad[0];
1350
                double radius = ((Double) cent_rad[1]).doubleValue();
1351
                
1352
                IGeometry circ = ShapeFactory.createCircle(cent, radius);
1353
                return circ;
1354
        }
1355
        
1356
        private IGeometry getCircleFromStruct(Datum[] the_data) {
1357
                
1358
                double[] threep = null;
1359
                
1360
                try {
1361
                        threep = ((ARRAY) the_data[4]).getDoubleArray();
1362
                } catch (SQLException se) {
1363
                        logger.error("While getting ords from struct: " + se.getMessage(), se);
1364
                        return new FNullGeometry();
1365
                }
1366
                Point2D[] three = new Point2D.Double[3];
1367
                three[0] = new Point2D.Double(threep[0], threep[1]);
1368
                three[1] = new Point2D.Double(threep[2], threep[3]);
1369
                three[2] = new Point2D.Double(threep[4], threep[5]);
1370

    
1371
                Object[] cent_rad = OracleSpatialUtils.getCenterAndRadiousOfCirc(three);
1372
                
1373
                Point2D cent = (Point2D) cent_rad[0];
1374
                double radius = ((Double) cent_rad[1]).doubleValue();
1375
                
1376
                IGeometry circ = ShapeFactory.createCircle(cent, radius);
1377
                return circ;
1378
        }
1379

    
1380
        
1381

    
1382
        private IGeometry getFMapGeometryMultiLineString(JGeometry jg, int dim) {
1383
                Shape shape = jg.createShape();
1384
                GeneralPathX gpx = new GeneralPathX(shape);
1385
                IGeometry ig = null;
1386
                
1387
                if (dim == 2) {
1388
                        ig = ShapeFactory.createPolyline2D(gpx);
1389
                } else {
1390
                        double[] z = getIndDoublesModule(jg.getOrdinatesArray(), 2, dim);
1391
                        ig = ShapeFactory.createPolyline3D(gpx, z);
1392
                }
1393
                return ig;
1394
        }
1395
        
1396
        private IGeometry getFMapGeometryMultiLineString(Datum[] the_data, int dim) {
1397
                GeneralPathX gpx = OracleSpatialUtils.structToGPX(the_data);
1398
                IGeometry ig = null;
1399
                double[] ords = null;
1400
                
1401
                if (dim == 2) {
1402
                        ig = ShapeFactory.createPolyline2D(gpx);
1403
                } else {
1404
                        ords = OracleSpatialUtils.getOrds(the_data);
1405
                        double[] z = getIndBigDecimalModule(ords, 2, dim);
1406
                        ig = ShapeFactory.createPolyline3D(gpx, z);
1407
                }
1408
                return ig;
1409
        }
1410
        
1411
        
1412

    
1413
        private IGeometry getFMapGeometryPoint(JGeometry jg_point, int dim) {
1414
                
1415
                if (jg_point.getOrdinatesArray() == null) { // sdo_point
1416
                        return getFMapGeometrySdoPoint(jg_point, dim);
1417
                }
1418
                
1419
                IGeometry ig = null;
1420
                int total_size = jg_point.getOrdinatesArray().length;
1421
                int no_po = total_size / dim;
1422
                double[] x = new double[no_po];
1423
                double[] y = new double[no_po];
1424
                double[] z = new double[no_po];
1425
                for (int i = 0; i < no_po; i++) {
1426
                        x[i] = jg_point.getOrdinatesArray()[i * dim]; // pp[i].getX();
1427
                        y[i] = jg_point.getOrdinatesArray()[i * dim + 1];
1428
                        if (dim >= 3) {
1429
                                z[i] = jg_point.getOrdinatesArray()[i * dim + 2];
1430
                        }
1431
                }
1432
                
1433
                if (dim == 2) {
1434
                        if (no_po == 1) {
1435
                                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1436
                        } else {
1437
                                ig = ShapeFactory.createMultipoint2D(x, y);
1438
                        }
1439
                        
1440
                } else {
1441
                        if (no_po == 1) {
1442
                                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1443
                        } else {
1444
                                ig = ShapeFactory.createMultipoint3D(x, y, z);
1445
                        }
1446
                }
1447
                return ig;
1448
                        
1449
        }
1450
        
1451
        private IGeometry getFMapGeometryPoint(Datum[] the_data, int dim) {
1452
                
1453
                double[] ords = OracleSpatialUtils.getOrds(the_data);
1454
                
1455
                if (ords == null) { // sdo_point
1456
                        return getFMapGeometrySdoPoint(the_data, dim);
1457
                }
1458
                
1459
                IGeometry ig = null;
1460
                int total_size = ords.length;
1461
                int no_po = total_size / dim;
1462
                double[] x = new double[no_po];
1463
                double[] y = new double[no_po];
1464
                double[] z = new double[no_po];
1465
                for (int i = 0; i < no_po; i++) {
1466
                        x[i] = ords[i * dim]; // pp[i].getX();
1467
                        y[i] = ords[i * dim + 1];
1468
                        if (dim >= 3) {
1469
                                z[i] = ords[i * dim + 2];
1470
                        }
1471
                }
1472
                
1473
                if (dim == 2) {
1474
                        if (no_po == 1) {
1475
                                ig = ShapeFactory.createPoint2D(x[0], y[0]);
1476
                        } else {
1477
                                ig = ShapeFactory.createMultipoint2D(x, y);
1478
                        }
1479
                        
1480
                } else {
1481
                        if (no_po == 1) {
1482
                                ig = ShapeFactory.createPoint3D(x[0], y[0], z[0]);
1483
                        } else {
1484
                                ig = ShapeFactory.createMultipoint3D(x, y, z);
1485
                        }
1486
                }
1487
                return ig;
1488
                        
1489
        }
1490
        
1491
        
1492
        private IGeometry getFMapGeometrySdoPoint(JGeometry jgp, int d) {
1493
                double[] p = jgp.getPoint();
1494
                IGeometry ig = null;
1495
                if (d == 2) {
1496
                        ig = ShapeFactory.createPoint2D(p[0], p[1]);
1497
                } else {
1498
                        ig = ShapeFactory.createPoint3D(p[0], p[1], p[2]);
1499
                }
1500
                return ig;
1501
        }
1502

    
1503
        private IGeometry getFMapGeometrySdoPoint(Datum[] the_data, int d) {
1504
                double x = 0, y = 0, z = 0;
1505
                try {
1506
                        Datum[] aux = ((STRUCT) the_data[2]).getOracleAttributes();
1507
                        x = ((NUMBER) aux[0]).doubleValue();
1508
                        y = ((NUMBER) aux[1]).doubleValue();
1509
                        if (d > 2) {
1510
                                z = ((NUMBER) aux[2]).doubleValue();
1511
                        }
1512
                } catch (SQLException se) {
1513
                        logger.error("While getting sdo point ordinates: " + se.getMessage(), se);
1514
                }
1515
                
1516
                IGeometry ig = null;
1517
                if (d == 2) {
1518
                        ig = ShapeFactory.createPoint2D(x, y);
1519
                } else {
1520
                        ig = ShapeFactory.createPoint3D(x, y, z);
1521
                }
1522
                return ig;
1523
        }
1524

    
1525
        private boolean isActuallyACollection(JGeometry jg) {
1526
                int[] info = jg.getElemInfo();
1527
                
1528
                if (info == null) {
1529
                        return false; // sdo_point
1530
                }
1531
                
1532
                int size = info.length / 3;
1533
                
1534
                if (size == 1) {
1535
                        return false;
1536
                }
1537
                
1538
                if (size == 2) {
1539
                        return ((info[1] % 1000) != (info[4] % 1000));
1540
                }
1541
                
1542
                int second = info[4] % 1000;
1543
                for (int i=2; i<size; i++) {
1544
                        if ((info[i*3 + 1] % 1000) != second) return true;
1545
                }
1546
                return false;
1547
        }
1548
        
1549
        private boolean isActuallyACollection(Datum[] the_data) {
1550
                
1551
                int[] info = null;
1552
                try {
1553
                        ARRAY aux = (ARRAY) the_data[3];
1554
                        if (aux == null) {
1555
                                return false;
1556
                        }
1557
                        info = aux.getIntArray();
1558
                } catch (SQLException se) {
1559
                        logger.error("While checking collection: " + se.getMessage());
1560
                        return false;
1561
                }
1562

    
1563
                if (info == null) {
1564
                        return false; // sdo_point
1565
                }
1566
                
1567
                int size = info.length / 3;
1568
                
1569
                if (size == 1) {
1570
                        return false;
1571
                }
1572
                
1573
                if (size == 2) {
1574
                        return ((info[1] % 1000) != (info[4] % 1000));
1575
                }
1576

    
1577
                int second = info[4] % 1000;
1578
                for (int i = 2; i < size; i++) {
1579
                        if ((info[i * 3 + 1] % 1000) != second)
1580
                                return true;
1581
                }
1582
                return false;
1583
        }
1584
        
1585

    
1586
        /*
1587
        private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1588
                Object[] _ord_of_elems = jg.getOrdinatesOfElements();
1589
                Object[] ord_of_elems = groupByElement(_ord_of_elems);
1590
                
1591
                int no_of_elems = ord_of_elems.length;
1592
                IGeometry[] geoms = new IGeometry[no_of_elems];
1593
                
1594
                int[] info_array = jg.getElemInfo();
1595
                for (int i=0; i<no_of_elems; i++) {
1596
                        int[] item_info_array = new int[3];
1597
                        item_info_array[0] = 1; // info_array[3 * i + 0]; 
1598
                        item_info_array[1] = info_array[3 * i + 1]; 
1599
                        item_info_array[2] = info_array[3 * i + 2];
1600
                        double[] item_ords = (double[]) ord_of_elems[i];
1601
                        JGeometry itemjg =
1602
                                new JGeometry(item_info_array[1], _srid, item_info_array, item_ords);
1603
                        geoms[i] = getFMapGeometry(itemjg);
1604
                }
1605
                return new FGeometryCollection(geoms);
1606
        }
1607
        */
1608
        
1609
        private IGeometry getFMapGeometryCollection(JGeometry jg, int dim, int _srid) {
1610
                
1611
                int main_type = jg.getType();
1612
                
1613
                int[] all_info_array = jg.getElemInfo();
1614
                Object[] elems_info_aray = groupByElement(all_info_array);
1615
                double[] all_ords = jg.getOrdinatesArray(); 
1616
                Object[] ords_of_groups = getOrdOfGroups(all_ords, elems_info_aray);
1617
                Object[] _elems_info_aray = new Object[elems_info_aray.length];
1618
                for (int i=0; i<elems_info_aray.length; i++) {
1619
                        _elems_info_aray[i] = updateIndexes((int[]) elems_info_aray[i]);
1620
                }
1621
                
1622
                // _elems_info_aray, ords_of_groups
1623
                
1624
                
1625
                int no_of_elems = ords_of_groups.length;
1626
                IGeometry[] geoms = new IGeometry[no_of_elems];
1627
                for (int i=0; i<no_of_elems; i++) {
1628
                        int[] item_info_array = (int[]) _elems_info_aray[i];
1629
                        double[] item_ords = (double[]) ords_of_groups[i];
1630
                        int gtype = dim * 1000 + item_info_array[1] % 1000;
1631
                        
1632
                        // if it's the first geometry, the type is the collection's main type (no?)
1633
                        if (i==0) {
1634
                                gtype = main_type;
1635
                        }
1636
                        
1637
                        JGeometry itemjg = null;
1638
                        if (tableHasSrid) {
1639
                                itemjg = new JGeometry(gtype, _srid, item_info_array, item_ords);
1640
                        } else {
1641
                                itemjg = new JGeometry(gtype, 0, item_info_array, item_ords);
1642
                        }
1643
                        
1644
                        geoms[i] = getFMapGeometry(itemjg, true);
1645
                }
1646
                return new FGeometryCollection(geoms);
1647
        }
1648
        
1649
        
1650
        
1651
        private Datum[] updateIndexes(Datum[] info) {
1652
                int size = info.length / 3;
1653
                NUMBER[] resp = new NUMBER[3 * size];
1654
                
1655
                try {
1656
                        
1657
                int rest = info[0].intValue() - 1;
1658
                for (int i=0; i<size; i++) {
1659
                        resp[3 * i] = new NUMBER(info[3 * i].intValue() - rest);
1660
                        resp[3 * i + 1] = new NUMBER(info[3 * i + 1].intValue());
1661
                        resp[3 * i + 2] = new NUMBER(info[3 * i + 2].intValue());
1662
                }
1663
                
1664
                } catch (SQLException se) {
1665
                        logger.error("Unexpected error: " + se.getMessage());
1666
                }
1667
                return resp;
1668
        }
1669
        
1670
        private int[] updateIndexes(int[] info) {
1671
                int size = info.length / 3;
1672
                int[] resp = new int[3 * size];
1673
                int rest = info[0] - 1;
1674
                for (int i=0; i<size; i++) {
1675
                        resp[3 * i] = info[3 * i] - rest;
1676
                        resp[3 * i + 1] = info[3 * i + 1];
1677
                        resp[3 * i + 2] = info[3 * i + 2];
1678
                }
1679
                return resp;
1680
        }
1681
        
1682
        /*
1683
        private BigDecimal[] updateIndexes(BigDecimal[] info) {
1684
                int size = info.length / 3;
1685
                BigDecimal[] resp = new BigDecimal[3 * size];
1686
                BigDecimal rest = new BigDecimal(info[0].intValue() - 1);
1687
                for (int i=0; i<size; i++) {
1688
                        resp[3 * i] = info[3 * i].subtract(rest);
1689
                        resp[3 * i + 1] = info[3 * i + 1];
1690
                        resp[3 * i + 2] = info[3 * i + 2];
1691
                }
1692
                return resp;
1693
        }
1694
        */
1695
        
1696
        
1697
        private int[] appendIntArrays(int[] head, int[] tail) {
1698
                int[] resp = new int[head.length + tail.length];
1699
                int hsize = head.length;
1700
                for (int i=0; i<hsize; i++) {
1701
                        resp[i] = head[i];
1702
                }
1703
                for (int i=0; i<tail.length; i++) {
1704
                        resp[hsize + i] = tail[i];
1705
                }
1706
                return resp;
1707
        }
1708
        
1709
        private Datum[] appendDatArrays(Datum[] head, Datum[] tail) {
1710
                Datum[] resp = new Datum[head.length + tail.length];
1711
                int hsize = head.length;
1712
                for (int i=0; i<hsize; i++) {
1713
                        resp[i] = head[i];
1714
                }
1715
                for (int i=0; i<tail.length; i++) {
1716
                        resp[hsize + i] = tail[i];
1717
                }
1718
                return resp;
1719
        }
1720
        
1721
        /*
1722
        private BigDecimal[] appendBigDecimalArrays(BigDecimal[] head, BigDecimal[] tail) {
1723
                BigDecimal[] resp = new BigDecimal[head.length + tail.length];
1724
                int hsize = head.length;
1725
                for (int i=0; i<hsize; i++) {
1726
                        resp[i] = head[i];
1727
                }
1728
                for (int i=0; i<tail.length; i++) {
1729
                        resp[hsize + i] = tail[i];
1730
                }
1731
                return resp;
1732
        }
1733
        */
1734
        
1735
        private int[] getNthGroupOfThree(int[] list, int n) {
1736
                int[] resp = new int[3];
1737
                resp[0] = list[3 * n];
1738
                resp[1] = list[3 * n + 1];
1739
                resp[2] = list[3 * n + 2];
1740
                return resp;
1741
        }
1742
        
1743
        private Datum[] getNthGroupOfThree(Datum[] list, int n) {
1744
                Datum[] resp = new Datum[3];
1745
                resp[0] = list[3 * n];
1746
                resp[1] = list[3 * n + 1];
1747
                resp[2] = list[3 * n + 2];
1748
                return resp;
1749
        }
1750
        
1751
        /*
1752
        private BigDecimal[] getNthGroupOfThree(BigDecimal[] list, int n) {
1753
                BigDecimal[] resp = new BigDecimal[3];
1754
                resp[0] = list[3 * n];
1755
                resp[1] = list[3 * n + 1];
1756
                resp[2] = list[3 * n + 2];
1757
                return resp;
1758
        }
1759
        */
1760
        
1761
        private Datum[] getSubSet(Datum[] all, int first_inc, int last_inc) {
1762
                
1763
                Datum[] resp = new Datum[last_inc - first_inc + 1];
1764
                for (int i=first_inc; i<=last_inc; i++) {
1765
                        resp[i-first_inc] = all[i];
1766
                }
1767
                return resp;
1768
        }
1769
        
1770
        private double[] getSubSet(double[] all, int first_inc, int last_inc) {
1771
                
1772
                double[] resp = new double[last_inc - first_inc + 1];
1773
                for (int i=first_inc; i<=last_inc; i++) {
1774
                        resp[i-first_inc] = all[i];
1775
                }
1776
                return resp;
1777
        }
1778
        
1779
        /*
1780
        private BigDecimal[] getSubSet(BigDecimal[] all, int first_inc, int last_inc) {
1781
                
1782
                BigDecimal[] resp = new BigDecimal[last_inc - first_inc + 1];
1783
                for (int i=first_inc; i<=last_inc; i++) {
1784
                        resp[i-first_inc] = all[i];
1785
                }
1786
                return resp;
1787
        }
1788
        */
1789
        
1790
        private Object[] getOrdOfGroups(Datum[] all, Object[] groups) {
1791
                
1792
                Object[] resp = new Object[groups.length];
1793
                if (resp.length == 1) {
1794
                        resp[0] = all;
1795
                        return resp;
1796
                }
1797
                
1798
                int ind = 0;
1799
                int[] aux = (int[]) groups[1];
1800
                int _end = aux[0] - 2;
1801
                Datum[] ord_aux = getSubSet(all, 0, _end);
1802

    
1803
                int _start = _end + 1;
1804
                resp[ind] = ord_aux; ind++;
1805
                
1806
                for (int i=2; i<groups.length; i++) {
1807
                        aux = (int[]) groups[i];
1808
                        _end = aux[0] - 2;
1809
                        ord_aux = getSubSet(all, _start, _end);
1810
                        resp[ind] = ord_aux; ind++;
1811
                        _start = _end + 1;
1812
                }
1813
                
1814
                // last
1815
                _end = all.length - 1;
1816
                ord_aux = getSubSet(all, _start, _end);
1817
                resp[groups.length - 1] = ord_aux;
1818
                
1819
                return resp;
1820
        }
1821
        
1822
        private Object[] getOrdOfGroups(double[] all, Object[] groups) {
1823
                
1824
                Object[] resp = new Object[groups.length];
1825
                if (resp.length == 1) {
1826
                        resp[0] = all;
1827
                        return resp;
1828
                }
1829
                
1830
                int ind = 0;
1831
                int[] aux = (int[]) groups[1];
1832
                int _end = aux[0] - 2;
1833
                double[] ord_aux = getSubSet(all, 0, _end);
1834

    
1835
                int _start = _end + 1;
1836
                resp[ind] = ord_aux; ind++;
1837
                
1838
                for (int i=2; i<groups.length; i++) {
1839
                        aux = (int[]) groups[i];
1840
                        _end = aux[0] - 2;
1841
                        ord_aux = getSubSet(all, _start, _end);
1842
                        resp[ind] = ord_aux; ind++;
1843
                        _start = _end + 1;
1844
                }
1845
                
1846
                // last
1847
                _end = all.length - 1;
1848
                ord_aux = getSubSet(all, _start, _end);
1849
                resp[groups.length - 1] = ord_aux;
1850
                
1851
                return resp;
1852
        }
1853
        
1854
        /*
1855
        private Object[] getOrdOfGroups(BigDecimal[] all, Object[] groups) {
1856
                
1857
                Object[] resp = new Object[groups.length];
1858
                if (resp.length == 1) {
1859
                        resp[0] = all;
1860
                        return resp;
1861
                }
1862
                
1863
                int ind = 0;
1864
                BigDecimal[] aux = (BigDecimal[]) groups[1];
1865
                int _end = aux[0].intValue() - 2;
1866
                BigDecimal[] ord_aux = getSubSet(all, 0, _end);
1867

1868
                int _start = _end + 1;
1869
                resp[ind] = ord_aux; ind++;
1870
                
1871
                for (int i=2; i<groups.length; i++) {
1872
                        aux = (BigDecimal[]) groups[i];
1873
                        _end = aux[0].intValue() - 2;
1874
                        ord_aux = getSubSet(all, _start, _end);
1875
                        resp[ind] = ord_aux; ind++;
1876
                        _start = _end + 1;
1877
                }
1878
                
1879
                // last
1880
                _end = all.length - 1;
1881
                ord_aux = getSubSet(all, _start, _end);
1882
                resp[groups.length - 1] = ord_aux;
1883
                
1884
                return resp;
1885
        }
1886
        */
1887
        
1888
        
1889

    
1890
        private Object[] groupByElement(int[] all_elem) { 
1891
                ArrayList resp = new ArrayList();
1892
                
1893
                int size = all_elem.length / 3;
1894

    
1895
                int[] aux = getNthGroupOfThree(all_elem, 0);
1896

    
1897
                int[] newaux; 
1898
                int i = 1;
1899
                while (i<size) {
1900
                        newaux = getNthGroupOfThree(all_elem, i);
1901
                        
1902
                        if (newaux[0] == aux[0]) {
1903
                                // aux[2] says how many components
1904
                                for (int j=0; j<aux[2]; j++) {
1905
                                        aux = appendIntArrays(aux, getNthGroupOfThree(all_elem, j+i));
1906
                                }
1907
                                resp.add(aux);
1908
                                i = i + aux[2];
1909
                                aux = getNthGroupOfThree(all_elem, i);
1910
                        } else {
1911
                                if (newaux[1] == 2003) {
1912
                                        aux = appendIntArrays(aux, newaux);
1913
                                } else {
1914
                                        resp.add(aux);
1915
                                        aux = getNthGroupOfThree(all_elem, i);
1916
                                }
1917
                        }
1918
                        i++;
1919
                }
1920
                resp.add(aux);
1921
                return resp.toArray();
1922
        }
1923
        
1924
        private Object[] groupByElement(Datum[] all_elem) { 
1925
                ArrayList resp = new ArrayList();
1926
                
1927
                int size = all_elem.length / 3;
1928

    
1929
                Datum[] aux = getNthGroupOfThree(all_elem, 0);
1930

    
1931
                Datum[] newaux; 
1932
                int i = 1;
1933
                
1934
                try {
1935
                        
1936
                while (i<size) {
1937
                        newaux = getNthGroupOfThree(all_elem, i);
1938
                        
1939
                        if (newaux[0] == aux[0]) {
1940
                                // aux[2] says how many components
1941
                                for (int j=0; j<((NUMBER) aux[2]).intValue(); j++) {
1942
                                        aux = appendDatArrays(aux, getNthGroupOfThree(all_elem, j+i));
1943
                                }
1944
                                resp.add(aux);
1945
                                i = i + ((NUMBER) aux[2]).intValue();
1946
                                aux = getNthGroupOfThree(all_elem, i);
1947
                        } else {
1948
                                if (((NUMBER) newaux[1]).intValue() == 2003) {
1949
                                        aux = appendDatArrays(aux, newaux);
1950
                                } else {
1951
                                        resp.add(aux);
1952
                                        aux = getNthGroupOfThree(all_elem, i);
1953
                                }
1954
                        }
1955
                        i++;
1956
                }
1957

    
1958
                } catch (SQLException se) {
1959
                        logger.error("Unexpected error: " + se.getMessage());
1960
                }
1961

    
1962
                resp.add(aux);
1963
                return resp.toArray();
1964
        }
1965
        
1966
        /*
1967
        private Object[] groupByElement(BigDecimal[] all_elem) { 
1968
                ArrayList resp = new ArrayList();
1969
                
1970
                int size = all_elem.length / 3;
1971

1972
                BigDecimal[] aux = getNthGroupOfThree(all_elem, 0);
1973

1974
                BigDecimal[] newaux; 
1975
                int i = 1;
1976
                while (i<size) {
1977
                        newaux = getNthGroupOfThree(all_elem, i);
1978
                        
1979
                        if (newaux[0] == aux[0]) {
1980
                                // aux[2] says how many components
1981
                                for (int j=0; j<aux[2].intValue(); j++) {
1982
                                        aux = appendBigDecimalArrays(aux, getNthGroupOfThree(all_elem, j+i));
1983
                                }
1984
                                resp.add(aux);
1985
                                i = i + aux[2].intValue();
1986
                                aux = getNthGroupOfThree(all_elem, i);
1987
                        } else {
1988
                                if (newaux[1].intValue() == 2003) {
1989
                                        aux = appendBigDecimalArrays(aux, newaux);
1990
                                } else {
1991
                                        resp.add(aux);
1992
                                        aux = getNthGroupOfThree(all_elem, i);
1993
                                }
1994
                        }
1995
                        i++;
1996
                }
1997
                resp.add(aux);
1998
                return resp.toArray();
1999
        }
2000
        */
2001

    
2002
        private IGeometry getJGeometryPoint2D(JGeometry _jgeom) {
2003
                Point2D p = _jgeom.getJavaPoint();
2004
                IGeometry ig = ShapeFactory.createPoint2D(p.getX(), p.getY());
2005
                return ig;
2006
        }
2007

    
2008
        private IGeometry getJGeometryMultiPoint2D(JGeometry _jgeom) {
2009
                Point2D[] pp = _jgeom.getJavaPoints();
2010
                int l = pp.length;
2011
                double x[] = new double[l];
2012
                double y[] = new double[l];
2013
                for (int i = 0; i < l; i++) {
2014
                        x[i] = pp[i].getX();
2015
                        y[i] = pp[i].getY();
2016
                }
2017
                IGeometry ig = ShapeFactory.createMultipoint2D(x, y);
2018
                return ig;
2019
        }
2020

    
2021
        private IGeometry getJGeometryOther(JGeometry _jgeom) {
2022
                int type = oracleTypeToFShapeTypeExceptPointTypes(_jgeom.getType());
2023
                Shape shape = _jgeom.createShape();
2024
                GeneralPathX gpx = new GeneralPathX(shape);
2025
                IGeometry ig = null;
2026

    
2027
                switch (type) {
2028
                case FShape.LINE:
2029
                        FPolyline2D fpl = new FPolyline2D(gpx);
2030
                        ig = ShapeFactory.createPolyline2D(gpx);
2031
                        break;
2032
                case FShape.POLYGON:
2033
                        FPolygon2D fpg = new FPolygon2D(gpx);
2034
                        ig = ShapeFactory.createPolygon2D(gpx);
2035
                        break;
2036
                }
2037
                return ig;
2038
        }
2039

    
2040
        private IGeometry getGeotoolsIGeometry(oracle.sql.STRUCT _struct) {
2041
                Geometry geo_jts = null;
2042
                try {
2043
                        geo_jts = geotools_conv.asGeometry(_struct);
2044
                } catch (SQLException e) {
2045
                        System.err.println("While using geotools converter: "
2046
                                        + e.getMessage());
2047
                }
2048
                IGeometry ig = FConverter.jts_to_igeometry(geo_jts);
2049
                return ig;
2050
        }
2051

    
2052
        private int oracleTypeToFShapeTypeExceptPointTypes(int type) {
2053

    
2054
                /*
2055
                 * Tipos en Oracle Spatial usando JGeometry
2056
                 * 
2057
                 * GTYPE_COLLECTION collection geometry type
2058
                 * GTYPE_CURVE curve geoemtry type
2059
                 * GTYPE_MULTICURVE multi-curve geometry type
2060
                 * GTYPE_MULTIPOINT multi-point geometry type
2061
                 * GTYPE_MULTIPOLYGON multi-polygon geometry type
2062
                 * GTYPE_POINT point geometry type
2063
                 * GTYPE_POLYGON  polygon geometry type
2064
                 * 
2065
                 * Tipos gvSIG FShape
2066
                 * 
2067
                 * NULL = 0;
2068
                 * POINT = 1;
2069
                 * LINE = 2;
2070
                 * POLYGON = 4;
2071
                 * TEXT = 8;
2072
                 * MULTI = 16;
2073
                 * MULTIPOINT = 32;
2074
                 * CIRCLE = 64;
2075
                 * ARC = 128;
2076
                 * ELLIPSE=256;
2077
                 * Z=512
2078
                 */
2079

    
2080
                switch (type) {
2081

    
2082
                case JGeometry.GTYPE_POLYGON:
2083
                case JGeometry.GTYPE_MULTIPOLYGON:
2084
                        return FShape.POLYGON;
2085

    
2086
                case JGeometry.GTYPE_CURVE:
2087
                case JGeometry.GTYPE_MULTICURVE:
2088
                        return FShape.LINE;
2089

    
2090
                }
2091

    
2092
                System.err.println("Unhandled Oracle Spatial geometry type: " + type
2093
                                + " (conversion returned FShape.NULL)");
2094

    
2095
                return FShape.NULL;
2096
        }
2097

    
2098
        private void cleanWhereClause() {
2099
                emptyWhereClause = false;
2100
                String aux = getWhereClauseWithoutWhere();
2101
                for (int i = 0; i < aux.length(); i++)
2102
                        if (aux.substring(i, i + 1).compareTo(" ") != 0)
2103
                                return;
2104
                getLyrDef().setWhereClause("");
2105
                emptyWhereClause = true;
2106
        }
2107

    
2108
        private String getMainSelect(String r) {
2109

    
2110
                String resp = "";
2111

    
2112
                if (isGeogCS) {
2113
                        
2114
                        String vport = "sdo_filter(" + geoColName + ", SDO_CS.VIEWPORT_TRANSFORM(" 
2115
                        + r + ", " + oracleSRID + "), 'querytype=window') = 'TRUE'";
2116
                        
2117
                        if (emptyWhereClause) {
2118
                                resp = "select " + getStandardSelectExpression() + ", c."
2119
                                                + geoColName + " from " + getTableName()
2120
                                                + " c where (" + vport + ")";
2121
                        } else {
2122
                                resp = "select " + getStandardSelectExpression() + ", c." 
2123
                                                + geoColName + " from " + getTableName()
2124
                                                + " c where " + "((" + getWhereClauseWithoutWhere()
2125
                                                + ") AND (" + vport + "))";
2126
                        }
2127

    
2128
                } else {
2129
                        if (emptyWhereClause) {
2130
                                resp = "select " + getStandardSelectExpression() + ", c."
2131
                                                + geoColName + " from " + getTableName()
2132
                                                + " c where (" + "sdo_relate(" + geoColName + ", " + r
2133
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE')";
2134
                        } else {
2135
                                resp = "select " + getStandardSelectExpression() + ", c." 
2136
                                                + geoColName + " from " + getTableName()
2137
                                                + " c where " + "((" + getWhereClauseWithoutWhere()
2138
                                                + ") AND (" + "sdo_relate(" + geoColName + ", " + r
2139
                                                + ", 'mask=anyinteract querytype=window') = 'TRUE'))";
2140
                        }
2141
                }
2142
                // resp = resp + " order by rowid";
2143
                // resp = "select " + getStandardSelectExpression() + " from " + getTableName() + " c";
2144
                return resp;
2145
        }
2146

    
2147
        public void setWorkingArea(Rectangle2D rect) {
2148
                super.setWorkingArea(rect);
2149
                originalOracleWorkingArea = rect;
2150

    
2151
        }
2152

    
2153
        private void setWAStruct() {
2154
                originalOracleWAStruct = shapeToStruct(originalOracleWorkingArea,
2155
                                FShape.NULL, tableHasSrid, false, true);
2156
        }
2157

    
2158
        private Geometry shapeToGeometry(Shape shp) {
2159

    
2160
                if (shp == null) {
2161
                        return null;
2162
                }
2163

    
2164
                int type = FShape.POLYGON;
2165
                if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D)))
2166
                        type = FShape.LINE;
2167
                if (shp instanceof FPoint2D)
2168
                        type = FShape.POINT;
2169
                if (shp instanceof FMultiPoint2D)
2170
                        type = FShape.MULTIPOINT;
2171

    
2172
                GeneralPathX wagp = new GeneralPathX(shp);
2173
                /*
2174
                 switch (type) {
2175
                 case FShape.POINT:
2176
                 FPoint2D fp = 
2177
                 FPolyline2D fpl = new FPolyline2D(gpx);
2178
                 ig = ShapeFactory.createPolyline2D(gpx);
2179
                 break;                        
2180
                 
2181
                 }
2182
                 */
2183
                FShapeGeneralPathX fwagp = new FShapeGeneralPathX(wagp, type);
2184
                return FConverter.java2d_to_jts(fwagp);
2185
        }
2186

    
2187
        public static Rectangle2D getBoundingBox(JGeometry _jg) {
2188
                Shape shape = _jg.createShape();
2189
                return shape.getBounds2D();
2190
        }
2191

    
2192
        private void printStruct(STRUCT st) {
2193

    
2194
                System.out.println("----------------------------------------------");
2195
                try {
2196
                        Object[] att = st.getAttributes();
2197
                        int l = att.length;
2198
                        for (int i = 0; i < l; i++) {
2199
                                System.out.println("ATT " + i + ": " + att[i].toString());
2200
                        }
2201
                } catch (Exception ex) {
2202
                        System.out
2203
                                        .println("- Error ---------------------------------------");
2204
                }
2205
                System.out.println("----------------------------------------------");
2206
        }
2207

    
2208

    
2209
        private static STRUCT rectangleToStruct(Rectangle2D r,
2210
                        boolean hasSrid,
2211
                        boolean isView,
2212
                        boolean _isGeogCS,
2213
                        String _oracleSRID,
2214
                        Connection __conn) {
2215

    
2216
                Point2D c1 = new Point2D.Double(r.getMinX(), r.getMinY());
2217
                Point2D c2 = new Point2D.Double(r.getMaxX(), r.getMaxY());
2218

    
2219
                if ((_isGeogCS) && (isView)) {
2220
                        c1.setLocation(Math.max(c1.getX(), -180), Math.max(c1.getY(), -90));
2221
                        c2.setLocation(Math.min(c2.getX(), 180), Math.min(c2.getY(), 90));
2222
                }
2223

    
2224
                STRUCT resp = null;
2225
                try {
2226
                        // System.out.println("ABIERTA: " + (!conn.isClosed()));
2227
                        // resp = structCreator.toSTRUCT(rect_wkt.getBytes(), conn);
2228
                        // Object[] old_obj = resp.getAttributes();
2229
                        int size = 5;
2230
                        Object[] new_obj = new Object[size];
2231

    
2232
                        // for (int i=0; i<size; i++) new_obj[i] = old_obj[i];
2233
                        new_obj[0] = new NUMBER(2003);
2234
                        
2235
                        if (hasSrid) {
2236
                                new_obj[1] = new NUMBER(_oracleSRID);
2237
                        } else {
2238
                                new_obj[1] = null;
2239
                        }
2240
                        
2241
                        new_obj[2] = null;
2242

    
2243
                        NUMBER[] elem_info = new NUMBER[3];
2244
                        elem_info[0] = new NUMBER(1);
2245
                        elem_info[1] = new NUMBER(1003);
2246
                        elem_info[2] = new NUMBER(3);
2247
                        new_obj[3] = elem_info;
2248

    
2249
                        NUMBER[] ords = null;
2250
                        ords = new NUMBER[4];
2251
                        ords[0] = new NUMBER(c1.getX());
2252
                        ords[1] = new NUMBER(c1.getY());
2253
                        ords[2] = new NUMBER(c2.getX());
2254
                        ords[3] = new NUMBER(c2.getY());
2255
                        new_obj[4] = ords;
2256

    
2257
                        // StructDescriptor dsc = StructDescriptor.createDescriptor("STRUCT", conn);
2258
                        StructDescriptor dsc = StructDescriptor.createDescriptor(
2259
                                        "MDSYS.SDO_GEOMETRY", __conn);
2260

    
2261
                        resp = new STRUCT(dsc, __conn, new_obj);
2262
                } catch (Exception ex) {
2263
                        logger.error("Error while creating rect struct: "
2264
                                        + ex.getMessage(), ex);
2265
                }
2266
                return resp;
2267
        }
2268

    
2269
        /*
2270
        private ResultSet getCursorold(STRUCT geoStruct, String fixsql,
2271
                        boolean hasSrid) {
2272

2273
                String sdo_intersect = getSdoConstructor(geoStruct, hasSrid);
2274
                String main_sel = "";
2275

2276
                if (fixsql == null) {
2277
                        // main_sel = getMainSelect3(var_name);
2278
                        main_sel = getMainSelect4(sdo_intersect);
2279
                } else {
2280
                        main_sel = fixsql;
2281
                }
2282

2283
                String declare_func = "";
2284

2285
                declare_func = "CREATE OR REPLACE FUNCTION getMainCursor ";
2286
                // declare_func = "CREATE OR REPLACE FUNCTION getMainCursor ";
2287
                declare_func = declare_func + "RETURN SYS_REFCURSOR " + "AS "
2288
                                + "the_cursor SYS_REFCURSOR; ";
2289

2290
                declare_func = declare_func + "BEGIN ";
2291

2292
                declare_func = declare_func + "OPEN the_cursor FOR " + main_sel + "; " +
2293
                // declare_func = declare_func + "OPEN the_cursor FOR select " + getStandardSelectExpression() + " from PROVINCIA c; " +
2294

2295
                                "RETURN the_cursor; " + "END;";
2296

2297
                ResultSet _resp = null;
2298

2299
                try {
2300
                        Statement stmnt = conn.createStatement();
2301
                        stmnt.execute(declare_func);
2302

2303
                        // declare_func =  "BEGIN ? := getMainCursor(?); END;";
2304
                        declare_func = "BEGIN ? := getMainCursor; END;";
2305

2306
                        CallableStatement callable = conn.prepareCall(declare_func);
2307

2308
                        callable.registerOutParameter(1, OracleTypes.CURSOR);
2309
                        callable.execute();
2310

2311
                        _resp = (ResultSet) callable.getObject(1);
2312

2313
                        stmnt.close();
2314
                } catch (SQLException se) {
2315
                        System.err.println("Error while getting main cursor");
2316
                }
2317

2318
                return _resp;
2319
        }
2320
        */
2321
        
2322
        private Object[] getViewResultSet(STRUCT geoStruct, String fixsql,
2323
                        boolean hasSrid) {
2324

    
2325
                String sdo_intersect = getSdoConstructor(geoStruct, hasSrid);
2326
                String main_sel = "";
2327

    
2328
                if (fixsql == null) {
2329
                        // main_sel = getMainSelect3(var_name);
2330
                        main_sel = getMainSelect(sdo_intersect);
2331
                } else {
2332
                        main_sel = fixsql;
2333
                }
2334
                
2335
                System.err.println("main sel = " + main_sel);
2336

    
2337
                ResultSet _rs = null;
2338
                Statement _stmnt = null;
2339
                Object[] _resp = new Object[2];
2340

    
2341
                try {
2342
                        _stmnt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
2343
                                        ResultSet.CONCUR_READ_ONLY);
2344
                        _stmnt.setFetchDirection(ResultSet.FETCH_FORWARD);
2345
                        _stmnt.setFetchSize(FETCH_SIZE);
2346
                        
2347
                        _rs = _stmnt.executeQuery(main_sel);
2348
                        // stmnt.close();
2349
                } catch (SQLException se) {
2350
                        logger.error("Error while getting main cursor: " + se.getMessage(), se);
2351
                }
2352

    
2353
                // this method returns the statement too, so that it can be closed afterwards
2354
                _resp[0] = _rs;
2355
                _resp[1] = _stmnt;
2356
                return _resp;
2357
        }
2358
        
2359

    
2360
        private String getSdoConstructor(STRUCT geoStruct, boolean hasSrid) {
2361
                String resp = "";
2362
                try {
2363

    
2364
                        String mdsys_sdo_elem_info_array = "mdsys.sdo_elem_info_array(1, 1003, 3)";
2365
                        String mdsys_sdo_ordinate_array = "";
2366
                        Datum[] vertices = ((ARRAY) geoStruct.getOracleAttributes()[4]).getOracleArray();
2367
                        for (int i = 0; i < vertices.length; i++) {
2368
                                mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array
2369
                                                + vertices[i].doubleValue() + ", ";
2370
                        }
2371
                        mdsys_sdo_ordinate_array = mdsys_sdo_ordinate_array.substring(0,
2372
                                        mdsys_sdo_ordinate_array.length() - 2);
2373
                        mdsys_sdo_ordinate_array = "mdsys.sdo_ordinate_array("
2374
                                        + mdsys_sdo_ordinate_array + ")";
2375

    
2376
                        String aux = "";
2377
                        if (hasSrid) {
2378
                                aux = oracleSRID;
2379
                                if (isGeogCS) {
2380
                                        aux = "0";
2381
                                }
2382
                        } else {
2383
                                aux = "null";
2384
                        }
2385
                        
2386

    
2387
                        resp = "mdsys.sdo_geometry(2003, " + aux + ", null, "
2388
                                        + mdsys_sdo_elem_info_array + ", "
2389
                                        + mdsys_sdo_ordinate_array + ")";
2390

    
2391
                } catch (Exception ex) {
2392
                        System.err.println("Error while getting sdo contructor: "
2393
                                        + ex.getMessage());
2394
                }
2395

    
2396
                return resp;
2397
        }
2398

    
2399
        public String getIdAndElemInfoFullResulltSetQuery() {
2400

    
2401
                String resp = "select rowid, c." + geoColName
2402
                + ".SDO_ELEM_INFO from " + getTableName() + " c";
2403
                
2404
//                String resp = "select rowid from " + getTableName();
2405

    
2406

    
2407
                if (originalOracleWAStruct == null) {
2408
                        if (emptyWhereClause) {
2409
                                // return "select rowid from " + getTableName();
2410
                        } else {
2411
                                resp = resp + " where " + "(" + getWhereClauseWithoutWhere()
2412
                                                + ")";
2413
                        }
2414
                } else {
2415
                        if (emptyWhereClause) {
2416
                                resp = resp + " where (sdo_relate(" + geoColName
2417
                                                + ", ?, 'mask=anyinteract querytype=window') = 'TRUE')";
2418
                        } else {
2419
                                resp = resp
2420
                                                + " where "
2421
                                                + "(("
2422
                                                + getWhereClauseWithoutWhere()
2423
                                                + ") AND ("
2424
                                                + "sdo_relate("
2425
                                                + geoColName
2426
                                                + ", ?, 'mask=anyinteract querytype=window') = 'TRUE'))";
2427
                        }
2428
                }
2429

    
2430
                // resp = resp + " order by rowid";
2431
                return resp;
2432
        }
2433

    
2434
        /*
2435
        private String getSearchRowNumQuery(int zero_based_row) {
2436

2437
                if (originalOracleWAStruct == null) {
2438
                        if (emptyWhereClause) {
2439
                                return "select * from (select " + getStandardSelectExpressionTrue() + " from "
2440
                                                + getTableName() + " c order by rowid) where (n = "
2441
                                                + (zero_based_row + 1) + ")";
2442
                        } else {
2443
                                return "select * from (select " + getStandardSelectExpressionTrue() + " from "
2444
                                                + getTableName() + " c " + " where " + "("
2445
                                                + getWhereClauseWithoutWhere() + ") order by rowid"
2446
                                                + ") where (n = " + (zero_based_row + 1) + ")";
2447
                        }
2448
                } else {
2449
                        if (emptyWhereClause) {
2450
                                return "select * from (select " + getStandardSelectExpressionTrue() + " from "
2451
                                                + getTableName() + " c " + " where (sdo_relate("
2452
                                                + geoColName
2453
                                                + ", ?, 'mask=anyinteract querytype=window') = 'TRUE')"
2454
                                                + " order by rowid) where (n = " + (zero_based_row + 1)
2455
                                                + ")";
2456
                        } else {
2457
                                return "select * from (select " + getStandardSelectExpressionTrue() + " from "
2458
                                                + getTableName()
2459
                                                + " c "
2460
                                                + " where "
2461
                                                + "(("
2462
                                                + getWhereClauseWithoutWhere()
2463
                                                + ") AND ("
2464
                                                + "sdo_relate("
2465
                                                + geoColName
2466
                                                + ", ?, 'mask=anyinteract querytype=window') = 'TRUE')) order by rowid) where (n = "
2467
                                                + (zero_based_row + 1) + ")";
2468
                        }
2469
                }
2470
        }
2471
        */
2472

    
2473
        private String getSearchId() {
2474

    
2475
                if (emptyWhereClause) {
2476
                        return "select " + getStandardSelectExpression()
2477
                        + ", c." + geoColName
2478
                        + " from " + getTableName()
2479
                                        + " c where rowid = ?";
2480
                } else {
2481
                        return "select " + getStandardSelectExpression()
2482
                        + ", c." + geoColName
2483
                        + " from " + getTableName() + " c "
2484
                                        + " where " + "((" + getWhereClauseWithoutWhere()
2485
                                        + ") and (rowid = ?))";
2486
                }
2487
        }
2488

    
2489
        public int getShapeType() {
2490
                return shapeType;
2491
        }
2492

    
2493
        private String getWhereClauseWithoutWhere() {
2494
                String resp = "";
2495
                String old = getLyrDef().getWhereClause();
2496
                resp = old;
2497

    
2498
                if (old.length() <= 6) {
2499
                        return old;
2500
                }
2501

    
2502
                if (old.substring(0, 6).compareToIgnoreCase("where ") == 0) {
2503
                        resp = resp.substring(6, resp.length());
2504
                }
2505
                return resp;
2506
        }
2507

    
2508
        private Rectangle2D doIntersect(Rectangle2D r1, Rectangle2D r2) {
2509
                if (r1.getMaxX() <= r2.getMinX())
2510
                        return null;
2511
                if (r2.getMaxX() <= r1.getMinX())
2512
                        return null;
2513
                if (r1.getMaxY() <= r2.getMinY())
2514
                        return null;
2515
                if (r2.getMaxY() <= r1.getMinY())
2516
                        return null;
2517

    
2518
                double minx = Math.max(r1.getMinX(), r2.getMinX());
2519
                double miny = Math.max(r1.getMinY(), r2.getMinY());
2520
                double maxx = Math.min(r1.getMaxX(), r2.getMaxX());
2521
                double maxy = Math.min(r1.getMaxY(), r2.getMaxY());
2522

    
2523
                double w = maxx - minx;
2524
                double h = maxy - miny;
2525

    
2526
                return new Rectangle2D.Double(minx, miny, w, h);
2527
        }
2528

    
2529
        private static int maxSizeForFieldType(int _type) {
2530

    
2531
                switch (_type) {
2532
                case Types.VARCHAR:
2533
                        return OracleSpatialDriver.VARCHAR2_STANDARD_SIZE;
2534
                case Types.LONGVARCHAR:
2535
                        return OracleSpatialDriver.VARCHAR2_LONG_SIZE;
2536
                }
2537
                return -1;
2538
        }
2539

    
2540
        public static String fieldTypeToSqlStringType(int fieldType) {
2541

    
2542
                String aux = "VARCHAR2(" + VARCHAR2_STANDARD_SIZE + " BYTE)"; // Por defecto.
2543

    
2544
                Value v;
2545
                switch (fieldType) {
2546

    
2547
                
2548
                
2549
                case Types.SMALLINT:
2550
                        aux = "NUMBER(5, 0)";
2551
                        break;
2552
                case Types.INTEGER:
2553
                        aux = "NUMBER(10, 0)";
2554
                        break;
2555
                case Types.BIGINT:
2556
                        aux = "NUMBER(38, 0)";
2557
                        break;
2558
                case Types.BOOLEAN:
2559
                        aux = "NUMBER(1, 0)";
2560
                        break;
2561
                case Types.DECIMAL:
2562
                        aux = "NUMBER";
2563
                        break;
2564
                case Types.NUMERIC:
2565
                        aux = "NUMBER";
2566
                        break;
2567
                case Types.DOUBLE:
2568
                        aux = "FLOAT";
2569
                        break;
2570
                case Types.FLOAT:
2571
                        aux = "FLOAT";
2572
                        break;
2573
                case Types.CHAR:
2574
                        aux = "CHAR(1 BYTE)";
2575
                        break;
2576
                case Types.VARCHAR:
2577
                        aux = "NVARCHAR2(" + VARCHAR2_STANDARD_SIZE + ")";
2578
                        break;
2579
                case Types.LONGVARCHAR:
2580
                        aux = "NVARCHAR2(" + VARCHAR2_LONG_SIZE + ")";
2581
                        break;
2582
                }
2583
                return aux;
2584
        }
2585

    
2586
        // -----------------------------------------------------------
2587
        // -----------------------------------------------------------
2588
        // -----------------------------------------------------------
2589
        public static String getDropTableSql(DBLayerDefinition dbLayerDef) {
2590
                return "DROP TABLE \"" + dbLayerDef.getTableName()
2591
                                + "\" CASCADE CONSTRAINTS";
2592
        }
2593

    
2594
        public static String getTableCreationSql(DBLayerDefinition dbLayerDef) {
2595

    
2596
                FieldDescription[] flds = dbLayerDef.getFieldsDesc();
2597

    
2598
                String type = "";
2599
                String name = "";
2600

    
2601
                String resp = "CREATE TABLE \"" + dbLayerDef.getTableName() + "\" ( ";
2602
                for (int i = 0; i < flds.length; i++) {
2603
                        name = flds[i].getFieldName();
2604

    
2605
                        // -------------- FORBIDDEN FIELD NAMES -----------------
2606
                        if (!isOracleAllowedFieldname(name)) {
2607
                                continue;
2608
                        }
2609
                        // ------------------------------------------------------
2610

    
2611
                        if (name.compareToIgnoreCase(DEFAULT_GEO_FIELD) == 0) {
2612

    
2613
                        } else {
2614
                                name = getValidOracleID(name, i);
2615
                                resp = resp + "\"" + name + "\" ";
2616
                                type = fieldTypeToSqlStringType(flds[i].getFieldType());
2617
                                resp = resp + type + ", ";
2618
                        }
2619
                }
2620

    
2621
                resp = resp + "\"" + DEFAULT_GEO_FIELD + "\" ";
2622
                resp = resp + "\"MDSYS\".\"SDO_GEOMETRY\"";
2623
                resp = resp + ", ";
2624

    
2625
                String pk = "CONSTRAINT \"" + dbLayerDef.getTableName()
2626
                                + "_PK\" PRIMARY KEY (\""
2627
                                + OracleSpatialDriver.DEFAULT_ID_FIELD + "\") ENABLE";
2628

    
2629
                resp = resp + pk + " )";
2630
                return resp;
2631
        }
2632

    
2633
        public static String getIndexCreationSql(DBLayerDefinition dbLayerDef) {
2634

    
2635
                String resp = "CREATE INDEX \"" + dbLayerDef.getTableName()
2636
                                + "_SX\" ON \"" + dbLayerDef.getTableName() + "\" (\""
2637
                                + OracleSpatialDriver.DEFAULT_GEO_FIELD
2638
                                + "\") INDEXTYPE IS \"MDSYS\".\"SPATIAL_INDEX\" ";
2639

    
2640
                /*
2641
                 CREATE INDEX "SPATIAL"."US_STATES_SX" ON "SPATIAL"."US_STATES" ("GEOM") 
2642
                 INDEXTYPE IS "MDSYS"."SPATIAL_INDEX" ;
2643
                 "\"MDSYS\".\"SPATIAL_INDEX\""
2644
                 */
2645
                return resp;
2646
        }
2647

    
2648
        public static String getRemoveMetadataSql(DBLayerDefinition dbLayerDef) {
2649
                return "DELETE FROM " + ORACLE_GEOMETADATA_VIEW
2650
                                + " WHERE TABLE_NAME = '" + dbLayerDef.getTableName() + "'";
2651
        }
2652

    
2653
        public static String getMetadataUpdateSql(String tName, String ora_srid,
2654
                        Rectangle2D bbox, int dim, boolean withsrid) {
2655

    
2656
                String[] dim_name = new String[dim];
2657
                double tolerance = 0.5;
2658

    
2659
                if (ora_srid.compareTo(GEODETIC_SRID) == 0) {
2660
                        dim_name[0] = "LONGITUDE";
2661
                        dim_name[1] = "LATITUDE";
2662
                } else {
2663
                        dim_name[0] = "X";
2664
                        dim_name[1] = "Y";
2665
                        if (dim > 2) {
2666
                                dim_name[2] = "Z";
2667
                                if (dim > 3) {
2668
                                        dim_name[3] = "T";
2669
                                }
2670
                        }
2671
                }
2672

    
2673
                String resp = "INSERT INTO " + ORACLE_GEOMETADATA_VIEW + " "
2674
                                + " ( TABLE_NAME, COLUMN_NAME, DIMINFO, SRID ) " + " VALUES ("
2675
                                + "'" + tName + "', " + "'" + DEFAULT_GEO_FIELD + "', "
2676
                                + "SDO_DIM_ARRAY( " +
2677
                                
2678
                                "SDO_DIM_ELEMENT ('" + dim_name[0] + "', " + bbox.getMinX() + ", "
2679
                                + bbox.getMaxX() + ", "        + tolerance + " ), " +
2680
                                "SDO_DIM_ELEMENT ('" + dim_name[1] + "', " + bbox.getMinY() + ", "
2681
                                + bbox.getMaxY() + ", " + tolerance + " ))";
2682
                                
2683
                if (dim > 2) {
2684
                        resp = resp.substring(0, resp.length() - 1) + ",";
2685
                        resp = resp + "SDO_DIM_ELEMENT ('" + dim_name[2] + "', 0.0, 100.0, "
2686
                        + tolerance + " ))";
2687
                        if (dim > 3) {
2688
                                resp = resp.substring(0, resp.length() - 1) + ",";
2689
                                resp = resp + "SDO_DIM_ELEMENT ('" + dim_name[3] + "', 0.0, 100.0, "
2690
                                + tolerance + " ))";
2691
                        }
2692
                }
2693
                if (withsrid) {
2694
                        resp = resp + ", " + ora_srid + " )";
2695
                } else {
2696
                        resp = resp + ", NULL )";
2697
                }
2698
                return resp;
2699
        }
2700

    
2701
        public static String getRowInsertSql(IFeature feat,
2702
                        DBLayerDefinition dbLayerDef, int rowInd, String _geoColName) {
2703

    
2704
                String name = "";
2705
                String aux_orig = "";
2706
                String aux_limited = "";
2707
                String aux_quotes_ok = "";
2708

    
2709
                FieldDescription[] fieldsDescr = dbLayerDef.getFieldsDesc();
2710

    
2711
                String resp = "INSERT INTO \"" + dbLayerDef.getTableName() + "\" ( ";
2712

    
2713
                for (int i = 0; i < fieldsDescr.length; i++) {
2714
                        name = fieldsDescr[i].getFieldName();
2715

    
2716
                        // -------------- FORBIDDEN FIELD NAMES -----------------
2717
                        if (!isOracleAllowedFieldname(name)) {
2718
                                continue;
2719
                        }
2720
                        // ------------------------------------------------------
2721

    
2722
                        if (name.compareToIgnoreCase(_geoColName) == 0) {
2723
                        } else {
2724
                                name = getValidOracleID(name, i);
2725
                                resp = resp + "\"" + name + "\"" + " , ";
2726
                        }
2727
                }
2728

    
2729
                resp = resp + _geoColName + " ) VALUES ( ";
2730

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

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

    
2740
                        String sur = getValueSurroundFromType(fieldsDescr[i].getFieldType());
2741

    
2742
                        if (name.compareToIgnoreCase(_geoColName) == 0) {
2743
                        } else {
2744
                                if (name
2745
                                                .compareToIgnoreCase(OracleSpatialDriver.DEFAULT_ID_FIELD) == 0) {
2746
                                        resp = resp + rowInd + " , ";
2747
                                } else {
2748
                                        Value attValue = feat.getAttribute(i);
2749
                                        if (attValue.toString() == null) {
2750
                                                resp = resp + "NULL , ";
2751
                                        } else {
2752
                                                if (sur.length() > 0) {
2753
                                                        aux_orig = attValue.toString();
2754
                                                        aux_limited = cropStringValue(aux_orig, i,
2755
                                                                        fieldsDescr);
2756
                                                        aux_quotes_ok = avoidQuoteProblem(aux_limited);
2757
                                                        
2758
                                                        resp = resp + sur + aux_quotes_ok + sur + " , ";
2759
                                                } else {
2760
                                                        String _aux = attValue.toString();
2761
                                                        if (_aux.length() == 0) {
2762
                                                                _aux = "NULL";
2763
                                                        }
2764
                                                        resp = resp + _aux + " , ";
2765
                                                }
2766
                                        }
2767
                                }
2768
                        }
2769
                }
2770
                resp = resp + " ? )";
2771
                return resp;
2772
        }
2773
        
2774
        public static String getRowUpdateSql(IFeature feat,
2775
                        DBLayerDefinition dbLayerDef, int rowInd, String geoFieldName) {
2776

    
2777
                String name = "";
2778
                String aux_orig = "";
2779
                String aux_limited = "";
2780
                String aux_quotes_ok = "";
2781
                
2782
                Value[] atts = feat.getAttributes();
2783
                FieldDescription[] _fieldsDescr = dbLayerDef.getFieldsDesc();
2784

    
2785
                String resp = "UPDATE \"" + dbLayerDef.getTableName() + "\" SET ";
2786

    
2787
                for (int i = 0; i < _fieldsDescr.length; i++) {
2788
                        name = _fieldsDescr[i].getFieldName();
2789

    
2790
                        // -------------- FORBIDDEN FIELD NAMES -----------------
2791
                        if (!isOracleAllowedFieldname(name)) {
2792
                                logger.info("Field: " + name + " will not be updated.");
2793
                                continue;
2794
                        }
2795
                        if (isStructAndNotGeoField(_fieldsDescr[i].getFieldType(), name, geoFieldName)) {
2796
                                logger.info("Field: " + name + " will not be updated (it's a struct).");
2797
                                continue;
2798
                        }
2799
                        // ------------------------------------------------------
2800

    
2801
                        if (name.compareToIgnoreCase(geoFieldName) == 0) {
2802
                                resp = resp + "\"" + name + "\"" + " = ?, ";
2803
                        } else {
2804
                                String sur = getValueSurroundFromType(_fieldsDescr[i].getFieldType());
2805
                                aux_orig = atts[i].toString();
2806
                                aux_limited = cropStringValue(aux_orig, i, _fieldsDescr);
2807
                                aux_quotes_ok = avoidQuoteProblem(aux_limited);                                
2808
                                resp = resp + "\"" + name + "\"" + " = " + sur + aux_quotes_ok + sur + ", ";
2809
                        }
2810
                }
2811

    
2812
                resp = resp.substring(0, resp.length() - 2);
2813
                resp = resp + " WHERE ROWID ='" + feat.getID() + "'";
2814
                return resp;
2815
        }
2816
        
2817
        private static boolean isStructAndNotGeoField(int ftype, String fldname, String geoname) {
2818
                
2819
                if (ftype == Types.STRUCT) {
2820
                        if (fldname.compareToIgnoreCase(geoname) != 0) {
2821
                                return true;
2822
                        }
2823
                }
2824
                return false;
2825
        }
2826

    
2827
        public static String getRowDeleteSql(
2828
                        DBLayerDefinition dbLayerDef, String id) {
2829

    
2830
                String resp = "DELETE FROM \"" + dbLayerDef.getTableName() + "\"";
2831
                resp = resp + " WHERE ROWID ='" + id + "'";
2832
                return resp;
2833
        }
2834
        
2835
        
2836

    
2837
        private static String cropStringValue(String orig_val, int i,
2838
                        FieldDescription[] _flds) {
2839

    
2840
                if (orig_val == null) {
2841
                        return "NULL";
2842
                }
2843

    
2844
                int tpe = _flds[i].getFieldType();
2845
                int max_size = maxSizeForFieldType(tpe);
2846

    
2847
                if (max_size == -1) {
2848
                        return orig_val;
2849
                }
2850

    
2851
                int or_size = orig_val.length();
2852
                if (or_size <= max_size) {
2853
                        return orig_val;
2854
                }
2855
                return orig_val.substring(0, max_size);
2856
        }
2857

    
2858
        private static String avoidQuoteProblem(String str) {
2859
                return str.replaceAll("'", "''");
2860
        }
2861

    
2862
        private static String getValueSurroundFromType(int type) {
2863
                if (fieldTypeToSqlStringType(type).indexOf("NUMBER") != -1) {
2864
                        return "";
2865
                }
2866
                return "'";
2867
        }
2868

    
2869
        public static String epsgSridToOracleSrid(String epsg) {
2870

    
2871
                String resp = "8307";
2872
                // --------------------------------------------
2873
                String sql = "select ORACLE from " + ORACLE_EPSG_TABLE_NAME
2874
                                + " where EPSG = " + epsg + " and PRF_ORACLE = 1;";
2875
                DataSource ds = null;
2876
                Value[] res = null;
2877
                try {
2878
                        ds = LayerFactory.getDataSourceFactory().executeSQL(sql,
2879
                                        DataSourceFactory.AUTOMATIC_OPENING); //.MANUAL_OPENING);
2880

    
2881
                        if (ds.getRowCount() == 0) {
2882
                                logger
2883
                                                .error("DBF file is wrong: EPSG code not found in table: "
2884
                                                                + epsg);
2885
                                logger.error("Returned: 8307");
2886
                                return resp;
2887
                        }
2888

    
2889
                        if (ds.getRowCount() > 1) {
2890
                                logger.error("===============");
2891
                                logger
2892
                                                .error("DBF file is wrong: More than one preferred Oracle Spatial code found for EPSG code: "
2893
                                                                + epsg);
2894
                                for (int i = 0; i < ds.getRowCount(); i++) {
2895
                                        int aux = (int) Math.round(((DoubleValue) ds.getRow(i)[0])
2896
                                                        .doubleValue());
2897
                                        if (i == 0) {
2898
                                                resp = "" + aux;
2899
                                        }
2900
                                        logger.error("" + aux);
2901
                                }
2902
                                logger.error("===============");
2903
                                return resp;
2904

    
2905
                        }
2906

    
2907
                        resp = ""
2908
                                        + Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2909
                } catch (Exception pe) {
2910
                        logger.error("Error with SQL statement. " + pe.getMessage());
2911
                }
2912
                return resp;
2913

    
2914
                /*
2915
                 if (epsg.compareToIgnoreCase("23030") == 0) {
2916
                 return 82337; 
2917
                 }
2918
                 return 8307;
2919
                 */
2920
        }
2921

    
2922
        public static String oracleSridToEpsgSrid(String ora) {
2923
                String resp = "4326";
2924
                // --------------------------------------------
2925
                String sql = "select EPSG from " + ORACLE_EPSG_TABLE_NAME
2926
                                + " where ORACLE = " + ora + ";";
2927
                DataSource ds = null;
2928
                Value[] res = null;
2929
                try {
2930
                        ds = LayerFactory.getDataSourceFactory().executeSQL(sql,
2931
                                        DataSourceFactory.MANUAL_OPENING);
2932

    
2933
                        if (ds.getRowCount() == 0) {
2934
                                logger
2935
                                                .error("DBF file is wrong: Oracle Spatial code not found in table: "
2936
                                                                + ora);
2937
                                logger.error("Returned: 4326");
2938
                                return resp;
2939
                        }
2940

    
2941
                        if (ds.getRowCount() > 1) {
2942
                                logger.error("===============");
2943
                                logger
2944
                                                .error("DBF file is wrong: More than one EPSG code found for Oracle Spatial code: "
2945
                                                                + ora);
2946
                                for (int i = 0; i < ds.getRowCount(); i++) {
2947
                                        String aux = ""
2948
                                                        + Math.round(((DoubleValue) ds.getRow(i)[0])
2949
                                                                        .doubleValue());
2950
                                        if (i == 0) {
2951
                                                resp = aux;
2952
                                        }
2953
                                        logger.error("" + aux);
2954
                                }
2955
                                logger.error("===============");
2956
                                return resp;
2957
                        }
2958

    
2959
                        resp = ""
2960
                                        + Math.round(((DoubleValue) ds.getRow(0)[0]).doubleValue());
2961
                } catch (Exception pe) {
2962
                        logger.error("Error with SQL statement. " + pe.getMessage());
2963
                }
2964
                return resp;
2965
        }
2966

    
2967
        public static void createOracleEpsgTable() {
2968

    
2969
                SourceInfo si = LayerFactory.getDataSourceFactory().getDriverInfo(
2970
                                ORACLE_EPSG_TABLE_NAME);
2971
                if (si != null) { // already created, nothing done
2972
                        return;
2973
                }
2974
                // Create 'oracle codes - epsg codes' table
2975
                DBFDriver dbfdrv = new DBFDriver(); 
2976
                // dbfdrv.setDataSourceFactory()
2977
                OFileDataSourceAdapter fdsa = new OFileDataSourceAdapter();
2978
                
2979
                fdsa.setDriver(dbfdrv);
2980

    
2981
                // ---------------------------------------------
2982
                FileSourceInfo fsi = new FileSourceInfo();
2983
                fsi.file = createFileString("dbf/" + ORACLE_EPSG_FILE_NAME);
2984
                fsi.spatial = false;
2985
                fsi.name = ORACLE_EPSG_TABLE_NAME;
2986
                fsi.driverName = dbfdrv.getName(); //"DBF Driver";
2987
                // ---------------------------------------------
2988

    
2989
                fdsa.setSourceInfo(fsi);
2990
                SelectableDataSource sds = null;
2991
                EditableAdapter ea = new EditableAdapter();
2992
                ProjectTable pt = null;
2993

    
2994
                try {
2995
                        sds = new SelectableDataSource(fdsa);
2996
                        ea.setOriginalDataSource(sds);
2997
                        pt = ProjectTableFactory.createTable(ORACLE_EPSG_TABLE_NAME, ea);
2998
                } catch (Exception ex) {
2999
                        System.err.println("While creating datasource: " + ex.getMessage());
3000
                }
3001

    
3002
                sds.setSourceInfo(fsi);
3003
                DataSourceFactory dsf = LayerFactory.getDataSourceFactory();
3004
                dsf.addFileDataSource(fsi.driverName, fsi.name, fsi.file);
3005
                sds.setDataSourceFactory(dsf);
3006

    
3007
                // LayerFactory.getDataSourceFactory();
3008

    
3009
                // return pt;
3010
        }
3011

    
3012
        private static String createFileString(String path) {
3013

    
3014
                try {
3015
                        File f = new File(
3016
                                        "./gvSIG/extensiones/com.iver.cit.gvsig.jdbc_spatial/"
3017
                                                        + path);
3018
//                        f = new File("./"+ path);
3019
                        
3020
                        return f.getCanonicalPath();
3021
                } catch (Exception ex) {
3022
                        return "./gvSIG/extensiones/com.iver.cit.gvsig.jdbc_spatial/"
3023
                                        + path;
3024
                }
3025
        }
3026

    
3027
        /*
3028
        public void declareTablee(ProjectTable _pt) {
3029
                ProjectExtension pe = (ProjectExtension) PluginServices
3030
                                .getExtension(ProjectExtension.class);
3031
                _pt.setProjectDocumentFactory(new ProjectTableFactory());
3032
                pe.getProject().addDocument(_pt);
3033
        }
3034
        */
3035

    
3036
        public static String getValidOracleID(String str, int ind) {
3037
                if (str.length() <= MAX_ID_LENGTH) {
3038
                        return str;
3039
                }
3040
                String resp = str.substring(0, MAX_ID_LENGTH - 7);
3041
                resp = resp + str.substring(MAX_ID_LENGTH - 6, MAX_ID_LENGTH - 5);
3042
                resp = resp + str.substring(MAX_ID_LENGTH - 4, MAX_ID_LENGTH - 3);
3043
                resp = resp + str.substring(MAX_ID_LENGTH - 2, MAX_ID_LENGTH - 1);
3044
                resp = resp + "_" + (ind % 1000);
3045
                return resp;
3046
        }
3047

    
3048
        private static ArrayList ensureSensibleShell(ArrayList cc) {
3049
                if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(cc
3050
                                .size() - 1))) {
3051
                        if (cc.size() == 2) {
3052
                                ArrayList resp = new ArrayList();
3053
                                resp.add(cc.get(0));
3054

    
3055
                                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3056
                                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3057
                                resp.add(newcoo);
3058

    
3059
                                newcoo = new Coordinate((Coordinate) cc.get(0));
3060
                                newcoo.x = newcoo.x + IRRELEVANT_DISTANCE;
3061
                                newcoo.y = newcoo.y - IRRELEVANT_DISTANCE;
3062
                                resp.add(newcoo);
3063

    
3064
                                resp.add(cc.get(0));
3065
                                return resp;
3066
                        }
3067
                        if (cc.size() == 3) {
3068
                                cc.remove(1);
3069
                                return ensureSensibleShell(cc);
3070
                        }
3071
                        return cc;
3072
                } else {
3073
                        cc.add(cc.get(0));
3074
                        return cc;
3075
                }
3076
        }
3077

    
3078
        private static ArrayList ensureSensibleHole(ArrayList cc) {
3079
                if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(cc
3080
                                .size() - 1))) {
3081
                        if (cc.size() == 2) {
3082
                                ArrayList resp = new ArrayList();
3083
                                resp.add(cc.get(0));
3084

    
3085
                                Coordinate newcoo = new Coordinate((Coordinate) cc.get(0));
3086
                                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3087
                                resp.add(newcoo);
3088

    
3089
                                newcoo = new Coordinate((Coordinate) cc.get(0));
3090
                                newcoo.x = newcoo.x - IRRELEVANT_DISTANCE;
3091
                                newcoo.y = newcoo.y + IRRELEVANT_DISTANCE;
3092
                                resp.add(newcoo);
3093

    
3094
                                resp.add(cc.get(0));
3095
                                return resp;
3096
                        }
3097
                        if (cc.size() == 3) {
3098
                                cc.remove(1);
3099
                                return ensureSensibleHole(cc);
3100
                        }
3101
                        return cc;
3102
                } else {
3103
                        cc.add(cc.get(0));
3104
                        return cc;
3105
                }
3106
        }
3107

    
3108
        private static ArrayList ensureSensibleLineString(ArrayList cc) {
3109
                if (cc.size() == 2) {
3110
                        if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(cc
3111
                                        .size() - 1))) {
3112
                                ArrayList resp = new ArrayList();
3113
                                resp.add(cc.get(0));
3114
                                Coordinate newc = new Coordinate((Coordinate) cc.get(0));
3115
                                newc.x = newc.x + IRRELEVANT_DISTANCE;
3116
                                resp.add(newc);
3117
                                return resp;
3118
                        }
3119
                }
3120
                return cc;
3121
        }
3122
        
3123
        private static boolean sameCoordinate(Coordinate c1, Coordinate c2) {
3124
                if (c1.x != c2.x) {
3125
                        return false;
3126
                }
3127
                if (c1.y != c2.y) {
3128
                        return false;
3129
                }
3130
                return true;
3131
        }
3132

    
3133
        
3134

    
3135
        private static ArrayList getClosedRelevantPolygon(ArrayList cc) {
3136
                if (cc.size() == 2) {
3137
                        return null;
3138
                }
3139
                if (cc.size() == 3) {
3140
                        if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(1)))
3141
                                return null;
3142
                        if (sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(2)))
3143
                                return null;
3144
                        if (sameCoordinate((Coordinate) cc.get(1), (Coordinate) cc.get(2)))
3145
                                return null;
3146
                        cc.add(cc.get(0));
3147
                        return cc;
3148
                }
3149
                if (!sameCoordinate((Coordinate) cc.get(0), (Coordinate) cc.get(cc
3150
                                .size() - 1))) {
3151
                        cc.add(cc.get(0));
3152
                }
3153
                return cc;
3154
        }
3155

    
3156
        private static MultiPolygon getMinMultiPolygon(Coordinate c) {
3157
                Coordinate[] p = new Coordinate[4];
3158
                p[0] = c;
3159
                Coordinate nc = new Coordinate(c);
3160
                nc.x = nc.x + IRRELEVANT_DISTANCE;
3161
                Coordinate nc2 = new Coordinate(nc);
3162
                nc2.y = nc2.y - IRRELEVANT_DISTANCE;
3163
                p[1] = nc;
3164
                p[2] = nc2;
3165
                p[3] = new Coordinate(c);
3166
                CoordinateArraySequence cs = new CoordinateArraySequence(p);
3167
                LinearRing ls = new LinearRing(cs, geomFactory);
3168
                Polygon po = new Polygon(ls, null, geomFactory);
3169
                Polygon[] pos = new Polygon[1];
3170
                pos[0] = po;
3171
                MultiPolygon mpo = new MultiPolygon(pos, geomFactory);
3172
                return mpo;
3173
        }
3174

    
3175
        public String getSourceProjection() {
3176
                // TODO Auto-generated method stub
3177
                if (tableHasSrid) {
3178
                        return epsgSRID;
3179
                }
3180
                return destProj;
3181
        }
3182

    
3183
        public String getDestProjection() {
3184
                return destProj;
3185
        }
3186

    
3187
        public void setDestProjection(String toEPSG) {
3188
                destProj = toEPSG;
3189
        }
3190

    
3191
        public boolean canReproject(String toEPSGdestinyProjection) {
3192
                return false;
3193
        }
3194

    
3195
        private static boolean isOracleAllowedFieldname(String str) {
3196
                if (str.compareToIgnoreCase("rowid") == 0) {
3197
                        return false;
3198
                }
3199
                if (str.compareToIgnoreCase("rownum") == 0) {
3200
                        return false;
3201
                }
3202
                return true;
3203
        }
3204

    
3205
        public STRUCT getOriginalOracleWAStruct() {
3206
                return originalOracleWAStruct;
3207
        }
3208
        
3209
        public Hashtable getHashRelate() {
3210
                return hashRelate;
3211
        }
3212
        
3213
        public void setHashRelate(Hashtable m) {
3214
                hashRelate = m;
3215
        }
3216
        
3217
        public void setNumReg(int n) {
3218
                numReg = n;
3219
        }
3220
        
3221
        private int[] getRandomSample(int maxn_one_based, int n) {
3222
                
3223
                int[] resp = new int[n];
3224
                
3225
                if (maxn_one_based <= n) {
3226
                        resp = new int[maxn_one_based];
3227
                        for (int i=0; i<maxn_one_based; i++) {
3228
                                resp[i] = i;
3229
                        }
3230
                } else {
3231
                        Random rnd = new Random();
3232
                        for (int i=0; i<n; i++) {
3233
                                resp[i] = rnd.nextInt(maxn_one_based);
3234
                        }
3235
                }
3236
                return resp;
3237
        }
3238
        
3239
        private String getRowIdRestrictionCondition(int nrecords) {
3240
                
3241
                /*
3242
                if (isNotAvailableYet) {
3243
                        return nullSampleSqlCondition;
3244
                }
3245
                */
3246
                
3247
                int[] zero_based_rows = getRandomSample(nrecords, GEODETIC_FULLEXTENT_SAMPLE_SIZE);
3248
                String resp = "(";
3249
                Object aux = "";
3250
                ROWID riaux = null;
3251
                for (int i=0; i<zero_based_rows.length; i++) {
3252
                        aux = rowToId.get(new Integer(zero_based_rows[i]));
3253
                        riaux = (ROWID) aux;
3254
                        resp = resp + "(ROWID = '" + riaux.stringValue() + "') OR ";
3255
                }
3256
                resp = resp.substring(0, resp.length() - 4);
3257
                resp = resp + ")";
3258
                return resp;
3259
        }
3260
        
3261
        private Rectangle2D getBoundingFromSample(int n_max) {
3262
                // SELECT column FROM ( SELECT column FROM table
3263
                // ORDER BY dbms_random.value ) WHERE rownum = 1
3264
                String _qry = "SELECT " + geoColName + " FROM " + getTableName() + " WHERE " +
3265
                getRowIdRestrictionCondition(n_max);
3266
                STRUCT auxstr = null;
3267
                IGeometry theGeom = null;
3268
                Rectangle2D resp = null;
3269

    
3270
                try {
3271
                        Statement st = conn.createStatement();
3272
                        ResultSet rs = st.executeQuery(_qry);
3273

    
3274
                        if (rs.next()) {
3275
                                auxstr = (STRUCT) rs.getObject(1);
3276
                                if (auxstr != null) {
3277
                                        theGeom = getGeometryUsing(auxstr, use_geotools);
3278
                                        if (resp == null) {
3279
                                                resp = theGeom.getBounds2D();
3280
                                        } else {
3281
                                                resp.add(theGeom.getBounds2D());
3282
                                        }
3283
                                }
3284
                                while (rs.next()) {
3285
                                        auxstr = (STRUCT) rs.getObject(1);
3286
                                        if (auxstr != null) {
3287
                                                theGeom = getGeometryUsing(auxstr, use_geotools);
3288
                                                if (resp == null) {
3289
                                                        resp = theGeom.getBounds2D();
3290
                                                } else {
3291
                                                        resp.add(theGeom.getBounds2D());
3292
                                                }
3293
                                        }
3294
                                }
3295
                                rs.close();
3296
                                st.close();
3297
                        } else {
3298
                                throw new SQLException("Empty resultset from this query: " + _qry);
3299
                        }
3300
                } catch (SQLException se) {
3301
                        System.err.println("Error while getting sample full extent: "
3302
                                        + se.getMessage());
3303
                }
3304
                if (resp == null) {
3305
                        logger.warn("Did not find a geometry to compute sample bbox. Returned geographic bbox for whole world.");
3306
                        return new Rectangle2D.Double(-180, -90, 360, 180);
3307
                }
3308
                return resp;
3309
        }
3310
        
3311
        /** Does what it says, reverses the order of the Coordinates in the ring.
3312
      * @param lr The ring to reverse.
3313
      * @return A new ring with the reversed Coordinates.
3314
      */  
3315
        public static LinearRing putInCCWOrderLR(LineString ls, GeometryFactory gf) {
3316
                
3317
                Coordinate[] cc = ls.getCoordinates();
3318
                if (CGAlgorithms.isCCW(cc)) {
3319
                        return gf.createLinearRing(cc);
3320
                } else {
3321
                        if (ls instanceof LinearRing) {
3322
                                return reverseRing((LinearRing) ls, gf);
3323
                        } else {
3324
                                return reverseLineString(ls, gf);
3325
                        }
3326
                }
3327
                
3328
        }
3329
        public static LinearRing reverseRing(LinearRing lr, GeometryFactory gf) {
3330
                int numPoints = lr.getNumPoints() - 1;
3331
                Coordinate[] newCoords = new Coordinate[numPoints + 1];
3332
                
3333
                for(int t = numPoints; t >= 0; t--) {
3334
                        newCoords[t] = lr.getCoordinateN(numPoints - t);
3335
                }
3336
                return gf.createLinearRing(newCoords);
3337
        }
3338
        
3339
        public static LinearRing reverseLineString(LineString ls, GeometryFactory gf) {
3340
                int numPoints = ls.getNumPoints() - 1;
3341
                Coordinate[] newCoords = new Coordinate[numPoints + 1];
3342
                
3343
                for(int t = numPoints; t >= 0; t--) {
3344
                        newCoords[t] = ls.getCoordinateN(numPoints - t);
3345
                }
3346
                return gf.createLinearRing(newCoords);
3347
        }
3348
        
3349
        private static Geometry putInCCWOrder(Geometry ge, GeometryFactory gf) {
3350
                if (ge instanceof MultiPolygon) {
3351
                        MultiPolygon mp = (MultiPolygon) ge;
3352
                        int size = ge.getNumGeometries();
3353
                        Polygon[] pols = new Polygon[size];
3354
                        for (int i=0; i<size; i++)
3355
                                pols[i] = (Polygon) putInCCWOrder((Polygon) mp.getGeometryN(i), gf);
3356
                        return new MultiPolygon(pols, gf);
3357
                } else {
3358
                        if (ge instanceof Polygon) {
3359
                                Polygon p = (Polygon) ge;
3360
                                LinearRing exterior = putInCCWOrderLR(p.getExteriorRing(), gf);
3361
                                int nholes = p.getNumInteriorRing();
3362
                                if (nholes > 0) {
3363
                                        LinearRing[] holes = new LinearRing[nholes];
3364
                                        for (int i=0; i<nholes; i++) {
3365
                                                holes[i] = putInCCWOrderLR(p.getInteriorRingN(i), gf);
3366
                                        }
3367
                                        return gf.createPolygon(exterior, holes);
3368
                                } else {
3369
                                        return gf.createPolygon(exterior, null);
3370
                                }
3371
                        } else {
3372
                                return ge;
3373
                        }
3374
                }
3375
        }
3376
        
3377
        
3378
        public static STRUCT iGeometryToSTRUCT(IGeometry ig, int _forced_type,
3379
                        Connection _conn, String _o_srid, boolean withSrid,
3380
                        boolean agu_bien, boolean _isGeoCS) {
3381

    
3382
                if (ig instanceof FGeometryCollection) {
3383
                        
3384
                        FGeometryCollection coll = (FGeometryCollection) ig;
3385
                        return OracleSpatialUtils.appendGeometriesInStruct(coll, _forced_type,
3386
                                        _conn, _o_srid, withSrid, agu_bien, _isGeoCS);
3387
                        // logger.error("Collections no soportadas por ahora.");
3388
                        // return null;
3389
                        
3390
                } else {
3391
                        
3392
                        Shape shp = ig.getInternalShape();
3393
                        return shapeToStruct(shp, _forced_type, _conn,
3394
                                        _o_srid, withSrid, agu_bien, false, _isGeoCS);
3395
                        
3396
                }
3397
        }
3398
        
3399
        public STRUCT shapeToStruct(Shape shp, int force_type,
3400
                        boolean hasSrid, boolean agu_bien, boolean isView) {
3401
                
3402
                return shapeToStruct(shp, force_type, conn, oracleSRID, hasSrid, agu_bien, isView, isGeogCS);
3403
        }
3404

    
3405
        public static STRUCT shapeToStruct(Shape shp, int forced_type, Connection _conn,
3406
                        String o_srid, boolean hasSrid, boolean agu_bien, boolean isView, boolean _isGeoCS) {
3407
                
3408
                int _srid = -1;
3409
                if (o_srid.length() > 0) {
3410
                        _srid = Integer.parseInt(o_srid);
3411
                }
3412

    
3413
                if (shp == null) {
3414
                        logger.info("Shape is null. shapeToStruct(Shape) returned null.");
3415
                        return null;
3416
                }
3417

    
3418
                if (shp instanceof Rectangle2D) {
3419
                        return rectangleToStruct((Rectangle2D) shp, hasSrid, isView,
3420
                                        _isGeoCS, o_srid, _conn);
3421
                }
3422
                
3423
                try {
3424
                        STRUCT the_struct =
3425
                                OracleSpatialUtils.fShapeToSTRUCT(shp, _conn, _srid, agu_bien, hasSrid);
3426
                        return the_struct;
3427
                } catch (SQLException ex) {
3428
                        logger.error("While creating STRUCT: " + ex.getMessage());
3429
                        return null;
3430
                }
3431
                
3432
                
3433
                // logger.info("wa_wktext = " + wa_wktext);
3434

    
3435
                /*
3436
                int type = FShape.POLYGON;
3437
                if ((shp instanceof FPolyline2D) && (!(shp instanceof FPolygon2D)))
3438
                        type = FShape.LINE;
3439
                if (shp instanceof FPoint2D)
3440
                        type = FShape.POINT;
3441
                if (shp instanceof FMultiPoint2D)
3442
                        type = FShape.MULTIPOINT;
3443

3444
                if (forced_type != FShape.NULL) {
3445
                        type = forced_type;
3446
                }
3447

3448
                WKTWriter wktw = new WKTWriter();
3449
                GeneralPathX wagp = new GeneralPathX(shp);
3450
                
3451
                FShape fshp = null;
3452
                
3453
                if (type == FShape.LINE) {
3454
                        fshp = new FPolyline2D(wagp);
3455
                } else {
3456
                        if (type == FShape.POLYGON) {
3457
                                fshp = new FPolygon2D(wagp);
3458
                        } else {
3459
                                fshp = new FShapeGeneralPathX(wagp, type);
3460
                        }
3461
                }
3462

3463
                Geometry jts_g = OracleSpatialDriver.java2d_to_jts(fshp);
3464
                jts_g = putInCCWOrder(jts_g, geomFactory);
3465

3466
                String wa_wktext = "";
3467

3468
                try {
3469
                        // This faisl sometimes:
3470
                        wa_wktext = wktw.write(jts_g);
3471
                } catch (Exception ex) {
3472
                        System.err.println("Error while getting WKT: " + ex.getMessage());
3473
                        return null;
3474
                }
3475

3476
                */
3477
                // WKT struct_creator = new WKT();
3478
                /*
3479
                try {
3480
                        STRUCT resp = struct_creator.toSTRUCT(wa_wktext.getBytes(), _conn);
3481
                        Object[] old_obj = resp.getAttributes();
3482
                        int size = old_obj.length;
3483
                        Object[] new_obj = new Object[size];
3484
                        for (int i = 0; i < size; i++)
3485
                                new_obj[i] = old_obj[i];
3486

3487
                        if (assumedSrid) {
3488
                                new_obj[1] = null;
3489
                        } else {
3490
                                new_obj[1] = new BigDecimal(o_srid);
3491
                        }
3492

3493
                        resp = new STRUCT(resp.getDescriptor(), _conn, new_obj);
3494
                        return resp;
3495
                } catch (Exception e) {
3496
                        System.err.println("Error in shapeToStruct(Shape): "
3497
                                        + e.getMessage());
3498
                        return null;
3499
                }
3500
                */
3501
        }
3502
        
3503
        // -------------------------- not ready yet ----------------
3504
        
3505
        public int getRowIndexByFID(IFeature _fid) {
3506
                if (isNotAvailableYet) {
3507
                        return -1;
3508
                } else {
3509
                        return super.getRowIndexByFID(_fid);
3510
                }
3511
        }
3512
        
3513
        public int getShapeCount() throws IOException {
3514
                if (isNotAvailableYet) {
3515
                        return 0;
3516
                } else {
3517
                        return numReg;
3518
                }
3519
        }
3520

    
3521
        public void setNotAvailableYet(boolean nav) {
3522
                isNotAvailableYet = nav;
3523
                
3524
        }
3525
        
3526
        // -------------------------------------------------------
3527
        // -------------------------------------------------------
3528
        // -------------------------------------------------------
3529
        
3530
    public String[] getTableNames(Connection conn, String catalog) throws SQLException {
3531
            
3532
            DatabaseMetaData dbmd = conn.getMetaData();
3533
        String[] types = {"TABLE", "VIEW"};
3534

    
3535
        ResultSet rs = null;
3536
        rs = getTableNamesFromTable(dbmd.getTables(
3537
                        catalog, ORACLE_GEO_SCHEMA, ORACLE_GEOMETADATA_VIEW, types), conn);                
3538

    
3539
                TreeMap ret = new TreeMap();
3540
                while (rs.next()){
3541
                        ret.put(rs.getString("TABLE_NAME"), rs.getString("TABLE_NAME"));
3542
                }
3543
                        
3544
                return (String[]) ret.keySet().toArray(new String[0]);
3545
    }
3546
    
3547
        private ResultSet getTableNamesFromTable(ResultSet res, Connection con) throws SQLException {
3548
                String tablename = "";
3549
                if (res.next()) {
3550
                        tablename = res.getString("TABLE_NAME"); 
3551
                        Statement st = con.createStatement();
3552
                        
3553
                        String sql = "("
3554
                                + "(select TABLE_NAME from USER_TABLES) "
3555
                                + "union (select VIEW_NAME from USER_VIEWS)) "
3556
                                + "intersect (select TABLE_NAME from " + tablename + ")";
3557
                        ResultSet rs = st.executeQuery(sql);
3558
                        // --------------------------
3559
                        // String geo_col = getGeometryFieldName(tablename, rs);
3560
                        // --------------------------
3561
                        return rs;
3562
                } else {
3563
                        System.err.println("Error while getting geometric tables.");
3564
                        return null;
3565
                }
3566
        }
3567
        
3568
    public String[] getIdFieldsCandidates(Connection conn, String table_name) throws SQLException {
3569
            String[] resp = { "ROWID" };
3570
            return resp;
3571
    }
3572
    
3573
    public String[] getGeometryFieldsCandidates(Connection conn, String table_name) throws SQLException {
3574
            
3575
                Statement _st = conn.createStatement();
3576
                String qry = "select * from " + ORACLE_GEOMETADATA_VIEW
3577
                                + " where TABLE_NAME = " + "'" + table_name + "'";
3578
                ResultSet _rs = _st.executeQuery(qry);
3579
                
3580
                ArrayList aux = new ArrayList();
3581

    
3582
                while (_rs.next()) {
3583
                        String _geo = _rs.getString("COLUMN_NAME");
3584
                        aux.add(_geo);
3585
                }
3586
                _rs.close(); _st.close();
3587
            return (String[]) aux.toArray(new String[0]);
3588
    }
3589
    
3590
        public boolean isEmptyTable(Connection conn, String tableName) {
3591
                
3592
                boolean res = true;
3593

    
3594
                try {
3595
                        Statement st = conn.createStatement();
3596
                        ResultSet rs = null;
3597
                        rs = st.executeQuery("select * from " + tableName + " where rownum = 1");
3598
                        res = !rs.next();
3599
                        rs.close(); st.close();
3600
                } catch (Exception ex) {
3601
                        res = true;
3602
                }
3603
                return res;
3604
        }
3605
        
3606
    public String[] getAllFields(Connection conn, String table_name) throws SQLException {
3607
            
3608
                Statement st = conn.createStatement();
3609
                ResultSet rs = st.executeQuery("select * from " + table_name + " where rownum = 1");
3610
                ResultSetMetaData rsmd = rs.getMetaData();
3611
                String[] ret = new String[rsmd.getColumnCount()];
3612

    
3613
                for (int i = 0; i < ret.length; i++) {
3614
                        ret[i] = rsmd.getColumnName(i+1);
3615
                }
3616
                rs.close(); st.close();
3617
                return ret;
3618
    }
3619
    
3620
    public String[] getAllFieldTypeNames(Connection conn, String table_name) throws SQLException {
3621
            
3622
                Statement st = conn.createStatement();
3623
                ResultSet rs = st.executeQuery("select * from " + table_name + " where rownum = 1");
3624
                ResultSetMetaData rsmd = rs.getMetaData();
3625
                String[] ret = new String[rsmd.getColumnCount()];
3626

    
3627
                for (int i = 0; i < ret.length; i++) {
3628
                        ret[i] = rsmd.getColumnTypeName(i+1);
3629
                }
3630
                rs.close(); st.close();
3631
                
3632
                close();
3633
                return ret;
3634
    }
3635
    
3636
        
3637
        
3638

    
3639
        
3640
        public String getConnectionString(String host,
3641
                    String port,
3642
                    String dbname,
3643
                    String user,
3644
                    String pw) {
3645

    
3646
                String _pw = pw;
3647
                if (_pw == null) _pw = "null";
3648

    
3649
                        String fullstr = CONN_STR_BEGIN;
3650
                        fullstr = fullstr + user.toLowerCase() + "/" + _pw;
3651
                        fullstr = fullstr + "@" + host.toLowerCase();
3652
                        fullstr = fullstr + ":" + port;
3653
                        fullstr = fullstr + ":" + dbname.toLowerCase();
3654
                        return fullstr;
3655
        }
3656

    
3657
        public IWriter getWriter() {
3658
                
3659
                // on(VectorialEditableDBAdapter.java:290)
3660
                if (writer == null) {
3661

    
3662
                        writer = new OracleSpatialWriter(getRowCount());
3663
                        writer.setDriver(this);
3664
                        writer.setLyrShapeType(getShapeType());
3665
                        writer.setGeoCS(isGeogCS());
3666
                        writer.setGeoColName(geoColName);
3667
                        writer.setSRID(oracleSRID);
3668
                        
3669
                        try {
3670
                                writer.initialize(getLyrDef());
3671
                        } catch (EditionException e) {
3672
                                logger.error("While initializing OS Writer: " + e.getMessage(), e);
3673
                        }
3674
                        writer.setStoreWithSrid(tableHasSrid);
3675
                }
3676
                return writer;
3677
        }
3678

    
3679
        public boolean isGeogCS() {
3680
                return isGeogCS;
3681
        }
3682
        
3683
        public void addRow(String id) {
3684

    
3685
                Value aux = ValueFactory.createValue(id);
3686
                Integer intobj = new Integer(numReg);
3687
                hashRelate.put(aux, intobj);
3688
                rowToId.put(intobj, id);
3689
                
3690
                numReg++;
3691
        }
3692
        
3693
        public void deleteRow(String id) {
3694
                
3695
                Value aux = ValueFactory.createValue(id);
3696
                Integer intobj = (Integer) hashRelate.get(aux);
3697
                hashRelate.remove(aux);
3698
                rowToId.remove(intobj);
3699
                
3700
                numReg--;
3701
        }
3702
        
3703
        private String getStandardSelectExpression() {
3704
                if (standardSelectExpressionFalse  == null) {
3705
                        standardSelectExpressionFalse = "";
3706
                        String[] flds = getLyrDef().getFieldNames();
3707
                        int size = flds.length;
3708
                        for (int i=0; i<size; i++) {
3709
                                if (i > 0) {
3710
                                        standardSelectExpressionFalse = standardSelectExpressionFalse + "c.\"" + flds[i] + "\", ";
3711
                                } else {
3712
                                        standardSelectExpressionFalse = standardSelectExpressionFalse + flds[i] + ", ";
3713
                                }
3714
                        }
3715
                        // standardSelectExpressionFalse = standardSelectExpressionFalse + "c." + geoColName;
3716
                        standardSelectExpressionFalse = standardSelectExpressionFalse.substring(0,
3717
                                        standardSelectExpressionFalse.length() - 2);
3718
                }
3719
                return standardSelectExpressionFalse;
3720
        }
3721
        
3722
        public String[] manageGeometryField(String[] flds, String geof) {
3723
                return addEndIfNotContained(flds, geof);
3724
        }
3725
        
3726
        public String[] manageIdField(String[] flds, String idf) {
3727
                return addStartIfNotContained(flds, idf);
3728
        }
3729
        
3730
        private String[] addEndIfNotContained(String[] arr, String item) {
3731
                if (contains(arr, item)) {
3732
                        return arr;
3733
                } else {
3734
                        int size = arr.length;
3735
                        String[] resp = new String[size + 1];
3736
                        for (int i=0; i<size; i++) {
3737
                                resp[i] = arr[i];
3738
                        }
3739
                        resp[size] = item;
3740
                        return resp;
3741
                }
3742
        }
3743
        
3744
        private String[] addStartIfNotContained(String[] arr, String item) {
3745
                if (contains(arr, item)) {
3746
                        return arr;
3747
                } else {
3748
                        int size = arr.length;
3749
                        String[] resp = new String[size + 1];
3750
                        for (int i=1; i<=size; i++) {
3751
                                resp[i] = arr[i];
3752
                        }
3753
                        resp[0] = item;
3754
                        return resp;
3755
                }
3756
        }
3757
        
3758
        private boolean contains(String[] arr, String item) {
3759
                for (int i=0; i<arr.length; i++) {
3760
                        if (arr[i].compareTo(item) == 0) {
3761
                                return true;
3762
                        }
3763
                }
3764
                return false;
3765
        }
3766
        
3767
        public void remove() {
3768
                cancelIDLoad = true;
3769
        }
3770
}