Statistics
| Revision:

svn-gvsig-desktop / tags / v1_0_2_Build_894 / libraries / libGDBMS / src / main / java / com / hardcode / gdbms / engine / values / ValueFactory.java @ 10309

History | View | Annotate | Download (19 KB)

1
package com.hardcode.gdbms.engine.values;
2

    
3
import com.hardcode.gdbms.engine.instruction.SemanticException;
4
import com.hardcode.gdbms.parser.SQLEngineConstants;
5

    
6
import java.lang.reflect.Constructor;
7
import java.lang.reflect.InvocationTargetException;
8
import java.sql.Time;
9
import java.sql.Timestamp;
10
import java.sql.Types;
11

    
12
import java.text.DateFormat;
13
import java.text.ParseException;
14
import java.text.SimpleDateFormat;
15

    
16
import java.util.Date;
17
import java.util.TimeZone;
18

    
19

    
20
/**
21
 * Factor?a abstracta de objetos value que dado un tipo b?sico, devuelve el
22
 * wrapper apropiado
23
 *
24
 * @author $author$
25
 * @version $Revision: 10309 $
26
 */
27
public class ValueFactory {
28
    final static int BYTE = 0;
29
    final static int SHORT = 1;
30
    final static int INTEGER = 2;
31
    final static int LONG = 3;
32
    final static int FLOAT = 5;
33
    final static int DOUBLE = 6;
34
    /**
35
     * Crea un objeto de tipo Value a partir de un int
36
     *
37
     * @param n valor que se quiere representar
38
     *
39
     * @return objeto Value con el valor que se pasa como par?metro
40
     */
41
    public static IntValue createValue(int n) {
42
        IntValue ret = new IntValue();
43
        ret.setValue(n);
44

    
45
        return ret;
46
    }
47

    
48
    /**
49
     * Crea un objeto de tipo Value a partir de un long
50
     *
51
     * @param l valor que se quiere representar
52
     *
53
     * @return objeto Value con el valor que se pasa como par?metro
54
     */
55
    public static LongValue createValue(long l) {
56
        LongValue ret = new LongValue();
57
        ret.setValue(l);
58

    
59
        return ret;
60
    }
61

    
62
    /**
63
     * Crea un objeto de tipo Value a partir de un String
64
     *
65
     * @param s valor que se quiere representar
66
     *
67
     * @return objeto Value con el valor que se pasa como par?metro
68
     */
69
    public static StringValue createValue(String s) {
70
        StringValue ret = new StringValue();
71
        ret.setValue(s);
72

    
73
        return ret;
74
    }
75

    
76
    /**
77
     * Crea un objeto de tipo Value a partir de un float
78
     *
79
     * @param f valor que se quiere representar
80
     *
81
     * @return objeto Value con el valor que se pasa como par?metro
82
     */
83
    public static FloatValue createValue(float f) {
84
        FloatValue ret = new FloatValue();
85
        ret.setValue(f);
86

    
87
        return ret;
88
    }
89

    
90
    /**
91
     * Crea un objeto de tipo Value a partir de un double
92
     *
93
     * @param d valor que se quiere representar
94
     *
95
     * @return objeto Value con el valor que se pasa como par?metro
96
     */
97
    public static DoubleValue createValue(double d) {
98
        DoubleValue ret = new DoubleValue();
99
        ret.setValue(d);
100

    
101
        return ret;
102
    }
103

    
104
    /**
105
     * Crea un objeto de tipo Date a partir de un Date
106
     *
107
     * @param d valor que se quiere representar
108
     *
109
     * @return objeto Value con el valor que se pasa como par?metro
110
     */
111
    public static DateValue createValue(Date d) {
112
        DateValue ret = new DateValue();
113
        ret.setValue(d);
114

    
115
        return ret;
116
    }
117

    
118
    /**
119
     * Creates a TimeValue object
120
     *
121
     * @param t Time value
122
     *
123
     * @return TimeValue
124
     */
125
    public static TimeValue createValue(Time t) {
126
        TimeValue ret = new TimeValue();
127
        ret.setValue(t);
128

    
129
        return ret;
130
    }
131

    
132
    /**
133
     * Creates a TimestampValue object
134
     *
135
     * @param t Timestamp value
136
     *
137
     * @return TimestampValue
138
     */
139
    public static TimestampValue createValue(Timestamp t) {
140
        TimestampValue ret = new TimestampValue();
141
        ret.setValue(t);
142

    
143
        return ret;
144
    }
145

    
146
    /**
147
     * Crea un objeto de tipo Value a partir de un booleano
148
     *
149
     * @param b valor que se quiere representar
150
     *
151
     * @return objeto Value con el valor que se pasa como par?metro
152
     */
153
    public static BooleanValue createValue(boolean b) {
154
        BooleanValue ret = new BooleanValue();
155
        ret.setValue(b);
156

    
157
        return ret;
158
    }
159

    
160
    /**
161
     * Creates an ArrayValue
162
     *
163
     * @param values DOCUMENT ME!
164
     *
165
     * @return ArrayValue
166
     */
167
    public static ValueCollection createValue(Value[] values) {
168
        ValueCollection v = new ValueCollection();
169
        v.setValues(values);
170

    
171
        return v;
172
    }
173

    
174
    /**
175
     * Crea un Value a partir de un literal encontrado en una instrucci?n y su
176
     * tipo
177
     *
178
     * @param text Texto del valor
179
     * @param type Tipo del valor
180
     *
181
     * @return Objeto Value del tipo adecuado
182
     *
183
     * @throws SemanticException Si el tipo del literal no est? soportado
184
     */
185
    public static Value createValue(String text, int type)
186
        throws SemanticException {
187
        switch (type) {
188
            case SQLEngineConstants.STRING_LITERAL:
189

    
190
                StringValue r1 = new StringValue();
191
                r1.setValue(text.substring(1, text.length() - 1));
192

    
193
                return r1;
194

    
195
            case SQLEngineConstants.INTEGER_LITERAL:
196

    
197
                try {
198
                    IntValue r2 = new IntValue();
199
                    r2.setValue(Integer.parseInt(text));
200

    
201
                    return r2;
202
                } catch (NumberFormatException e) {
203
                    LongValue r2 = new LongValue();
204
                    r2.setValue(Long.parseLong(text));
205

    
206
                    return r2;
207
                }
208

    
209
            case SQLEngineConstants.FLOATING_POINT_LITERAL:
210

    
211
                try {
212
                    FloatValue r2 = new FloatValue();
213
                    r2.setValue(Float.parseFloat(text));
214

    
215
                    return r2;
216
                } catch (NumberFormatException e) {
217
                    DoubleValue r2 = new DoubleValue();
218
                    r2.setValue(Double.parseDouble(text));
219

    
220
                    return r2;
221
                }
222

    
223
            default:
224
                throw new SemanticException("Unexpected literal type: " + text +
225
                    "->" + type);
226
        }
227
    }
228

    
229
    /**
230
     * DOCUMENT ME!
231
     *
232
     * @param text DOCUMENT ME!
233
     * @param type DOCUMENT ME!
234
     *
235
     * @return DOCUMENT ME!
236
     *
237
     * @throws ParseException DOCUMENT ME!
238
     */
239
    public static Value createValueByType(String text, int type)
240
        throws ParseException {
241
        Value value;
242

    
243
        switch (type) {
244
            case Types.BIGINT:
245
                value = ValueFactory.createValue(Long.parseLong(text));
246

    
247
                break;
248

    
249
            case Types.BIT:
250
            case Types.BOOLEAN:
251
                value = ValueFactory.createValue(Boolean.valueOf(text)
252
                                                        .booleanValue());
253

    
254
                break;
255

    
256
            case Types.CHAR:
257
            case Types.VARCHAR:
258
            case Types.LONGVARCHAR:
259
                value = ValueFactory.createValue(text);
260

    
261
                break;
262

    
263
            case Types.DATE:
264
                    try {
265
                    value = ValueFactory.createValue(new Date(Date.parse(text)));
266
                    }catch (IllegalArgumentException e) {
267
                                        throw new ParseException(e.getMessage(),0);
268
                                }
269
                break;
270

    
271
            case Types.DECIMAL:
272
            case Types.NUMERIC:
273
            case Types.FLOAT:
274
            case Types.DOUBLE:
275
                value = ValueFactory.createValue(Double.parseDouble(text));
276

    
277
                break;
278

    
279
            case Types.INTEGER:
280
                value = ValueFactory.createValue(Integer.parseInt(text));
281

    
282
                break;
283

    
284
            case Types.REAL:
285
                value = ValueFactory.createValue(Float.parseFloat(text));
286

    
287
                break;
288

    
289
            case Types.SMALLINT:
290
                value = ValueFactory.createValue(Short.parseShort(text));
291

    
292
                break;
293

    
294
            case Types.TINYINT:
295
                value = ValueFactory.createValue(Byte.parseByte(text));
296

    
297
                break;
298

    
299
            case Types.BINARY:
300
            case Types.VARBINARY:
301
            case Types.LONGVARBINARY:
302

    
303
                if ((text.length() / 2) != (text.length() / 2.0)) {
304
                    throw new ParseException("binary fields must have even number of characters.",
305
                        0);
306
                }
307

    
308
                byte[] array = new byte[text.length() / 2];
309

    
310
                for (int i = 0; i < (text.length() / 2); i++) {
311
                    String byte_ = text.substring(2 * i, (2 * i) + 2);
312
                    array[i] = (byte) Integer.parseInt(byte_, 16);
313
                }
314

    
315
                value = ValueFactory.createValue(array);
316

    
317
                break;
318

    
319
            case Types.TIMESTAMP:
320
                value = ValueFactory.createValue(Timestamp.valueOf(text));
321

    
322
                break;
323

    
324
            case Types.TIME:
325
                DateFormat tf = DateFormat.getTimeInstance();
326
                value = ValueFactory.createValue(new Time(
327
                            tf.parse(text).getTime()));
328

    
329
                break;
330

    
331
            default:
332
                value = ValueFactory.createValue(text);
333
        }
334

    
335
        return value;
336
    }
337

    
338
    /**
339
     * DOCUMENT ME!
340
     *
341
     * @param text DOCUMENT ME!
342
     * @param className DOCUMENT ME!
343
     *
344
     * @return DOCUMENT ME!
345
     *
346
     * @throws SemanticException DOCUMENT ME!
347
     *
348
     * @deprecated Use createValueWithType(String, int) instead
349
     */
350
    public static Value createValue(String text, String className)
351
        throws SemanticException {
352
        if (className.equals("com.hardcode.gdbms.engine.values.BooleanValue")) {
353
            return createValue(Boolean.getBoolean(text));
354
        }
355

    
356
        if (className.equals("com.hardcode.gdbms.engine.values.DateValue")) {
357
            try {
358
                return createValue(DateFormat.getInstance().parse(text));
359
            } catch (ParseException e) {
360
                throw new SemanticException(e);
361
            }
362
        }
363

    
364
        if (className.equals("com.hardcode.gdbms.engine.values.DoubleValue")) {
365
            return createValue(Double.parseDouble(text));
366
        }
367

    
368
        if (className.equals("com.hardcode.gdbms.engine.values.FloatValue")) {
369
            return createValue(Float.parseFloat(text));
370
        }
371

    
372
        if (className.equals("com.hardcode.gdbms.engine.values.IntValue")) {
373
            return createValue(Integer.parseInt(text));
374
        }
375

    
376
        if (className.equals("com.hardcode.gdbms.engine.values.LongValue")) {
377
            return createValue(Long.parseLong(text));
378
        }
379

    
380
        if (className.equals("com.hardcode.gdbms.engine.values.StringValue")) {
381
            return createValue(text);
382
        }
383

    
384
        // default:
385
        throw new SemanticException(
386
            "Unexpected className in createValue (GDBMS) text: " + text +
387
            "-> className: " + className);
388
    }
389

    
390
    /**
391
     * Creates a new null Value
392
     *
393
     * @return NullValue
394
     */
395
    public static NullValue createNullValue() {
396
        return new NullValue();
397
    }
398

    
399
    /**
400
     * Dado el tipo que se pasa como par?metro, expresado con una de las
401
     * constantes definidas en la clase java.sql.Types se devuelve la clase
402
     * que implementa dicho tipo
403
     *
404
     * @param type Tipo de la columna
405
     *
406
     * @return Clase que implementa el tipo
407
     *
408
     * @throws RuntimeException if type is not recognized
409
     */
410
    public static Class getType(int type) {
411
        switch (type) {
412
            case Types.NUMERIC:
413
            case Types.BIGINT:
414
                return LongValue.class;
415

    
416
            case Types.BIT:
417
                return BooleanValue.class;
418

    
419
            case Types.SMALLINT:
420
                return ShortValue.class;
421

    
422
            case Types.TINYINT:
423
                return ByteValue.class;
424

    
425
            case Types.CHAR:
426
            case Types.VARCHAR:
427
            case Types.LONGVARCHAR:
428
                return StringValue.class;
429

    
430
            case Types.DATE:
431
                return DateValue.class;
432

    
433
            case Types.FLOAT:
434
            case Types.DOUBLE:
435
            case Types.DECIMAL:
436
                return DoubleValue.class;
437

    
438
            case Types.INTEGER:
439
                return IntValue.class;
440

    
441
            case Types.REAL:
442
                return FloatValue.class;
443

    
444
            case Types.BINARY:
445
            case Types.VARBINARY:
446
            case Types.LONGVARBINARY:
447
                return BinaryValue.class;
448

    
449
            case Types.TIMESTAMP:
450
                return TimestampValue.class;
451

    
452
            case Types.TIME:
453
                return TimeValue.class;
454

    
455
            case Types.OTHER:default:
456
                throw new RuntimeException("Type not recognized: " + type);
457
        }
458
    }
459

    
460
    /**
461
     * Gets a Value with the value v1 plus v2
462
     *
463
     * @param v1 first value
464
     * @param v2 second value
465
     *
466
     * @return a numeric value with the operation
467
     */
468
    static NumericValue suma(NumericValue v1, NumericValue v2) {
469
        int type = Math.max(v1.getType(), v2.getType());
470

    
471
        while (true) {
472
            switch (type) {
473
                /*
474
                 * El operador '+' en java no est? definido para byte ni short, as?
475
                 * que nosotros tampoco lo definimos.
476
                 * Por otro lado no conocemos manera de detectar el overflow al operar
477
                 * con long's ni double's de manera eficiente, as? que no se detecta.
478
                 */
479
                case BYTE:
480
                case SHORT:
481
                case INTEGER:
482

    
483
                    int intValue = v1.intValue() + v2.intValue();
484

    
485
                    if ((intValue) != (v1.longValue() + v2.longValue())) {
486
                        type = LONG;
487

    
488
                        continue;
489
                    } else {
490
                        return (NumericValue) createValue(intValue);
491
                    }
492

    
493
                case LONG:
494
                    return (NumericValue) createValue(v1.longValue() +
495
                        v2.longValue());
496

    
497
                case FLOAT:
498

    
499
                    float floatValue = v1.floatValue() + v2.floatValue();
500

    
501
                    if ((floatValue) != (v1.doubleValue() + v2.doubleValue())) {
502
                        type = DOUBLE;
503

    
504
                        continue;
505
                    } else {
506
                        return (NumericValue) createValue(floatValue);
507
                    }
508

    
509
                case DOUBLE:
510
                    return (NumericValue) createValue(v1.doubleValue() +
511
                        v2.doubleValue());
512
            }
513
        }
514
    }
515

    
516
    /**
517
     * Gets the value of the operation v1  v2
518
     *
519
     * @param v1 first value
520
     * @param v2 second value
521
     *
522
     * @return a numeric value with the operation
523
     */
524
    static NumericValue producto(NumericValue v1, NumericValue v2) {
525
        int type = Math.max(v1.getType(), v2.getType());
526

    
527
        while (true) {
528
            switch (type) {
529
                /*
530
                 * El operador '+' en java no est? definido para byte ni short, as?
531
                 * que nosotros tampoco lo definimos.
532
                 * Por otro lado no conocemos manera de detectar el overflow al operar
533
                 * con long's ni double's de manera eficiente, as? que no se detecta.
534
                 */
535
                case BYTE:
536
                case SHORT:
537
                case INTEGER:
538

    
539
                    int intValue = v1.intValue() * v2.intValue();
540

    
541
                    if ((intValue) != (v1.intValue() * v2.intValue())) {
542
                        type = LONG;
543

    
544
                        continue;
545
                    } else {
546
                        return (NumericValue) createValue(intValue);
547
                    }
548

    
549
                case LONG:
550
                    return (NumericValue) createValue(v1.longValue() * v2.longValue());
551

    
552
                case FLOAT:
553

    
554
                    float floatValue = v1.floatValue() * v2.floatValue();
555

    
556
                    if ((floatValue) != (v1.doubleValue() * v2.doubleValue())) {
557
                        type = DOUBLE;
558

    
559
                        continue;
560
                    } else {
561
                        return (NumericValue) createValue(floatValue);
562
                    }
563

    
564
                case DOUBLE:
565
                    return (NumericValue) createValue(v1.doubleValue() * v2.doubleValue());
566
            }
567
        }
568
    }
569

    
570
    /**
571
     * Calcula la inversa (1/v) del valor que se pasa como par?metro.
572
     *
573
     * @param v Valor cuya inversa se quiere obtener
574
     *
575
     * @return DoubleValue
576
     */
577
    static NumericValue inversa(NumericValue v) {
578
        int type = v.getType();
579

    
580
        return (NumericValue) createValue(1 / v.doubleValue());
581
    }
582

    
583
    /**
584
     * Creates a byte array value
585
     *
586
     * @param bytes bytes of the value
587
     *
588
     * @return
589
     */
590
    public static BinaryValue createValue(byte[] bytes) {
591
        BinaryValue ret = new BinaryValue(bytes);
592

    
593
        return ret;
594
    }
595
    
596
    /**
597
     * Creates a complex value based on a xml parseable
598
     * string
599
     *
600
     * @param string
601
     *
602
     * @return new instance of ComplexValue or null???
603
     */    
604
    public static ComplexValue createComplexValue(String string) {
605
            try {
606
                    return new ComplexValue(string);
607
                    
608
            } catch (Exception e) {
609
                    //FIXME: OJO!!! QUE HACEMOS AQUI
610
                    return null;
611
                }
612
    }
613

    
614
    /**
615
     *  Create a Value instance from a String value using
616
     * the class specified in valueName.
617
     * <P>
618
     * 
619
     * <code>
620
     * Nota: Habria que ver que hacemos con esto... seguimos delegando
621
     * o modificar el createValueByType para que delege en esta
622
     * </code>
623
     * <P>
624
     * @param text String representation of value
625
     * @param valueName class name of the instance of Value to return.
626
     *                         It can be the class name without the package.
627
     * @return a Value instance
628
     * @throws ParseException
629
     */
630
    public static Value createValueByValueName(String text, String valueName)
631
            throws ParseException {
632
            String baseName;
633
            if (valueName.indexOf(".") > -1) {
634
                    baseName = valueName.substring( valueName.lastIndexOf(".")+1);
635
            } else {
636
                    baseName = valueName;
637
            }
638
            if (baseName.equals("BinaryValue")) {
639
                    return createValueByType(text,Types.BINARY);
640
            } else if (baseName.equals("BooleanValue")) {
641
                    return createValueByType(text,Types.BOOLEAN);
642
            } else if (baseName.equals("ByteValue")) {
643
                    return createValueByType(text,Types.TINYINT);
644
            } else if (baseName.equals("ComplexValue")) {
645
                    return createComplexValue(text);
646
            } else if (baseName.equals("DateValue")) {
647
                    return createValueByType(text,Types.DATE);
648
            } else if (baseName.equals("DoubleValue")) {
649
                    return createValueByType(text,Types.DOUBLE);
650
            } else if (baseName.equals("FloatValue")) {
651
                    return createValueByType(text,Types.REAL);
652
            } else if (baseName.equals("IntValue")) {
653
                    return createValueByType(text,Types.INTEGER);
654
            } else if (baseName.equals("LongValue")) {
655
                    return createValueByType(text,Types.BIGINT);
656
            } else if (baseName.equals("NullValue")) {
657
                    return new NullValue();
658
            } else if (baseName.equals("ShortValue")) {
659
                    return createValueByType(text,Types.SMALLINT);
660
            } else if (baseName.equals("StringValue")) {
661
                    return createValueByType(text,Types.VARCHAR);
662
            } else if (baseName.equals("TimestampValue")) {
663
                    return createValueByType(text,Types.TIMESTAMP);
664
            } else if (baseName.equals("TimeValue")) {
665
                    return createValueByType(text,Types.TIME);
666
            } else {
667
                    try {
668
                        Class valueClass = Class.forName(valueName);
669
                        Constructor constr= valueClass.getConstructor(new Class[] {String.class});
670
                        return (Value) constr.newInstance(new Object[] {text});
671
                        } catch (Exception e) {
672
                                throw new ParseException(e.getMessage(),0);
673
                        }
674
            }
675
    }
676
}