Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / feature / impl / DataTypeDetectorImpl.java

History | View | Annotate | Download (17.5 KB)

1 47206 jjdelcerro
package org.gvsig.fmap.dal.feature.impl;
2 43983 jjdelcerro
3 47206 jjdelcerro
import org.gvsig.fmap.dal.feature.DataTypeDetector;
4 44936 jjdelcerro
import java.math.BigDecimal;
5 43983 jjdelcerro
import java.net.URL;
6 47337 fdiaz
import java.sql.Date;
7
import java.sql.Time;
8
import java.sql.Timestamp;
9
import java.text.DateFormat;
10 47235 jjdelcerro
import java.text.DecimalFormat;
11
import java.text.NumberFormat;
12 47337 fdiaz
import java.text.ParseException;
13 47235 jjdelcerro
import java.text.ParsePosition;
14 47337 fdiaz
import java.text.SimpleDateFormat;
15 43983 jjdelcerro
import java.util.Locale;
16 45775 jjdelcerro
import org.apache.commons.lang3.StringUtils;
17 43983 jjdelcerro
import org.gvsig.fmap.dal.DataTypes;
18 47222 jjdelcerro
import org.gvsig.fmap.geom.Geometry;
19 45929 jjdelcerro
import org.gvsig.fmap.geom.GeometryCoercionContext;
20
import org.gvsig.fmap.geom.GeometryLocator;
21 47222 jjdelcerro
import org.gvsig.fmap.geom.GeometryManager;
22
import org.gvsig.fmap.geom.GeometryUtils;
23
import org.gvsig.fmap.geom.type.GeometryType;
24 43983 jjdelcerro
import org.gvsig.tools.ToolsLocator;
25
import org.gvsig.tools.dataTypes.DataTypesManager;
26 44669 jjdelcerro
import org.gvsig.tools.dataTypes.Coercion;
27
import org.gvsig.tools.dataTypes.CoercionContext;
28 47337 fdiaz
import org.gvsig.tools.dataTypes.CoercionContextLocale;
29 43983 jjdelcerro
30
/**
31
 *
32
 * @author jjdelcerro
33
 */
