/* * $Id: PropertyParser.java,v 1.1 2007-02-27 12:45:29 eugen Exp $ * * Copyright (C) 2002 by Brockmann Consult (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation. This program is distributed in the hope it will * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package com.bc.util.prop; import com.bc.util.geom.Geometry; import com.bc.util.geom.GeometryParser; import java.awt.Color; import java.io.File; import java.text.ParseException; import java.util.Map; import java.util.StringTokenizer; public class PropertyParser { private static final char EOS = (char) -1; private static final int NAME_EXPECTED = 0; private static final int PARENT_CREATED = 1; private static final int INDEX_EXPECTED = 2; private static final int EOS_SEEN = 4; private static final int ARRAY_CREATED = 3; private PropertyParser() { } public static Property parseProperty(Class parentType, String fullName) throws ParseException, PropertyNotFoundException { int state = NAME_EXPECTED; StringBuffer tokenBuf = new StringBuffer(); Property parent = null; int pos = 0; while (true) { char c; // skip whitespace characters while (true) { c = getChar(fullName, pos); if (Character.isWhitespace(c)) { pos++; } else { break; } } if (state == NAME_EXPECTED) { // name expected if (Character.isJavaIdentifierStart(c)) { tokenBuf.append(c); pos++; while (true) { c = getChar(fullName, pos); if (Character.isJavaIdentifierPart(c)) { tokenBuf.append(c); pos++; } else { break; } } final String propertyName = tokenBuf.toString(); tokenBuf.setLength(0); if (parent != null) { parent = PropertyFactory.createNestedProperty(parent, propertyName); } else { parent = PropertyFactory.createChildProperty(parentType, propertyName); } if (parent == null) { throw new PropertyNotFoundException("'" + propertyName + "' not found"); } state = PARENT_CREATED; // parent created, '.' or '[' or EOS expected } else { throw new ParseException("name expected, got " + fullName, pos); } } else if (state == PARENT_CREATED) { // parent created, '.' or '[' or EOS expected if (c == '.') { pos++; state = NAME_EXPECTED; // name expected } else if (c == '[') { pos++; state = INDEX_EXPECTED; // index or key expected } else if (c == EOS) { state = EOS_SEEN; // EOS break; } else { throw new ParseException("'.' or '[' or EOS expected", pos); } } else if (state == INDEX_EXPECTED) { // index or key expected if (Character.isDigit(c)) { tokenBuf.append(c); pos++; while (true) { c = getChar(fullName, pos); if (Character.isDigit(c)) { tokenBuf.append(c); pos++; } else { break; } } final String indexString = tokenBuf.toString(); tokenBuf.setLength(0); final int index = Integer.parseInt(indexString); final Property arrayBase; if (parent instanceof NestedProperty) { NestedProperty np = (NestedProperty) parent; arrayBase = np.getChild(); } else { arrayBase = parent; } if (arrayBase.getType() != Property.UNKNOWN_TYPE && !arrayBase.getType().isArray()) { throw new ParseException("'" + parent.getName() + "' is not a Java array", pos); } final ArrayProperty ap = new ArrayProperty(arrayBase, index); if (parent instanceof NestedProperty) { NestedProperty np = (NestedProperty) parent; np.setChild(ap); } else { parent = ap; } state = ARRAY_CREATED; // array parent created, ']' expected } else if (c == '"') { pos++; while (true) { c = getChar(fullName, pos); // todo 3 nf/** - recognize escape characters if (c == '"') { pos++; break; } else if (c == EOS) { throw new ParseException("string delimitter expected", pos); } tokenBuf.append(c); pos++; } final String key = tokenBuf.toString(); tokenBuf.setLength(0); final Property mapBase; if (parent instanceof NestedProperty) { NestedProperty np = (NestedProperty) parent; mapBase = np.getChild(); } else { mapBase = parent; } if (mapBase.getType() != Property.UNKNOWN_TYPE && !Map.class.isAssignableFrom(mapBase.getType())) { throw new ParseException("'" + parent.getName() + "' is not a java.util.Map", pos); } final MapProperty mp = new MapProperty(key); if (parent instanceof NestedProperty) { parent = new NestedProperty(parent, mp); } else { parent = new NestedProperty(mapBase, mp); } //System.out.println("parent.getName() = " + parent.getName()); state = ARRAY_CREATED; // array parent created, ']' expected } else { throw new ParseException("index or key expected", pos); } } else if (state == ARRAY_CREATED) { // array parent created, ']' expected if (c == ']') { pos++; state = PARENT_CREATED; // parent created, '.' or '[' or EOS expected } else { throw new ParseException("']' expected", pos); } } else { throw new IllegalStateException(); } } if (state != EOS_SEEN) { // EOS throw new IllegalStateException(); } if (parent == null) { throw new IllegalStateException(); } return parent; } public static Object parseValue(Class type, final String name, final String value) throws ParseException { final Object obj; try { if (type.equals(Boolean.TYPE) || type.equals(Boolean.class)) { obj = Boolean.valueOf(value); } else if (type.equals(Byte.TYPE) || type.equals(Byte.class)) { obj = Byte.valueOf(value); } else if (type.equals(Character.TYPE) || type.equals(Character.class)) { if (value.length() != 1) { throw new ParseException( "character value expected for property '" + name + "', value was '" + value + "'", 0); } obj = new Character(value.charAt(0)); } else if (type.equals(Short.TYPE) || type.equals(Short.class)) { obj = Short.valueOf(value); } else if (type.equals(Integer.TYPE) || type.equals(Integer.class)) { obj = Integer.valueOf(value); } else if (type.equals(Long.TYPE) || type.equals(Long.class)) { obj = Long.valueOf(value); } else if (type.equals(Float.TYPE) || type.equals(Float.class)) { obj = Float.valueOf(value); } else if (type.equals(Double.TYPE) || type.equals(Double.class)) { obj = Double.valueOf(value); } else if (type.equals(String.class)) { obj = value; } else if (type.equals(File.class)) { obj = new File(value); } else if (type.equals(Color.class)) { obj = parseColor(value); if (obj == null) { throw new ParseException( "color value expected for property '" + name + "', value was '" + value + "'", 0); } } else if (Geometry.class.isAssignableFrom(type)) { obj = new GeometryParser().parseWKT(value); } else { throw new ParseException( "don't know how to convert value for property '" + name + "', value was '" + value + "'", 0); } } catch (NumberFormatException e) { throw new ParseException("number value expected for property '" + name + "', value was '" + value + "'", 0); } return obj; } public static Object parseColor(String value) { final StringTokenizer st = new StringTokenizer(value, ",", false); final int count = st.countTokens(); try { if (count == 1) { return Color.decode(value); } else if (count == 3 || count == EOS_SEEN) { final int r = Integer.parseInt(st.nextToken()); final int g = Integer.parseInt(st.nextToken()); final int b = Integer.parseInt(st.nextToken()); final int a = count == EOS_SEEN ? Integer.parseInt(st.nextToken()) : 255; try { return new Color(r, g, b, a); } catch (IllegalArgumentException e) { return null; } } else { return null; } } catch (NumberFormatException e) { return null; } } private static char getChar(String fullName, int pos) { char c; if (pos < fullName.length()) { c = fullName.charAt(pos); } else { c = EOS; } return c; } }