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 @ 47667

History | View | Annotate | Download (17.5 KB)

1
package org.gvsig.fmap.dal.feature.impl;
2

    
3
import org.gvsig.fmap.dal.feature.DataTypeDetector;
4
import java.math.BigDecimal;
5
import java.net.URL;
6
import java.sql.Date;
7
import java.sql.Time;
8
import java.sql.Timestamp;
9
import java.text.DateFormat;
10
import java.text.DecimalFormat;
11
import java.text.NumberFormat;
12
import java.text.ParseException;
13
import java.text.ParsePosition;
14
import java.text.SimpleDateFormat;
15
import java.util.Locale;
16
import org.apache.commons.lang3.StringUtils;
17
import org.gvsig.fmap.dal.DataTypes;
18
import org.gvsig.fmap.geom.Geometry;
19
import org.gvsig.fmap.geom.GeometryCoercionContext;
20
import org.gvsig.fmap.geom.GeometryLocator;
21
import org.gvsig.fmap.geom.GeometryManager;
22
import org.gvsig.fmap.geom.GeometryUtils;
23
import org.gvsig.fmap.geom.type.GeometryType;
24
import org.gvsig.tools.ToolsLocator;
25
import org.gvsig.tools.dataTypes.DataTypesManager;
26
import org.gvsig.tools.dataTypes.Coercion;
27
import org.gvsig.tools.dataTypes.CoercionContext;
28
import org.gvsig.tools.dataTypes.CoercionContextLocale;
29

    
30
/**
31
 *
32
 * @author jjdelcerro
33
 */
34
@SuppressWarnings("UseSpecificCatch")
35
public class DataTypeDetectorImpl implements DataTypeDetector {
36

    
37
    private Locale locale;
38

    
39
    private static class DataTypeDetectedImpl implements DataTypeDetected {
40

    
41
        private int type;
42
        private int displaySize;
43
        private int integerDigits;
44
        private int decimalDigits;
45
        private boolean blank;
46
        private GeometryType geomtype;
47
        
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
            return this.decimalDigits + this.integerDigits;
61
        }
62

    
63
        @Override
64
        public int getScale() {
65
            return this.decimalDigits;
66
        }
67
        
68
        @Override
69
        public boolean isBlank() {
70
            return this.blank;
71
        }
72

    
73
        @Override
74
        public GeometryType getGeometryType() {
75
            return this.geomtype;
76
        }
77

    
78
        @Override
79
        public void setDisplaySize(int size) {
80
            this.displaySize = size;
81
        }
82
    }
83

    
84
    private static class PossibleDataType {
85

    
86
        public boolean possibleInt = true;
87
        public boolean possibleFloat = true;
88
        public boolean possibleDouble = true;
89
        public boolean possibleDecimal = true;
90
        public boolean possibleLong = true;
91
        public boolean possibleURL = true;
92
        public boolean possibleDate = true;
93
        public boolean possibleTime = true;
94
        public boolean possibleTimestamp = true;
95
        public boolean possibleGeometry = true;
96
        private int possibleGeometrySubtype;
97
        private int possibleGeometryType;
98
    }
99

    
100
    private PossibleDataType possibleDataType;
101
    private DataTypeDetectedImpl detectedDataType;
102
//    private Coercion toDecimal;
103
//    private Coercion toDouble;
104
//    private Coercion toFloat;
105
//    private Coercion toDate;
106
//    private Coercion toTime;
107
//    private Coercion toTimestamp;
108
//    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
    }
117
   
118
    private void init(Locale locale) {
119
        if (locale == null) {
120
            locale = Locale.getDefault();
121
        }
122
        DataTypesManager typeManager = ToolsLocator.getDataTypesManager();
123
        coercionContext = CoercionContextLocale.create(locale);
124
        
125
//        toDecimal = typeManager.getCoercion(DataTypes.DECIMAL);
126
//        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
//        toInt = typeManager.getCoercion(DataTypes.INT);
132
//        toLong = typeManager.getCoercion(DataTypes.LONG);
133
        toGeom = typeManager.getCoercion(DataTypes.GEOMETRY); 
134

    
135
        geometryCoercionContext = GeometryLocator.getGeometryManager().createGeometryCoercionContext();
136
        geometryCoercionContext.setMode(GeometryCoercionContext.MODE_ONERROR_THROW);
137
        
138
        detectedDataType = new DataTypeDetectedImpl();
139
        possibleDataType = new PossibleDataType();
140
        possibleDataType.possibleGeometryType = Geometry.TYPES.UNKNOWN;
141
        possibleDataType.possibleGeometrySubtype = Geometry.SUBTYPES.UNKNOWN;
142
        this.locale = locale;
143
    }
144
    
145
    @SuppressWarnings("ResultOfObjectAllocationIgnored")
146
    @Override
147
    public void addValue(String rawvalue) {
148
        if( rawvalue == null ) {
149
           return; 
150
        }
151
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
152

    
153
        if( detectedDataType.blank ) {
154
            detectedDataType.blank = StringUtils.isBlank(rawvalue);
155
        }
156
        int displaySize = rawvalue.length();
157
        if( displaySize>detectedDataType.displaySize ) {
158
            detectedDataType.displaySize = displaySize;
159
        }
160
        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
                }
178
            }
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
                }
186
            }
187
            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
            }
195
            if (possibleDataType.possibleLong) {
196
                    possibleDataType.possibleLong = isValidLong(rawvalue);
197
            }
198
            if (possibleDataType.possibleInt) {
199
                possibleDataType.possibleInt = isValidInteger(rawvalue);
200
            }
201
            if (possibleDataType.possibleDate) {
202
                try {
203
                    possibleDataType.possibleDate = (toDate(rawvalue) != null);
204
                } catch (Exception ex) {
205
                    possibleDataType.possibleDate = false;
206
                }
207
            }
208
            if (possibleDataType.possibleTime) {
209
                try {
210
                    possibleDataType.possibleTime = (toTime(rawvalue) != null);
211
                } catch (Exception ex) {
212
                    possibleDataType.possibleTime = false;
213
                }
214
            }
215
            if (possibleDataType.possibleTimestamp) {
216
                try {
217
                    possibleDataType.possibleTimestamp = (toTimestamp(rawvalue) != null);
218
                } catch (Exception ex) {
219
                    possibleDataType.possibleTimestamp = false;
220
                }
221
            }
222
            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

    
231
            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
                    }
252
                } catch (Exception ex) {
253
                    possibleDataType.possibleGeometry = false;
254
                }
255
            }
256
        }
257
        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
        } else { //if( this.detectedDataType.type == 0 ) {
284
            this.detectedDataType.type = DataTypes.STRING;
285
            this.detectedDataType.displaySize = Math.max(10,this.detectedDataType.displaySize);
286
        }
287
    }
288

    
289
    @Override
290
    public DataTypeDetected getDataType() {
291
        return this.detectedDataType;
292
    }
293

    
294
    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

    
334
    
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
   
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
}