34 47206 jjdelcerro
@SuppressWarnings("UseSpecificCatch")
35
public class DataTypeDetectorImpl implements DataTypeDetector {
36 43983 jjdelcerro
37 47235 jjdelcerro
    private Locale locale;
38
39 47206 jjdelcerro
    private static class DataTypeDetectedImpl implements DataTypeDetected {
40 44455 omartinez
41 44936 jjdelcerro
        private int type;
42
        private int displaySize;
43 45129 jjdelcerro
        private int integerDigits;
44
        private int decimalDigits;
45 45775 jjdelcerro
        private boolean blank;
46 47222 jjdelcerro
        private GeometryType geomtype;
47 44936 jjdelcerro
48
        @Override
49
        public int getType() {
50
            return this.type;
51
        }
52
53
        @Override
54
        public int getDisplaySize() {
55
            return this.displaySize;
56
        }
57
58
        @Override
59
        public int getPrecision() {
60 45129 jjdelcerro
            return this.decimalDigits + this.integerDigits;
61 44936 jjdelcerro
        }
62
63
        @Override
64
        public int getScale() {
65 45129 jjdelcerro
            return this.decimalDigits;
66 44936 jjdelcerro
        }
67
68 47206 jjdelcerro
        @Override
69 45775 jjdelcerro
        public boolean isBlank() {
70
            return this.blank;
71
        }
72 47206 jjdelcerro
73
        @Override
74 47222 jjdelcerro
        public GeometryType getGeometryType() {
75
            return this.geomtype;
76
        }
77
78
        @Override
79 47206 jjdelcerro
        public void setDisplaySize(int size) {
80
            this.displaySize = size;
81
        }
82 44936 jjdelcerro
    }
83
84 43983 jjdelcerro
    private static class PossibleDataType {
85
86
        public boolean possibleInt = true;
87
        public boolean possibleFloat = true;
88
        public boolean possibleDouble = true;
89 44669 jjdelcerro
        public boolean possibleDecimal = true;
90 43983 jjdelcerro
        public boolean possibleLong = true;
91
        public boolean possibleURL = true;
92
        public boolean possibleDate = true;
93 45563 jolivas
        public boolean possibleTime = true;
94
        public boolean possibleTimestamp = true;
95 43983 jjdelcerro
        public boolean possibleGeometry = true;
96 47222 jjdelcerro
        private int possibleGeometrySubtype;
97
        private int possibleGeometryType;
98 43983 jjdelcerro
    }
99
100 47206 jjdelcerro
    private PossibleDataType possibleDataType;
101
    private DataTypeDetectedImpl detectedDataType;
102 47235 jjdelcerro
//    private Coercion toDecimal;
103 47337 fdiaz
//    private Coercion toDouble;
104
//    private Coercion toFloat;
105
//    private Coercion toDate;
106
//    private Coercion toTime;
107
//    private Coercion toTimestamp;
108 47206 jjdelcerro
//    private Coercion toInt;
109
//    private Coercion toLong;
110
    private Coercion toGeom;
111
    private CoercionContext coercionContext;
112
    private GeometryCoercionContext  geometryCoercionContext;
113
114
    public DataTypeDetectorImpl(Locale locale) {
115
        init(locale);
116 43983 jjdelcerro
    }
117 47206 jjdelcerro
118
    private void init(Locale locale) {
119
        if (locale == null) {
120
            locale = Locale.getDefault();
121
        }
122
        DataTypesManager typeManager = ToolsLocator.getDataTypesManager();
123 47337 fdiaz
        coercionContext = CoercionContextLocale.create(locale);
124
125 47235 jjdelcerro
//        toDecimal = typeManager.getCoercion(DataTypes.DECIMAL);
126 47337 fdiaz
//        toDouble = typeManager.getCoercion(DataTypes.DOUBLE);
127
//        toFloat = typeManager.getCoercion(DataTypes.FLOAT);
128
//        toDate = typeManager.getCoercion(DataTypes.DATE);
129
//        toTime = typeManager.getCoercion(DataTypes.TIME);
130
//        toTimestamp = typeManager.getCoercion(DataTypes.TIMESTAMP);
131 47206 jjdelcerro
//        toInt = typeManager.getCoercion(DataTypes.INT);
132
//        toLong = typeManager.getCoercion(DataTypes.LONG);
133
        toGeom = typeManager.getCoercion(DataTypes.GEOMETRY);
134 43983 jjdelcerro
135 47206 jjdelcerro
        geometryCoercionContext = GeometryLocator.getGeometryManager().createGeometryCoercionContext();
136
        geometryCoercionContext.setMode(GeometryCoercionContext.MODE_ONERROR_THROW);
137 47222 jjdelcerro
138
        detectedDataType = new DataTypeDetectedImpl();
139
        possibleDataType = new PossibleDataType();
140
        possibleDataType.possibleGeometryType = Geometry.TYPES.UNKNOWN;
141
        possibleDataType.possibleGeometrySubtype = Geometry.SUBTYPES.UNKNOWN;
142 47235 jjdelcerro
        this.locale = locale;
143 43983 jjdelcerro
    }
144 47206 jjdelcerro
145
    @SuppressWarnings("ResultOfObjectAllocationIgnored")
146
    @Override
147
    public void addValue(String rawvalue) {
148
        if( rawvalue == null ) {
149
           return;
150
        }
151 47222 jjdelcerro
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
152 43983 jjdelcerro
153 47206 jjdelcerro
        if( detectedDataType.blank ) {
154
            detectedDataType.blank = StringUtils.isBlank(rawvalue);
155 45929 jjdelcerro
        }
156 47206 jjdelcerro
        int displaySize = rawvalue.length();
157
        if( displaySize>detectedDataType.displaySize ) {
158
            detectedDataType.displaySize = displaySize;
159
        }
160 47235 jjdelcerro
        if( StringUtils.isNotBlank(rawvalue) ) {
161
            if (possibleDataType.possibleDecimal) {
162
                try {
163
                        BigDecimal decimal = this.toDecimal(rawvalue);
164
                        if( decimal==null ) {
165
                            possibleDataType.possibleDecimal = false;
166
                        } else {
167
                            if( decimal.scale() > detectedDataType.decimalDigits ) {
168
                                detectedDataType.decimalDigits = decimal.scale();
169
                            }
170
                            int integerDigits = decimal.precision() - decimal.scale();
171
                            if( integerDigits>detectedDataType.integerDigits ) {
172
                                detectedDataType.integerDigits = integerDigits;
173
                            }
174
                        }
175
                } catch (Exception ex) {
176
                    possibleDataType.possibleDecimal = false;
177 47206 jjdelcerro
                }
178 47235 jjdelcerro
            }
179
            if (possibleDataType.possibleDouble) {
180
                try {
181
                        Double num = toDouble(rawvalue);
182
                        possibleDataType.possibleDouble = (num!=null);
183
                } catch (Exception ex) {
184
                    possibleDataType.possibleDouble = false;
185 47206 jjdelcerro
                }
186 43983 jjdelcerro
            }
187 47235 jjdelcerro
            if (possibleDataType.possibleFloat) {
188
                try {
189
                        Float num = toFloat(rawvalue);
190
                        possibleDataType.possibleFloat = (num!=null);
191
                } catch (Exception ex) {
192
                    possibleDataType.possibleFloat = false;
193
                }
194 43983 jjdelcerro
            }
195 47235 jjdelcerro
            if (possibleDataType.possibleLong) {
196
                    possibleDataType.possibleLong = isValidLong(rawvalue);
197 43983 jjdelcerro
            }
198 47235 jjdelcerro
            if (possibleDataType.possibleInt) {
199
                possibleDataType.possibleInt = isValidInteger(rawvalue);
200 43983 jjdelcerro
            }
201 47235 jjdelcerro
            if (possibleDataType.possibleDate) {
202
                try {
203 47337 fdiaz
                    possibleDataType.possibleDate = (toDate(rawvalue) != null);
204 47235 jjdelcerro
                } catch (Exception ex) {
205
                    possibleDataType.possibleDate = false;
206
                }
207 45929 jjdelcerro
            }
208 47235 jjdelcerro
            if (possibleDataType.possibleTime) {
209
                try {
210 47337 fdiaz
                    possibleDataType.possibleTime = (toTime(rawvalue) != null);
211 47235 jjdelcerro
                } catch (Exception ex) {
212
                    possibleDataType.possibleTime = false;
213
                }
214 43983 jjdelcerro
            }
215 47235 jjdelcerro
            if (possibleDataType.possibleTimestamp) {
216
                try {
217 47337 fdiaz
                    possibleDataType.possibleTimestamp = (toTimestamp(rawvalue) != null);
218 47235 jjdelcerro
                } catch (Exception ex) {
219
                    possibleDataType.possibleTimestamp = false;
220
                }
221 47206 jjdelcerro
            }
222 47235 jjdelcerro
            if (possibleDataType.possibleURL) {
223
                try {
224
                    new URL((String) rawvalue);
225
                    possibleDataType.possibleURL = true;
226
                } catch (Exception ex) {
227
                    possibleDataType.possibleURL = false;
228
                }
229
            }
230 47206 jjdelcerro
231 47235 jjdelcerro
            if (possibleDataType.possibleGeometry) {
232
                try {
233
                    Geometry geom = (Geometry) toGeom.coerce((String) rawvalue, geometryCoercionContext);
234
                    if( geom==null ) {
235
                        possibleDataType.possibleGeometry = true;
236
                    } else {
237
                        possibleDataType.possibleGeometry = true;
238
                        if( possibleDataType.possibleGeometryType == Geometry.TYPES.UNKNOWN ) {
239
                            possibleDataType.possibleGeometryType = geom.getGeometryType().getType();
240
                        } else if( possibleDataType.possibleGeometryType != geom.getGeometryType().getType() ) {
241
                            // FIXME: habria que calcualar correctamente el geom-type, en funcion del actual y el ultimo.
242
                            possibleDataType.possibleGeometryType = Geometry.TYPES.GEOMETRY;
243
                        }
244
                        if( possibleDataType.possibleGeometrySubtype == Geometry.SUBTYPES.UNKNOWN ) {
245
                            possibleDataType.possibleGeometrySubtype = geom.getGeometryType().getSubType();
246
                        } else if( possibleDataType.possibleGeometrySubtype != geom.getGeometryType().getSubType()) {
247
                            // FIXME: habria que calcualar correctamente el geom-type, en funcion del actual y el ultimo.
248
    //                        possibleDataType.possibleGeometrySubtype = Geometry.SUBTYPES.GEOM3DM;
249
                            possibleDataType.possibleGeometrySubtype = Geometry.SUBTYPES.GEOM3D; // H2 no soporta M
250
                        }
251 47222 jjdelcerro
                    }
252 47235 jjdelcerro
                } catch (Exception ex) {
253
                    possibleDataType.possibleGeometry = false;
254 47222 jjdelcerro
                }
255 47206 jjdelcerro
            }
256
        }
257 47222 jjdelcerro
        if (possibleDataType.possibleInt) {
258
            this.detectedDataType.type = DataTypes.INT;
259
        } else if (possibleDataType.possibleLong) {
260
            this.detectedDataType.type = DataTypes.LONG;
261
        } else if (possibleDataType.possibleDecimal) {
262
            // Preferimos un Decimal que un Float/Double
263
            this.detectedDataType.type = DataTypes.DECIMAL;
264
        } else if (possibleDataType.possibleFloat) {
265
            // Forzamos los float a double para evitar perder precision
266
            this.detectedDataType.type = DataTypes.DOUBLE;
267
        } else if (possibleDataType.possibleDouble) {
268
            this.detectedDataType.type = DataTypes.DOUBLE;
269
        } else if (possibleDataType.possibleURL) {
270
            this.detectedDataType.type = DataTypes.URL;
271
        } else if (possibleDataType.possibleDate) {
272
            this.detectedDataType.type = DataTypes.DATE;
273
        } else if (possibleDataType.possibleTime) {
274
            this.detectedDataType.type = DataTypes.TIME;
275
        } else if (possibleDataType.possibleTimestamp) {
276
            this.detectedDataType.type = DataTypes.TIMESTAMP;
277
        } else if (possibleDataType.possibleGeometry) {
278
            this.detectedDataType.type = DataTypes.GEOMETRY;
279
            this.detectedDataType.geomtype = GeometryUtils.getGeometryType(
280
                    this.possibleDataType.possibleGeometryType,
281
                    this.possibleDataType.possibleGeometrySubtype
282
            );
283 47667 fdiaz
        } else { //if( this.detectedDataType.type == 0 ) {
284 47222 jjdelcerro
            this.detectedDataType.type = DataTypes.STRING;
285 47667 fdiaz
            this.detectedDataType.displaySize = Math.max(10,this.detectedDataType.displaySize);
286 47222 jjdelcerro
        }
287 43983 jjdelcerro
    }
288
289 47206 jjdelcerro
    @Override
290
    public DataTypeDetected getDataType() {
291
        return this.detectedDataType;
292
    }
293
294 43983 jjdelcerro
    private boolean isValidLong(String s) {
295
        if (s == null) {
296
            return true;
297
        }
298
        s = s.trim().toLowerCase();
299
        if (s.isEmpty()) {
300
            return true;
301
        }
302
        try {
303
            if (s.startsWith("0x")) {
304
                Long.valueOf(s.substring(2), 16);
305
            } else {
306
                Long.valueOf(s);
307
            }
308
            return true;
309
        } catch (Exception ex) {
310
            return false;
311
        }
312
    }
313
314
    private boolean isValidInteger(String s) {
315
        if (s == null) {
316
            return true;
317
        }
318
        s = s.trim().toLowerCase();
319
        if (s.isEmpty()) {
320
            return true;
321
        }
322
        try {
323
            if (s.startsWith("0x")) {
324
                Integer.valueOf(s.substring(2), 16);
325
            } else {
326
                Integer.valueOf(s);
327
            }
328
            return true;
329
        } catch (Exception ex) {
330
            return false;
331
        }
332
    }
333 44455 omartinez
334 47235 jjdelcerro
335
    private BigDecimal toDecimal(String s) {
336
        try {
337
            if (s.startsWith("+")) {
338
                s = s.substring(1);
339
            }
340
            ParsePosition p = new ParsePosition(0);
341
            DecimalFormat nf = (DecimalFormat) NumberFormat.getInstance(this.locale);
342
            nf.setParseBigDecimal(true);
343
            BigDecimal num = (BigDecimal) nf.parse(s, p);
344
            if (p.getErrorIndex() > 0 || p.getIndex() < s.length()) {
345
                return null;
346
            }
347
            return num;
348
        } catch (Exception ex) {
349
            return null;
350
        }
351
    }
352
353
    private Double toDouble(String s) {
354
        try {
355
            if (s.startsWith("+")) {
356
                s = s.substring(1);
357
            }
358
            ParsePosition p = new ParsePosition(0);
359
            DecimalFormat nf = (DecimalFormat) NumberFormat.getInstance(this.locale);
360
            Number n = nf.parse(s, p);
361
            if (p.getErrorIndex() > 0 || p.getIndex() < s.length()) {
362
                return null;
363
            }
364
            double num = n.doubleValue();
365
            return num;
366
        } catch (Exception ex) {
367
            return null;
368
        }
369
    }
370
371
    private Float toFloat(String s) {
372
        try {
373
            if (s.startsWith("+")) {
374
                s = s.substring(1);
375
            }
376
            ParsePosition p = new ParsePosition(0);
377
            DecimalFormat nf = (DecimalFormat) NumberFormat.getInstance(this.locale);
378
            Number n = nf.parse(s, p);
379
            if (p.getErrorIndex() > 0 || p.getIndex() < s.length()) {
380
                return null;
381
            }
382
            double num = n.doubleValue();
383
            if( num > Float.MAX_VALUE || num<Float.MIN_VALUE ) {
384
                return null;
385
            }
386
            return (float)num;
387
        } catch (Exception ex) {
388
            return null;
389
        }
390
    }
391 47337 fdiaz
392
    private Date toDate(String s) {
393
        DateFormat[] formatters = new DateFormat[]{
394
            DateFormat.getDateInstance(DateFormat.SHORT, locale),
395
            DateFormat.getDateInstance(DateFormat.MEDIUM, locale),
396
            DateFormat.getDateInstance(DateFormat.LONG, locale),
397
            new SimpleDateFormat("yyyy-MM-dd") // PostgreSQL format
398
        };
399
400
        for (DateFormat formatter : formatters) {
401
            formatter.setLenient(false);
402
            try {
403
                java.util.Date d = formatter.parse(s);
404
                if (d != null) {
405
                    return new Date(d.getTime());
406
                }
407
            } catch (ParseException e) {
408
                // Continue
409
            }
410
        }
411
        return null;
412
    }
413
414
    private Time toTime(String s) {
415
        DateFormat[] formatters = new DateFormat[]{
416
            DateFormat.getTimeInstance(DateFormat.MEDIUM, locale),
417
            DateFormat.getTimeInstance(DateFormat.SHORT, locale),
418
            DateFormat.getTimeInstance(DateFormat.LONG, locale),
419
            new SimpleDateFormat("HH:mm:ss"),
420
            new SimpleDateFormat("HH:mm"),
421
422
        };
423
424
        for (DateFormat formatter : formatters) {
425
            formatter.setLenient(false);
426
            try {
427
                java.util.Date d = formatter.parse(s);
428
                if (d != null) {
429
                    return new Time(d.getTime());
430
                }
431
            } catch (ParseException e) {
432
                // Continue
433
            }
434
        }
435
        return null;
436
    }
437
438
    private Timestamp toTimestamp(String s) {
439
        DateFormat[] formatters = new DateFormat[]{
440
            DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale),
441
            DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, locale),
442
            DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG, locale),
443
            DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale),
444
            DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale),
445
            DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale),
446
            DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, locale),
447
            DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT, locale),
448
            DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale),
449
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), // PostgreSQL timestamp format
450
            new SimpleDateFormat("yyyy-MM-dd HH:mm")
451
452
        };
453
454
        for (DateFormat formatter : formatters) {
455
            formatter.setLenient(false);
456
            try {
457
                java.util.Date d = formatter.parse(s);
458
                if (d != null) {
459
                    return new Timestamp(d.getTime());
460
                }
461
            } catch (ParseException e) {
462
                // Continue
463
            }
464
        }
465
        try {
466
            return Timestamp.valueOf(s);
467
        } catch (Exception ex){
468
        }
469
        return null;
470
    }
471 43983 jjdelcerro
}