001: /*
002: * Copyright 2004-2007 Gary Bentley
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may
005: * not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015: package org.josql.functions;
016:
017: import java.util.Map;
018: import java.util.HashMap;
019: import java.util.Date;
020: import java.util.GregorianCalendar;
021: import java.util.Calendar;
022:
023: import java.text.SimpleDateFormat;
024:
025: import org.josql.QueryExecutionException;
026:
027: /**
028: * Note: creating new instances of SimpleDateFormat objects are VERY costly over
029: * large(ish) numbers of objects therefore a cache of objects is provided.
030: */
031: public class ConversionFunctions extends AbstractFunctionHandler {
032:
033: public static final String HANDLER_ID = "_internal_conversion";
034:
035: /**
036: * Represents the {@link Calendar#MINUTE} field, is: <b>mi</b>.
037: */
038: public static final String MINUTE = "mi";
039:
040: /**
041: * Represents the {@link Calendar#DATE} field, is: <b>d</b>.
042: */
043: public static final String DAY = "d";
044:
045: /**
046: * Represents the {@link Calendar#YEAR} field, is: <b>y</b>.
047: */
048: public static final String YEAR = "y";
049:
050: /**
051: * Represents the {@link Calendar#SECOND} field, is: <b>s</b>.
052: */
053: public static final String SECOND = "s";
054:
055: /**
056: * Represents the {@link Calendar#HOUR_OF_DAY} field, is: <b>h</b>.
057: */
058: public static final String HOUR = "h";
059:
060: /**
061: * Represents the {@link Calendar#MONTH} field, is: <b>m</b>.
062: */
063: public static final String MONTH = "m";
064:
065: /**
066: * Represents the {@link Calendar#WEEK_OF_YEAR} field, is: <b>w</b>.
067: */
068: public static final String WEEK = "w";
069:
070: public static String DEFAULT_DATE_FORMAT_SPEC = "dd/MMM/yyyy";
071: public static String DEFAULT_DATE_FORMAT_SPEC_2 = "dd-MMM-yyyy";
072: public static String DEFAULT_DATE_FORMAT_SPEC_3 = "dd MMM yyyy";
073:
074: private static Map sdfs = new HashMap();
075: private static Calendar cal = Calendar.getInstance();
076:
077: static {
078:
079: ConversionFunctions.sdfs.put(
080: ConversionFunctions.DEFAULT_DATE_FORMAT_SPEC,
081: new SimpleDateFormat(
082: ConversionFunctions.DEFAULT_DATE_FORMAT_SPEC));
083: ConversionFunctions.sdfs
084: .put(
085: ConversionFunctions.DEFAULT_DATE_FORMAT_SPEC_2,
086: new SimpleDateFormat(
087: ConversionFunctions.DEFAULT_DATE_FORMAT_SPEC_2));
088: ConversionFunctions.sdfs
089: .put(
090: ConversionFunctions.DEFAULT_DATE_FORMAT_SPEC_3,
091: new SimpleDateFormat(
092: ConversionFunctions.DEFAULT_DATE_FORMAT_SPEC_3));
093:
094: }
095:
096: /**
097: * This method (function) will return the associated field from a
098: * {@link Calendar} instance. The <b>type</b> parm should be one of the
099: * constants from this class. The default {@link java.util.TimeZone} is used.
100: *
101: * @param d If the type is a long value then it is first converted to a Date.
102: * Or a {@link Date} should be used.
103: * @param type The type of field to get.
104: * @return The field from {@link Calendar}.
105: * @throws QueryExecutionException If the <b>d</b> parm isn't an instance of
106: * {@link Long} or {@link Date}.
107: */
108: public int timeField(Object d, String type)
109: throws QueryExecutionException {
110:
111: if ((!(d instanceof Date)) && (!(d instanceof Long))) {
112:
113: throw new QueryExecutionException(
114: "Value passed in is of type: "
115: + d.getClass().getName() + " only: "
116: + Long.class.getName() + " or: "
117: + Date.class.getName() + " are supported.");
118:
119: }
120:
121: Date date = null;
122:
123: if (d instanceof Long) {
124:
125: date = new Date(((Long) d).longValue());
126:
127: }
128:
129: if (d instanceof Date) {
130:
131: date = (Date) d;
132:
133: }
134:
135: ConversionFunctions.cal.setTime(date);
136:
137: type = type.toLowerCase();
138:
139: if (type.equals(ConversionFunctions.SECOND)) {
140:
141: return ConversionFunctions.cal.get(Calendar.SECOND);
142:
143: }
144:
145: if (type.equals(ConversionFunctions.MINUTE)) {
146:
147: return ConversionFunctions.cal.get(Calendar.MINUTE);
148:
149: }
150:
151: if (type.equals(ConversionFunctions.HOUR)) {
152:
153: return ConversionFunctions.cal.get(Calendar.HOUR_OF_DAY);
154:
155: }
156:
157: if (type.equals(ConversionFunctions.DAY)) {
158:
159: return ConversionFunctions.cal.get(Calendar.DATE);
160:
161: }
162:
163: if (type.equals(ConversionFunctions.WEEK)) {
164:
165: return ConversionFunctions.cal.get(Calendar.WEEK_OF_YEAR);
166:
167: }
168:
169: if (type.equals(ConversionFunctions.MONTH)) {
170:
171: return ConversionFunctions.cal.get(Calendar.MONTH);
172:
173: }
174:
175: if (type.equals(ConversionFunctions.YEAR)) {
176:
177: return ConversionFunctions.cal.get(Calendar.YEAR);
178:
179: }
180:
181: // None of the above...
182: return -1;
183:
184: }
185:
186: public Date addTime(Date d, Double amount, String type) {
187:
188: int a = amount.intValue();
189:
190: long v = d.getTime();
191:
192: if (type.equals(ConversionFunctions.SECOND)) {
193:
194: v += (a * 1000);
195:
196: return new Date(v);
197:
198: }
199:
200: if (type.equals(ConversionFunctions.MINUTE)) {
201:
202: v += (a * 60000);
203:
204: return new Date(v);
205:
206: }
207:
208: if (type.equals(ConversionFunctions.HOUR)) {
209:
210: v += (a * 3600000);
211:
212: return new Date(v);
213:
214: }
215:
216: if (type.equals(ConversionFunctions.DAY)) {
217:
218: v += (a * 24 * 3600000);
219:
220: return new Date(v);
221:
222: }
223:
224: if (type.equals(ConversionFunctions.WEEK)) {
225:
226: v += (a * 7 * 24 * 3600000);
227:
228: return new Date(v);
229:
230: }
231:
232: if (type.equals(ConversionFunctions.MONTH)) {
233:
234: // Need something a bit more sophisticated now...
235: GregorianCalendar gc = new GregorianCalendar();
236: gc.setTime(d);
237:
238: gc.add(Calendar.MONTH, a);
239:
240: return gc.getTime();
241:
242: }
243:
244: if (type.equals(ConversionFunctions.YEAR)) {
245:
246: // Need something a bit more sophisticated now...
247: GregorianCalendar gc = new GregorianCalendar();
248: gc.setTime(d);
249:
250: gc.add(Calendar.YEAR, a);
251:
252: return gc.getTime();
253:
254: }
255:
256: // None of the above...
257: return d;
258:
259: }
260:
261: public Date toDate(Object value) throws QueryExecutionException {
262:
263: if (value == null) {
264:
265: return null;
266:
267: }
268:
269: if (value instanceof Number) {
270:
271: return new Date(((Number) value).longValue());
272:
273: }
274:
275: if (value instanceof String) {
276:
277: return this .toDate((String) value, null);
278:
279: }
280:
281: if (value instanceof Date) {
282:
283: return (Date) value;
284:
285: }
286:
287: throw new QueryExecutionException("Type: "
288: + value.getClass().getName() + " is not supported.");
289:
290: }
291:
292: public Date to_date(Object value) throws QueryExecutionException {
293:
294: return this .toDate(value);
295:
296: }
297:
298: public Date to_date(String value, String spec)
299: throws QueryExecutionException {
300:
301: return this .toDate(value, spec);
302:
303: }
304:
305: public Date toDate(String value, String spec)
306: throws QueryExecutionException {
307:
308: if (spec == null) {
309:
310: spec = ConversionFunctions.DEFAULT_DATE_FORMAT_SPEC;
311:
312: }
313:
314: SimpleDateFormat df = (SimpleDateFormat) ConversionFunctions.sdfs
315: .get(spec);
316:
317: if (df == null) {
318:
319: df = new SimpleDateFormat(spec);
320:
321: ConversionFunctions.sdfs.put(spec, df);
322:
323: }
324:
325: try {
326:
327: return df.parse(value);
328:
329: } catch (Exception e) {
330:
331: throw new QueryExecutionException(
332: "Unable to parse date value: " + value
333: + " using spec: " + spec, e);
334:
335: }
336:
337: }
338:
339: public Long toMillis(Date d) {
340:
341: return new Long(d.getTime());
342:
343: }
344:
345: public Long toDateMillis(String value, String spec)
346: throws QueryExecutionException {
347:
348: if (spec == null) {
349:
350: spec = ConversionFunctions.DEFAULT_DATE_FORMAT_SPEC;
351:
352: }
353:
354: SimpleDateFormat df = (SimpleDateFormat) ConversionFunctions.sdfs
355: .get(spec);
356:
357: if (df == null) {
358:
359: df = new SimpleDateFormat(spec);
360:
361: ConversionFunctions.sdfs.put(spec, df);
362:
363: }
364:
365: try {
366:
367: Date d = df.parse(value);
368:
369: return new Long(d.getTime());
370:
371: } catch (Exception e) {
372:
373: throw new QueryExecutionException(
374: "Unable to parse date value: " + value
375: + " using spec: " + spec, e);
376:
377: }
378:
379: }
380:
381: public String upper(Object o) {
382:
383: if (o == null) {
384:
385: return null;
386:
387: }
388:
389: return o.toString().toUpperCase();
390:
391: }
392:
393: public String lower(Object o) {
394:
395: if (o == null) {
396:
397: return null;
398:
399: }
400:
401: return o.toString().toLowerCase();
402:
403: }
404:
405: public String to_string(Object o) {
406:
407: return this .toString(o);
408:
409: }
410:
411: public String toString(Object o) {
412:
413: return o + "";
414:
415: }
416:
417: public Number to_number(Object o) {
418:
419: return this .toNumber(o);
420:
421: }
422:
423: public Number toNumber(Object o) {
424:
425: if (o == null) {
426:
427: return null;
428:
429: }
430:
431: if (o instanceof String) {
432:
433: // Try and parse as a double.
434: try {
435:
436: return new Double((String) o);
437:
438: } catch (Exception e) {
439:
440: // Ignore? Maybe have an option...
441:
442: }
443:
444: }
445:
446: if (o instanceof Date) {
447:
448: return new Double(((Date) o).getTime());
449:
450: }
451:
452: if (!(o instanceof Number)) {
453:
454: return null;
455:
456: }
457:
458: return (Number) o;
459:
460: }
461:
462: }
|