/******************************************************************************* * Copyright (c) 2000, 2003 Advanced Systems Concepts, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * Advanced Systems Concepts - Initial api and implementation * Yu You - Add automatical resource management *******************************************************************************/ package com.swtworkbench.community.xswt.dataparser; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Widget; import com.swtworkbench.community.xswt.XSWTException; import com.swtworkbench.community.xswt.dataparser.parsers.ArrayDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.ByteDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.CharacterDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.ClassDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.DeviceDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.FontDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.ImageDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.IntDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.PointDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.RGBDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.RectangleDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.StringBufferDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.StringDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.ValueOfDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.color.CSSColorsDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.color.RGBColorDataParser; import com.swtworkbench.community.xswt.dataparser.parsers.color.SWTColorsDataParser; import com.swtworkbench.community.xswt.layoutbuilder.ReflectionSupport; import com.swtworkbench.community.xswt.scripting.Bindings; import com.swtworkbench.community.xswt.scripting.InterfaceDataParser; /** * Class DataParser. Assists in converting from Strings to arbitrary types. * * @author daveo */ public final class DataParser implements IDataParserContext { private HashMap dataParsers = new HashMap(); private HashMap disposableData = new HashMap(); /* private static List extensionDataParsers; public static void addExtensionDataParser(String className, IDataParser parser) { if (extensionDataParsers == null) { extensionDataParsers = new ArrayList(); } extensionDataParsers.add(className); extensionDataParsers.add(parser); } */ public DataParser(boolean addStandardParsers) { // ColorDataParser is registered inside setColorManager() // ControlDataParser is registered inside the constructor if (addStandardParsers) { registerDataParser(Character.TYPE, new CharacterDataParser()); registerDataParser(Integer.TYPE, new IntDataParser()); registerDataParser(Byte.TYPE, new ByteDataParser()); registerDataParser(String.class, new StringDataParser()); registerDataParser(StringBuffer.class, new StringBufferDataParser()); registerDataParser(RGB.class, new RGBDataParser(this)); registerDataParser(Point.class, new PointDataParser(this)); registerDataParser(Rectangle.class, new RectangleDataParser(this)); registerDataParser(Image.class, new ImageDataParser()); registerDataParser(Font.class, new FontDataParser()); // registerDataParser(Color.class, new ColorDataParser(this)); addDataParser(Color.class, new CSSColorsDataParser()); addDataParser(Color.class, new SWTColorsDataParser()); addDataParser(Color.class, new RGBColorDataParser()); registerDataParser(Device.class, new DeviceDataParser()); } /* if (addExtensionPointParsers && extensionDataParsers != null) { for (int i = 0; i < extensionDataParsers.size(); i += 2) { } // Make sure we're inside an Eclipse runtime to begin with. :-) // XswtPlugin plugin = XswtPlugin.getDefault(); // if (plugin != null) { // plugin.addDataParsers(this); // } } */ } public DataParser() { this(true); } /** * Tells this object to dispose all its managed resources. */ public void dispose() { Iterator cit = disposableData.values().iterator(); while (cit.hasNext()){ Object obj = cit.next(); if (obj instanceof Color) ((Color)obj).dispose(); else if (obj instanceof Font) ((Font)obj).dispose(); else if (obj instanceof Image) ((Image)obj).dispose(); else obj = null; } disposableData.clear(); } /** * Method registerDataParser. Register a class that can convert from a * String to Java type represented by Class klass. * * @param klass * The Class object representing the type that will be returned * @param dataParser * The object that can convert a String to that type */ public void registerDataParser(Class klass, IDataParser dataParser) { dataParsers.put(klass, dataParser); dataParsers.put(klass.getName(), dataParser); } /** * Method addDataParser. Register an additional class that can convert from a * String to Java type represented by Class klass. Does not clear an existing one, * but makes them operate together, trying each in order until one returns an object. * * @param klass * The Class object representing the type that will be returned * @param dataParser * The object that can convert a String to that type */ public void addDataParser(Class klass, IDataParser dataParser) { IDataParser oldParser = (IDataParser)dataParsers.get(klass); if (oldParser == null) { registerDataParser(klass, dataParser); } else { if (! (oldParser instanceof CompositeDataParser)) { oldParser = new CompositeDataParser(oldParser); dataParsers.put(klass, oldParser); } ((CompositeDataParser)oldParser).addDataParser(dataParser); } } private boolean trySuperclassParsers = true; public void setTrySuperclassParsers(boolean trySuperclassParsers) { this.trySuperclassParsers = trySuperclassParsers; } private Class upperSuperclass = null; public void setUpperSuperclass(Class upperSuperclass) { this.upperSuperclass = upperSuperclass; } /** * Method parseValue. Parse a String value into an object of type klass * * @param value * The value to convert * @param klass * The Class into which value should be converted * @return Object the converted value as type klass */ public Object parse(String value, Class klass) throws XSWTException { String stringValue = value; while (stringValue != null) { Class superClass = klass; Class objectClass = ClassDataParser.getObjectClass(klass); Object lastResult = null; do { Object result = null; IDataParser parser = getDataParser(superClass); if (parser != null) { try { result = parser.parse(stringValue, klass, this); } catch (IllegalArgumentException e) { } catch (RuntimeException e) { throw new XSWTException("Exception when parsing " + value + " for " + superClass, e); } } else if (! trySuperclassParsers) { throw new XSWTException("Unable to find a parser for type: " + klass.getName()); } if (result != null) { if (parser.isResourceDisposeRequired()) { // FIXME: This will pick up Label, any other SWT control disposableData.put(klass, result); } if (objectClass.isInstance(result)) { return result; } else { lastResult = result; } } superClass = superClass.getSuperclass(); } while (trySuperclassParsers && superClass != null && superClass != upperSuperclass); Object result = resolvePath(stringValue); if (result == null || objectClass.isInstance(result)) { return result; } if (result instanceof String) { // and try again with new value stringValue = (String)result; } else { // only throw exception if we got a result that was of the wrong class throw new XSWTException(value + " (" + stringValue + ")" + " could not be parsed into " + klass + ", but to " + lastResult); } } return null; } private IDataParser getDataParser(Class klass) { IDataParser parser = (IDataParser)dataParsers.get(klass); if (parser == null) { parser = (IDataParser)dataParsers.get(klass.getName()); } if (parser == null) { if (klass.isArray()) { parser = new ArrayDataParser(); } else if (ValueOfDataParser.supportsClass(klass)) { parser = new ValueOfDataParser(); } else if (klass.isInterface() && klass.getName().endsWith("Listener")) { parser = new InterfaceDataParser(); } if (parser != null) { dataParsers.put(klass, parser); } else { parser = (IDataParser)dataParsers.get(Object.class); // WidgetDataParser is the fallback parser } } return parser; } private static char pathSeparator = '.'; private Object resolvePath(String valueSource) throws XSWTException { int pos = valueSource.indexOf(pathSeparator); if (pos <= 0) { return null; } Object result = parse(valueSource.substring(0, pos), Object.class); int start = pos + 1; while (result != null && start < valueSource.length()) { if (result instanceof Bindings) { return ((Bindings)result).get(valueSource.substring(start)); } pos = valueSource.indexOf(pathSeparator, start); if (pos < 0) { pos = valueSource.length(); } String methodName = "get" + Character.toUpperCase(valueSource.charAt(start)) + valueSource.substring(start + 1, pos); start = pos; Method getter = ReflectionSupport.resolveAttributeGetMethod(result.getClass(), methodName); if (getter != null) { try { result = getter.invoke(result, null); } catch (Exception e) { throw new XSWTException("Error calling getter " + getter.getName(), e); } } else { result = null; } } return result; } }