001: /*
002: * @(#)Configuration.java 1.7 05/06/27
003: *
004: * Copyright (c) 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.lang;
010:
011: import java.io.ObjectInputStream;
012: import java.io.Serializable;
013: import java.io.IOException;
014: import java.lang.reflect.Constructor;
015: import java.lang.reflect.InvocationTargetException;
016: import java.lang.reflect.Method;
017: import java.util.Enumeration;
018: import java.util.HashMap;
019: import java.util.Map;
020: import java.util.List;
021: import java.util.AbstractList;
022: import java.util.RandomAccess;
023: import java.util.Arrays;
024: import java.util.ArrayList;
025: import java.math.BigDecimal;
026: import java.math.BigInteger;
027: import java.util.Properties;
028: import org.pnuts.util.*;
029: import org.pnuts.lang.*;
030:
031: /**
032: * This class defines the interface of runtime configuration, such as how to
033: * find method/field candidates, how to get the field value, how to get indexed
034: * elements, and so on.
035: */
036: public abstract class Configuration implements Serializable {
037:
038: static final long serialVersionUID = 8561037106846360504L;
039:
040: /**
041: * The normal configuration, which is the fall-back of the default
042: * configuration.
043: */
044: protected final static Configuration normalConfiguration;
045:
046: /**
047: * The default configuration, which can be configured with the system
048: * property "pnuts.lang.defaultConfiguration" at start-up time
049: */
050: private static Configuration defaultConfiguration;
051:
052: static {
053: normalConfiguration = ConfigurationConstants.NORMAL_CONFIGURATION;
054: defaultConfiguration = getInstance(Runtime
055: .getProperty("pnuts.lang.defaultConfiguration"));
056: }
057:
058: /**
059: * object1 + object2
060: */
061: protected BinaryOperator _add;
062:
063: /**
064: * object1 - object2
065: */
066: protected BinaryOperator _subtract;
067:
068: /**
069: * object1 * object2
070: */
071: protected BinaryOperator _multiply;
072:
073: /**
074: * object1 % object2
075: */
076: protected BinaryOperator _mod;
077:
078: /**
079: * object1 / object2
080: */
081: protected BinaryOperator _divide;
082:
083: /**
084: * object1 >>> object2
085: */
086: protected BinaryOperator _shiftArithmetic;
087:
088: /**
089: * object1 < < object2
090: */
091: protected BinaryOperator _shiftLeft;
092:
093: /**
094: * object1 >> object2
095: */
096: protected BinaryOperator _shiftRight;
097:
098: /**
099: * object1 & object2
100: */
101: protected BinaryOperator _and;
102:
103: /**
104: * object1 | object2
105: */
106: protected BinaryOperator _or;
107:
108: /**
109: * object1 ^ object2
110: */
111: protected BinaryOperator _xor;
112:
113: /**
114: * object++, ++object
115: */
116: protected UnaryOperator _add1;
117:
118: /**
119: * object--, object--
120: */
121: protected UnaryOperator _subtract1;
122:
123: /**
124: * ~object
125: */
126: protected UnaryOperator _not;
127:
128: /**
129: * - object
130: */
131: protected UnaryOperator _negate;
132:
133: /**
134: * object1 == object2
135: */
136: protected BooleanOperator _eq;
137:
138: /**
139: * object1 < object2
140: */
141: protected BooleanOperator _lt;
142:
143: /**
144: * object1 <= object2
145: */
146: protected BooleanOperator _le;
147:
148: /**
149: * object1 > object2
150: */
151: protected BooleanOperator _gt;
152:
153: /**
154: * object1 >= object2
155: */
156: protected BooleanOperator _ge;
157:
158: /**
159: * Default imports
160: */
161: String[] _imports;
162:
163: private final static String[] DEFAULT_IMPORTS = new String[] { "*",
164: "java.lang.*" };
165:
166: /**
167: * Returns the default Configuration object.
168: *
169: * @return the current default configuration
170: */
171: public static Configuration getDefault() {
172: return defaultConfiguration;
173: }
174:
175: static Configuration getDefault(Properties properties) {
176: String property = properties
177: .getProperty("pnuts.lang.defaultConfiguration");
178: return getInstance(property);
179: }
180:
181: static Configuration getInstance(String className) {
182: try {
183: if (className != null
184: && !className.equals("pnuts.lang.Configuration")) {
185: Class cls = Class.forName(className);
186: return (Configuration) cls.newInstance();
187: }
188: } catch (Exception e2) {
189: /* ignore */
190: }
191: return normalConfiguration;
192: }
193:
194: public Configuration() {
195: initializeOperators();
196: }
197:
198: /**
199: * Subclasses may redefines default imports
200: *
201: * @return an array of imported classes, package, or statics
202: */
203: protected String[] getDefaultImports() {
204: return DEFAULT_IMPORTS;
205: }
206:
207: protected void initializeOperators() {
208: this ._add = BinaryOperator.Add.instance;
209: this ._subtract = BinaryOperator.Subtract.instance;
210: this ._multiply = BinaryOperator.Multiply.instance;
211: this ._mod = BinaryOperator.Mod.instance;
212: this ._divide = BinaryOperator.Divide.instance;
213: this ._shiftArithmetic = BinaryOperator.ShiftArithmetic.instance;
214: this ._shiftLeft = BinaryOperator.ShiftLeft.instance;
215: this ._shiftRight = BinaryOperator.ShiftRight.instance;
216: this ._and = BinaryOperator.And.instance;
217: this ._or = BinaryOperator.Or.instance;
218: this ._xor = BinaryOperator.Xor.instance;
219: this ._add1 = UnaryOperator.Add1.instance;
220: this ._subtract1 = UnaryOperator.Subtract1.instance;
221: this ._not = UnaryOperator.Not.instance;
222: this ._negate = UnaryOperator.Negate.instance;
223: this ._eq = BooleanOperator.EQ.instance;
224: this ._lt = BooleanOperator.LT.instance;
225: this ._le = BooleanOperator.LE.instance;
226: this ._gt = BooleanOperator.GT.instance;
227: this ._ge = BooleanOperator.GE.instance;
228: }
229:
230: /**
231: * Get the value of a static field.
232: *
233: * @param context
234: * the context in which the field is accessed
235: * @param clazz
236: * the class in which the static field is defined
237: * @param name
238: * the name of the static field
239: * @return the value
240: */
241: public abstract Object getStaticField(Context context, Class clazz,
242: String name);
243:
244: /**
245: * Sets a value to the static field of the specified class.
246: *
247: * @param context
248: * the context in which the field is written.
249: * @param clazz
250: * the class in which the static field is defined
251: * @param name
252: * the field name
253: * @param value
254: * the field value
255: */
256: public abstract void putStaticField(Context context, Class clazz,
257: String name, Object value);
258:
259: /**
260: * Gets an array element
261: *
262: * @param context
263: * the context
264: * @param target
265: * the target object (an array)
266: * @param key
267: * the key or the index of the element
268: * @return the value of the element
269: */
270: public abstract Object getElement(Context context, Object target,
271: Object key);
272:
273: /**
274: * Sets an element
275: *
276: * @param context
277: * the context
278: * @param target
279: * the target object (an array)
280: * @param key
281: * the key or the index of the element
282: * @param value
283: * the new value of the element
284: */
285: public abstract void setElement(Context context, Object target,
286: Object key, Object value);
287:
288: /**
289: * Calls a method
290: *
291: * @param context
292: * the contexct
293: * @param c
294: * the class of the method
295: * @param name
296: * the name of the method
297: * @param args
298: * arguments
299: * @param types
300: * type information of each arguments
301: * @param target
302: * the target object of the method call
303: * @return the result of the method call
304: */
305: public abstract Object callMethod(Context context, Class c,
306: String name, Object args[], Class types[], Object target);
307:
308: /**
309: * Calls a constructor
310: *
311: * @param context
312: * the context
313: * @param c
314: * class of the constructor
315: * @param args
316: * the arguments
317: * @param types
318: * type information of each arguments
319: * @return the result
320: */
321: public abstract Object callConstructor(Context context, Class c,
322: Object[] args, Class[] types);
323:
324: /**
325: * Get all public methods of the specified class.
326: *
327: * @param cls
328: * the class
329: * @return an array of Method objects
330: */
331: public abstract Method[] getMethods(Class cls);
332:
333: /**
334: * Get all public constructors of the specified class.
335: *
336: * @param cls
337: * the class
338: * @return an array of Constructor objects
339: */
340: public abstract Constructor[] getConstructors(Class cls);
341:
342: /**
343: * Defines the semantices of an expression like: <blockquote>
344: *
345: * <pre>
346: *
347: * target[idx1..idx2]
348: *
349: * </pre>
350: *
351: * </blockquote>
352: *
353: * @param context
354: * the context
355: * @param target
356: * the target object
357: * @param idx1
358: * the start index
359: * @param idx2
360: * the end index. null in idx2 means open-ended.
361: * @return the result
362: */
363: public abstract Object getRange(Context context, Object target,
364: Object idx1, Object idx2);
365:
366: /**
367: * Defines the semantices of an expression like: <blockquote>
368: *
369: * <pre>
370: *
371: * target[idx1..idx2] = value
372: *
373: * </pre>
374: *
375: * </blockquote>
376: *
377: * @param context
378: * the context in which the assignment is done
379: * @param target
380: * the target object
381: * @param idx1
382: * the start index
383: * @param idx2
384: * the end index. null in idx2 means open-ended.
385: * @param value
386: * the new value of the indexed element
387: * @return the result
388: */
389: public abstract Object setRange(Context context, Object target,
390: Object idx1, Object idx2, Object value);
391:
392: /**
393: * Gets a field value of the target object.
394: *
395: * @param context
396: * the context in which the field is read
397: * @param target
398: * the target object
399: * @param name
400: * the field name
401: * @return the field value
402: */
403: public abstract Object getField(Context context, Object target,
404: String name);
405:
406: /**
407: * Sets a field value of the specified object.
408: *
409: * @param context
410: * the context in which the field is written.
411: * @param target
412: * the target object
413: * @param name
414: * the field name
415: * @param value
416: * the field value
417: */
418: public abstract void putField(Context context, Object target,
419: String name, Object value);
420:
421: /**
422: * Convert an object to Enumeration. This method is used by foreach
423: * statements. Subclasses can override this method to customize the behavior
424: * of foreach statements.
425: */
426: public abstract Enumeration toEnumeration(Object obj);
427:
428: /**
429: * Convert an object to Callable. This method is used by call expression, e.g. obj(arg1, ...).
430: * Subclasses can override this method to register custom callable objects.
431: */
432: public abstract Callable toCallable(Object obj);
433:
434: /**
435: * Handle an "not.defined" error
436: *
437: * This method can be redefined by a subclass so that a special value (e.g.
438: * null) is returned when undefined symbol is referenced.
439: *
440: * @param symbol
441: * the undefined symbol
442: * @param context
443: * the context in which the symbol is referenced
444: * @return the value to be returned
445: */
446: public Object handleUndefinedSymbol(String symbol, Context context) {
447: throw new PnutsException("not.defined",
448: new Object[] { symbol }, context);
449: }
450:
451: /**
452: * Return the value of an array expression. e.g. [a,b,c] {1,2,3}
453: *
454: * This method can be redefined by a subclass so that array expression
455: * returns different type of object, such as java.util.List.
456: *
457: * @param parameters
458: * the elements in the array expression
459: * @return the value of the array expression
460: */
461: public Object makeArray(Object[] parameters, Context context) {
462: return parameters;
463: }
464:
465: /**
466: * Create a new Map object that corresponds to {key=>value} expression.
467: *
468: * @param size
469: * the map size
470: * @return a new Map object
471: */
472: public Map createMap(int size, Context context) {
473: return new HashMap(size);
474: }
475:
476: public List createList() {
477: return new ComparableArrayList();
478: }
479:
480: /**
481: * Defines how objects are printed in the interactive shell.
482: *
483: * @param obj
484: * the target object to print
485: * @return the string representation of the target object
486: */
487: public String formatObject(Object obj) {
488: return Runtime.format(obj, 64);
489: }
490:
491: protected static Object invokeMethod(Context context, Class c,
492: String name, Object args[], Class types[], Object target) {
493: return context.runtime._callMethod(context, c, name, args,
494: types, target);
495: }
496:
497: /*
498: * class <-> public methods
499: */
500: private transient Cache mtab = new MemoryCache();
501:
502: synchronized Method[] _getMethods(Class cls, String name) {
503: Cache cache = (Cache) mtab.get(cls);
504: if (cache == null) {
505: cache = new MemoryCache();
506: mtab.put(cls, cache);
507: }
508: Object v = cache.get(name);
509: if (v instanceof Method[]) {
510: return (Method[]) v;
511: } else {
512: Method m[] = getMethods(cls);
513: if (m == null) { // for Bug:4137722
514: throw new NoClassDefFoundError("" + cls);
515: }
516: int j = 0;
517: for (int i = 0; i < m.length; i++) {
518: String m_name = m[i].getName();
519: if (m_name.equals(name) && i >= j) {
520: m[j] = m[i];
521: j++;
522: }
523: }
524: Method m2[] = new Method[j];
525: System.arraycopy(m, 0, m2, 0, j);
526: cache.put(name, m2);
527: return m2;
528: }
529: }
530:
531: /*
532: * class <-> Constructors
533: */
534: private transient Cache ctab = new MemoryCache();
535:
536: synchronized Constructor[] _getConstructors(Class cls) {
537: Object v = ctab.get(cls);
538: if (v instanceof Constructor[]) {
539: return (Constructor[]) v;
540: } else {
541: Constructor con[] = getConstructors(cls);
542: ctab.put(cls, con);
543: return con;
544: }
545: }
546:
547: Object reInvoke(IllegalAccessException t, Method method,
548: Object target, Object[] args)
549: throws IllegalAccessException, IllegalArgumentException,
550: InvocationTargetException {
551: return normalConfiguration.reInvoke(t, method, target, args);
552: }
553:
554: protected ClassLoader getInitialClassLoader() {
555: return null;
556: }
557:
558: void replace(StringBuffer buf, int start, int end, String str) {
559: normalConfiguration.replace(buf, start, end, str);
560: }
561:
562: BigDecimal longToBigDecimal(long lval) {
563: return new BigDecimal(BigInteger.valueOf(lval));
564: }
565:
566: private void readObject(ObjectInputStream s) throws IOException,
567: ClassNotFoundException {
568: s.defaultReadObject();
569: mtab = new MemoryCache();
570: ctab = new MemoryCache();
571: }
572: }
|