Source code: com/tripi/asp/Types.java
1 /**
2 * ArrowHead ASP Server
3 * This is a source file for the ArrowHead ASP Server - an 100% Java
4 * VBScript interpreter and ASP server.
5 *
6 * For more information, see http://www.tripi.com/arrowhead
7 *
8 * Copyright (C) 2002 Terence Haddock
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25 package com.tripi.asp;
26
27 import java.util.Date;
28 import java.util.Enumeration;
29 import java.util.Vector;
30
31 import jregex.Pattern;
32 import jregex.Replacer;
33
34 import org.apache.log4j.Category;
35
36 /**
37 * The Types class contains utilities for conversion between data types.
38 *
39 * @author Terence Haddock
40 * @version 0.9
41 */
42 public class Types
43 {
44 /** Debugging instance */
45 static private final Category DBG = Category.getInstance(Types.class);
46
47 /**
48 * Coerces a data type into an Integer type.
49 * <ul>
50 * <li><i>null</i> = 0
51 * <li><i>undefined</i> = 0
52 * <li><i>Integer</i> = self
53 * <li><i>Double</i> = Cast to integer
54 * <li><i>String</i> = Parsed to integer, errors are passed through
55 * <li>Everything else causes a AspCastException
56 * </ul>
57 *
58 * @param obj Object to cast
59 * @return Integer representation of the cast.
60 * @throws AspException if an error occurs.
61 */
62 static public Integer coerceToInteger(Object obj) throws AspException
63 {
64 if (obj instanceof SimpleReference)
65 {
66 return coerceToInteger(((SimpleReference)obj).getValue());
67 } else
68 if (obj == null || obj instanceof NullNode ||
69 obj instanceof UndefinedValueNode)
70 {
71 return new Integer(0);
72 } else if (obj instanceof Integer)
73 {
74 return (Integer)obj;
75 } else if (obj instanceof Double)
76 {
77 return new Integer((int)((Double)obj).doubleValue());
78 } else if (obj instanceof Long)
79 {
80 return new Integer((int)((Long)obj).doubleValue());
81 } else if (obj instanceof Short)
82 {
83 return new Integer((int)((Short)obj).doubleValue());
84 } else if (obj instanceof Boolean)
85 {
86 boolean boolValue = ((Boolean)obj).booleanValue();
87 if (boolValue) return new Integer(-1);
88 return new Integer(0);
89 } else if (obj instanceof String)
90 {
91 String strValue = ((String)obj).trim();
92 if (strValue.equals("")) return new Integer(0);
93 try {
94 return new Integer(strValue);
95 } catch (NumberFormatException ex) {
96 throw new AspCastException(ex.toString());
97 }
98 } else {
99 throw new AspCastException(obj.getClass().toString());
100 }
101 }
102
103 /**
104 * Coerces an object to a string.
105 * <ul>
106 * <li><i>null</i> = ""
107 * <li><i>undefined</i> = ""
108 * <li><i>String</i> = self
109 * <li><i>Integer</i> = cast to string
110 * <li><i>Boolean</i> = cast to "true"/"false"
111 * </ul>
112 *
113 * @param obj Object to cast to string.
114 * @return Object casted to string
115 * @throws AspException is a casting error occurs.
116 */
117 static public String coerceToString(Object obj) throws AspException
118 {
119 if (obj instanceof SimpleReference)
120 {
121 return coerceToString(((SimpleReference)obj).getValue());
122 } else
123 if (obj == null || obj instanceof NullNode ||
124 obj instanceof UndefinedValueNode)
125 {
126 return "";
127 } else if (obj instanceof String)
128 {
129 return (String)obj;
130 } else if (obj instanceof Integer)
131 {
132 return obj.toString();
133 } else if (obj instanceof Boolean)
134 {
135 Boolean b = (Boolean)obj;
136 if (b.booleanValue()) return "True";
137 return "False";
138 } else if (obj instanceof Double)
139 {
140 /* If a double value contains an integer number, do not print
141 decimal places. */
142 Double doub = (Double)obj;
143 if (DBG.isDebugEnabled())
144 {
145 DBG.debug("int value: " + doub.intValue());
146 DBG.debug("doub value: " + doub.doubleValue());
147 }
148 if (doub.intValue() == doub.doubleValue())
149 return "" + doub.intValue();
150 return doub.toString();
151 } else if (obj instanceof AspDate)
152 {
153 AspDate date = (AspDate)obj;
154 return date.toString();
155 } else if (obj instanceof JavaObjectNode)
156 {
157 return coerceToString(((JavaObjectNode)obj).
158 getSubObject());
159 } else {
160 //throw new AspCastException(obj.getClass().toString());
161 return obj.toString();
162 }
163 }
164
165 /**
166 * Converts a data object to a boolean type.
167 * <ul>
168 * <li><i>null</i> = false
169 * <li><i>undefined</i> = false
170 * <li><i>Boolean</i> = self
171 * </ul>
172 *
173 * @param obj Object to cast.
174 * @return boolean value of object.
175 * @throws AspException if exception occurs.
176 */
177 static Boolean coerceToBoolean(Object obj) throws AspException
178 {
179 if (DBG.isDebugEnabled()) {
180 DBG.debug("coerceToBoolean: " + obj);
181 }
182 if (obj instanceof SimpleReference)
183 {
184 return coerceToBoolean(((SimpleReference)obj).getValue());
185 } else
186 if (obj == null || obj instanceof NullNode ||
187 obj instanceof UndefinedValueNode) {
188 return new Boolean(false);
189 } else if (obj instanceof Boolean)
190 {
191 return (Boolean)obj;
192 } else if (obj instanceof String)
193 {
194 String str = (String)obj;
195 if (str.equalsIgnoreCase("true"))
196 return new Boolean(true);
197 else if (str.equalsIgnoreCase("false"))
198 return new Boolean(false);
199 else
200 return new Boolean(coerceToInteger(obj).intValue() != 0);
201 } else {
202 return new Boolean(coerceToInteger(obj).intValue() != 0);
203 }
204 }
205
206 /**
207 * Casts an object to a double value.
208 * <ul>
209 * <li><i>null</i> - 0.0
210 * <li><i>undefined</i> - 0.0
211 * <li><i>Double</i> - self
212 * <li><i>Integer</i> - Casted to double
213 * <li><i>String</i> - Parsed to double
214 * </ul>
215 *
216 * @param obj Object to cast to double.
217 * @return obj as a double value.
218 * @throws AspException if an error occurs.
219 */
220 static Double coerceToDouble(Object obj) throws AspException
221 {
222 if (obj instanceof SimpleReference)
223 {
224 return coerceToDouble(((SimpleReference)obj).getValue());
225 } else
226 if (obj == null || obj instanceof NullNode)
227 {
228 throw new AspCastException("NULL");
229 } else if (obj instanceof UndefinedValueNode)
230 {
231 return new Double(0);
232 } else
233 if (obj instanceof Double)
234 {
235 return (Double)obj;
236 } else if (obj instanceof Integer)
237 {
238 return new Double((double)((Integer)obj).intValue());
239 } else if (obj instanceof Long)
240 {
241 return new Double((double)((Long)obj).intValue());
242 } else if (obj instanceof Short)
243 {
244 return new Double((double)((Short)obj).intValue());
245 } else if (obj instanceof String)
246 {
247 try {
248 String str = (String)obj;
249 if (str.indexOf(",") != -1)
250 {
251 /* Have to ignore commas */
252 final Pattern p = new Pattern(",");
253 /* XXX It would be nice to make Replacer final, but there is no
254 mention of the thread safely of replacer */
255 Replacer r = p.replacer("");
256 str = r.replace((String)obj);
257 }
258 return new Double(str);
259 } catch (NumberFormatException ex) {
260 throw new AspCastException(ex.toString());
261 }
262 } else if (obj instanceof Boolean) {
263 Boolean b = (Boolean)obj;
264 if (b.booleanValue()) return new Double(-1);
265 return new Double(0);
266 } else {
267 if (DBG.isDebugEnabled()) {
268 DBG.debug("Cast Exception for object: " + obj);
269 }
270 throw new AspCastException(obj.getClass().toString());
271 }
272 }
273
274 /**
275 * Coerces a data value to a Date value.
276 * <ul>
277 * <li><i>Date</i> - Self
278 * </ul>
279 *
280 * @param obj Object to convert to date.
281 * @return obj casted to a date value
282 * @throws AspException if the type cannot be casted.
283 */
284 static AspDate coerceToDate(Object obj) throws AspException
285 {
286 if (obj instanceof SimpleReference)
287 {
288 return coerceToDate(((SimpleReference)obj).getValue());
289 } else if (obj instanceof AspDate)
290 {
291 return (AspDate)obj;
292 } else if (obj instanceof Date)
293 {
294 return new AspDate((Date)obj);
295 } else {
296 String objStr = coerceToString(obj).trim();
297 return new AspDate(objStr);
298 }
299 }
300
301 /**
302 * Coerces an object to a "node".
303 * All of the known base types (Integer, Boolean, Double, String)
304 * are left as-is, but other Java objects are wrapped into
305 * a JavaObjectNode-type class to handle ASP->Java calls.
306 * <ul>
307 * <li><i>null</i> - null
308 * <li><i>Node</i> - self
309 * <li><i>Double</i> - self
310 * <li><i>Integer</i> - self
311 * <li><i>Boolean</i> - self
312 * <li><i>Byte</i> - self
313 * <li><i>String</i> - self
314 * <li><i>SimpleMap + SimpleReference</i> - Wrapped in a JavaReferenceMapNode
315 * <li><i>SimpleMap</i> - Wrapped in a JavaMapNode
316 * <li><i>SimpleReference</i> - Wrapped in a JavaReferenceNode
317 * <li>Other - Wrapped in a JavaObjectNode
318 * </ul>
319 *
320 * @param obj Object to map
321 * @return Node object, or base type.
322 * @throws AspException if a casting error occurs
323 */
324 static Object coerceToNode(Object obj) throws AspException
325 {
326 if (DBG.isDebugEnabled())
327 DBG.debug("coerceToNode: " + obj);
328 if (obj == null) {
329 if (DBG.isDebugEnabled())
330 DBG.debug("=null");
331 return Constants.undefinedValueNode;
332 } else if (obj instanceof Node) {
333 if (DBG.isDebugEnabled())
334 DBG.debug("=Node");
335 return obj;
336 } else if (obj instanceof Double) {
337 if (DBG.isDebugEnabled())
338 DBG.debug("=Double");
339 return obj;
340 } else if (obj instanceof Integer) {
341 if (DBG.isDebugEnabled())
342 DBG.debug("=Integer");
343 return obj;
344 } else if (obj instanceof Long) {
345 if (DBG.isDebugEnabled())
346 DBG.debug("=Long");
347 return obj;
348 } else if (obj instanceof Boolean) {
349 if (DBG.isDebugEnabled())
350 DBG.debug("=Boolean");
351 return obj;
352 } else if (obj instanceof Short) {
353 if (DBG.isDebugEnabled())
354 DBG.debug("=Short");
355 return obj;
356 } else if (obj instanceof Byte) {
357 return new Integer(((Byte)obj).byteValue());
358 } else if (obj instanceof String) {
359 if (DBG.isDebugEnabled())
360 DBG.debug("=String");
361 return obj;
362 // XXX Problem with objects like java.sql.Timestamp
363 //} else if (obj instanceof java.util.Date) {
364 // return new AspDate((java.util.Date)obj);
365 } else if (obj instanceof SimpleMap) {
366 if (obj instanceof SimpleReference) {
367 if (DBG.isDebugEnabled())
368 DBG.debug("=ObjectReferenceMap(" +
369 obj.toString() + ")");
370 return new JavaReferenceMapNode(obj);
371 }
372 if (DBG.isDebugEnabled())
373 DBG.debug("=ObjectMap(" + obj.toString() + ")");
374 return new JavaMapNode((SimpleMap)obj);
375 } else if (obj instanceof SimpleReference) {
376 if (DBG.isDebugEnabled())
377 DBG.debug("=ObjectReference(" + obj.toString() + ")");
378 return new JavaReferenceNode((SimpleReference)obj);
379 } else {
380 if (DBG.isDebugEnabled())
381 DBG.debug("=Object(" + obj.toString() + ")");
382 /* Test for character array */
383 if (obj.getClass().isArray())
384 {
385 if (obj.getClass().getComponentType() == char.class) {
386 return new PackedCharArrayNode((char[])obj);
387 }
388 else if (obj.getClass().getComponentType() == byte.class) {
389 return new PackedByteArrayNode((byte[])obj);
390 }
391 }
392 return new JavaObjectNode(obj);
393 }
394 }
395
396 /**
397 * Coerce a type to a SimpleMap object.
398 * @param obj Object to coerce.
399 * @return SimpleMap object.
400 */
401 //public static SimpleMap coerceToMap(Object obj) throws AspException
402 //{
403 // while (obj instanceof SimpleReference &&
404 // !(obj instanceof SimpleMap))
405 // {
406 // if (DBG.isDebugEnabled()) DBG.debug("Dereferencing: "
407 // + obj);
408 // obj = ((SimpleReference)obj).getValue();
409 // }
410 // if (obj instanceof SimpleMap) return (SimpleMap)obj;
411 // throw new AspCastException("Map");
412 //}
413
414 /**
415 * Obtains an integer value from a hex string line &FF.
416 * @param str String to convert
417 * @return Integer value of string
418 */
419 static public Integer integerFromHex(String str)
420 {
421 return new Integer(Integer.parseInt(str.substring(2),16));
422 }
423
424 /**
425 * Determines if this object is a number.
426 * @param obj Object to test
427 * @return <b>true</b> if this object is a number, <b>false</b> otherwise.
428 */
429 static public boolean isNumber(Object obj)
430 throws AspException
431 {
432 Object deref = dereference(obj);
433 if (deref instanceof Integer) return true;
434 if (deref instanceof Double) return true;
435 if (deref instanceof Long) return true;
436 return false;
437 }
438
439 /**
440 * Derefernces the given object. If the object is a SimpleReference
441 * object, it will dereference it, and keep dereferencing it until
442 * a non-SimpleReference object is found.
443 * @param obj Object to dereference.
444 * @return Non-SimpleReference object.
445 */
446 public static Object dereference(Object obj) throws AspException
447 {
448 while (obj instanceof SimpleReference) {
449 if (DBG.isDebugEnabled())
450 DBG.debug("Dereferencing: " + obj);
451 obj = ((SimpleReference)obj).getValue();
452 }
453 return obj;
454 }
455
456 /**
457 * This function tests an object to see if it is a date object.
458 * @param testObject object to test
459 * @return <b>true</b> if this is a date object, <b>false</b> otherwise.
460 */
461 public static boolean isDate(Object testObject)
462 {
463 return testObject instanceof AspDate;
464 }
465 }