001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.convert;
025:
026: import jacareto.struct.StructureElement;
027: import jacareto.system.Environment;
028: import jacareto.toolkit.EnhancedHashtable;
029: import jacareto.toolkit.PriorityList;
030:
031: import java.lang.reflect.Constructor;
032: import java.lang.reflect.InvocationTargetException;
033:
034: import java.util.Enumeration;
035: import java.util.Iterator;
036:
037: /**
038: * This converter selects a registered converter for a given object.
039: *
040: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
041: * @author <a href="mailto:markus.bois@web.de">Markus Bois</a>
042: * @version 1.02
043: */
044: public class SelectionConverter extends Converter {
045: /** Load the converters from the customization at the beginning. */
046: public static final int INIT_CUSTOM = 0;
047:
048: /** There should no converters be added at the beginning. */
049: public static final int INIT_EMPTY = 1;
050:
051: /** List of all registered converters. */
052: private PriorityList converters;
053:
054: /**
055: * Creates a new selection converter with the default class loader to load the converters.
056: *
057: * @param env the environment
058: * @param customizationKey the key of the customization map for this selection converter
059: * @param init {@link #INIT_CUSTOM} or {@link #INIT_EMPTY}
060: */
061: public SelectionConverter(Environment env, String customizationKey,
062: int init) {
063: this (env, customizationKey, init, null);
064: }
065:
066: /**
067: * Creates a new selection converter.
068: *
069: * @param env the environment
070: * @param customizationKey the key of the customization map for this selection converter
071: * @param init {@link #INIT_CUSTOM} or {@link #INIT_EMPTY}
072: * @param classLoader the class loader which should be used when loading converters
073: */
074: public SelectionConverter(Environment env, String customizationKey,
075: int init, ClassLoader classLoader) {
076: super (env);
077: converters = new PriorityList();
078:
079: if (classLoader != null) {
080: setClassLoader(classLoader);
081: }
082:
083: if (init == INIT_CUSTOM) {
084: loadConverters(customizationKey, classLoader);
085: }
086: }
087:
088: /**
089: * Registers a Converter with the specified priority. A greater value of priority symbolizes a
090: * higher priority.
091: *
092: * @param converter the converter to add
093: * @param priority the priority
094: */
095: public void addConverter(Converter converter, int priority) {
096: if (priority >= 0) {
097: converters.add(converter, priority);
098: } else {
099: converters.add(converter);
100: }
101: }
102:
103: /**
104: * Registers a Converter with the lowest priority.
105: *
106: * @param converter the converter to add
107: */
108: public void addConverter(Converter converter) {
109: addConverter(converter, -1);
110: }
111:
112: /**
113: * Returns an iterator on all registered converters, sorted by priority. The converter with the
114: * highest priority comes first.
115: *
116: * @return the iterator;
117: */
118: public Iterator convertersIterator() {
119: return converters.iterator();
120: }
121:
122: /**
123: * Returns whether this converter is able to transform the specified structure element to an
124: * other representation. A selection converter handles a element if a registered converter
125: * handles it.
126: *
127: * @param element the structure element
128: *
129: * @return <code>true</code> if this converter is responsible for this structure element;
130: * otherwise <code>false</code>.
131: */
132: public boolean handlesElement(StructureElement element) {
133: boolean result = false;
134: Iterator it = convertersIterator();
135:
136: while (it.hasNext() && !result) {
137: Converter tmp = (Converter) it.next();
138: result |= tmp.handlesElement(element);
139: }
140:
141: return result;
142: }
143:
144: /**
145: * Converts the specified element to an other representation. The precondition for this method
146: * is that the converter handles the given structure element.
147: *
148: * @param element the structure element to convert
149: *
150: * @return the other representation
151: */
152: public Object convertElement(StructureElement element) {
153: Converter converter = getConverterForElement(element);
154:
155: if (converter != null) {
156: return converter.convertElement(element);
157: }
158:
159: logger
160: .warn(language
161: .getString("Convert.SelectionConverter.Msg.NoConverter")
162: + " " + element.getElementName());
163:
164: return null;
165: }
166:
167: /**
168: * Returns whether this converter is able to transform the specified other representation to a
169: * structure element. A selection converter handles a representation if a registered converter
170: * handles it.
171: *
172: * @param other the other representation
173: *
174: * @return <code>true</code> if this converter is responsible for this other representation;
175: * otherwise <code>false</code>.
176: */
177: public boolean handlesOther(Object other) {
178: boolean result = false;
179: Iterator it = convertersIterator();
180:
181: while (it.hasNext() && !result) {
182: Converter tmp = (Converter) it.next();
183: result |= tmp.handlesOther(other);
184: }
185:
186: return result;
187: }
188:
189: /**
190: * Converts the specified other representation to a structure element. The precondition for
191: * this method is that the converter handles the given other representation.
192: *
193: * @param other the other representation to convert
194: *
195: * @return the structure element
196: */
197: public StructureElement convertOther(Object other) {
198: return getConverterForOther(other).convertOther(other);
199: }
200:
201: /**
202: * Returns the first converter which feels responsible for the given element. If no converter
203: * is responsible, <code>null</code> will be returned
204: *
205: * @param element the structure element.
206: *
207: * @return the first converter which feels responsible, or <code>null</code> if no converter is
208: * responsible.
209: */
210: protected Converter getConverterForElement(StructureElement element) {
211: Converter converter;
212: Iterator i = convertersIterator();
213:
214: while (i.hasNext()) {
215: converter = (Converter) i.next();
216:
217: if (converter.handlesElement(element)) {
218: return converter;
219: }
220: }
221:
222: return null;
223: }
224:
225: /**
226: * Returns the first converter which feels responsible for the given other representation. If
227: * no converter is responsible, <code>null</code> will be returned
228: *
229: * @param other the other representation
230: *
231: * @return the first converter which feels responsible, or <code>null</code> if no converter is
232: * responsible.
233: */
234: protected Converter getConverterForOther(Object other) {
235: if (other != null) {
236: Converter converter;
237: Iterator i = convertersIterator();
238:
239: while (i.hasNext()) {
240: converter = (Converter) i.next();
241:
242: if (converter.handlesOther(other)) {
243: return converter;
244: }
245: }
246: }
247:
248: return null;
249: }
250:
251: /**
252: * Loads the specific converters from the {@link jacareto.system.Customization} instance of the
253: * {@link jacareto.system.Environment} object with the default class loader.
254: *
255: * @param customizationKey the key of the customization element which is the map of the
256: * converters to the priorities
257: */
258: protected void loadConverters(String customizationKey) {
259: loadConverters(customizationKey, null);
260: }
261:
262: /**
263: * Loads the specific converters from the {@link jacareto.system.Customization} instance of the
264: * {@link jacareto.system.Environment} object with the given class loader.
265: *
266: * @param customizationKey the key of the customization element which is the map of the
267: * converters to the priorities
268: * @param classLoader the class loader to use
269: */
270: protected void loadConverters(String customizationKey,
271: ClassLoader classLoader) {
272: try {
273: Class converterClass = Class
274: .forName("jacareto.convert.RecursiveConverter");
275: Class[] parameterTypes;
276: Object[] parameters;
277:
278: if (classLoader == null) {
279: if (getClassLoader() != null) {
280: classLoader = getClassLoader();
281: } else {
282: classLoader = ClassLoader.getSystemClassLoader();
283: }
284: }
285:
286: // load the map of converters
287: EnhancedHashtable convertersMap = getCustomization()
288: .getMap(customizationKey, new EnhancedHashtable());
289: Enumeration enumeration = convertersMap.keys();
290:
291: while (enumeration.hasMoreElements()) {
292: String constructorType = "";
293: int priority = 0;
294:
295: String converterClassName = (String) enumeration
296: .nextElement();
297: String converterAttributes = convertersMap.getString(
298: converterClassName, "");
299:
300: if (!converterAttributes.equals("")) {
301: constructorType = getCustomization().getString(
302: converterAttributes + ".Constructor", "");
303: priority = getCustomization().getInt(
304: converterAttributes + ".Priority", 0);
305: logger
306: .debug(language
307: .getString("Convert.SelectionConverter.Msg.AttributesFound")
308: + " " + converterClassName);
309: }
310:
311: // some reflection instances
312: if (constructorType.equals("Recursive")) {
313: converterClass = Class.forName(
314: "jacareto.convert.RecursiveConverter",
315: true, classLoader);
316: parameterTypes = new Class[2];
317: parameterTypes[0] = Class.forName(
318: "jacareto.system.Environment", true,
319: classLoader);
320: parameterTypes[1] = Class.forName(
321: "jacareto.convert.SelectionConverter",
322: true, classLoader);
323: parameters = new Object[2];
324: parameters[0] = env;
325: parameters[1] = this ;
326: } else {
327: converterClass = Class.forName(
328: "jacareto.convert.Converter", true,
329: classLoader);
330: parameterTypes = new Class[1];
331: parameterTypes[0] = Class.forName(
332: "jacareto.system.Environment", true,
333: classLoader);
334: parameters = new Object[1];
335: parameters[0] = env;
336: }
337:
338: try {
339: Class concreteConverterClass = Class.forName(
340: converterClassName, true, classLoader);
341: Constructor converterConstructor = concreteConverterClass
342: .getConstructor(parameterTypes);
343:
344: if (converterClass
345: .isAssignableFrom(concreteConverterClass)) {
346: try {
347: logger
348: .debug(language
349: .getString("Convert.SelectionConverter.Msg.Loading")
350: + " " + converterClassName);
351:
352: Converter newConverter = (Converter) converterConstructor
353: .newInstance(parameters);
354: newConverter.setClassLoader(classLoader);
355: addConverter(newConverter, priority);
356: } catch (InstantiationException inst) {
357: logger
358: .debug(
359: language
360: .getString("Convert.SelectionConverter.Error.Construction"),
361: inst);
362: } catch (IllegalAccessException ill) {
363: logger
364: .debug(
365: language
366: .getString("Convert.SelectionConverter.Error.Construction"),
367: ill);
368: } catch (IllegalArgumentException ila) {
369: logger
370: .debug(
371: language
372: .getString("Convert.SelectionConverter.Error.Construction"),
373: ila);
374: } catch (InvocationTargetException inv) {
375: logger
376: .debug(
377: language
378: .getString("Convert.SelectionConverter.Error.Construction"),
379: inv);
380: }
381: } else {
382: logger
383: .debug(language
384: .getString("Convert.SelectionConverter.Msg.NotSubclass")
385: + ": " + converterClassName);
386: }
387: } catch (ClassNotFoundException c) {
388: logger
389: .debug(
390: language
391: .getString("Convert.SelectionConverter.Error.MissingClass")
392: + ": " + converterClassName,
393: c);
394: } catch (NoSuchMethodException n) {
395: logger
396: .debug(
397: language
398: .getString("Convert.SelectionConverter.Error.MissingConstructor")
399: + ": " + converterClassName,
400: n);
401: }
402: }
403: } catch (ClassNotFoundException c) {
404: logger
405: .error(
406: language
407: .getString("Convert.SelectionConverter.Error.MissingClass"),
408: c);
409: }
410: }
411: }
|