diff --git a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneRuleSet.java b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneRuleSet.java index a00f081c4..ed4a7846b 100644 --- a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneRuleSet.java +++ b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneRuleSet.java @@ -1,5 +1,5 @@ // -// $Id: SpotSceneRuleSet.java,v 1.6 2004/08/27 02:20:48 mdb Exp $ +// $Id$ // // Narya library - tools for developing networked games // Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved @@ -21,10 +21,21 @@ package com.threerings.whirled.spot.tools.xml; -import com.samskivert.xml.SetPropertyFieldsRule; -import com.threerings.tools.xml.NestableRuleSet; -import org.apache.commons.digester.Digester; +import java.lang.reflect.Field; +import com.samskivert.xml.SetPropertyFieldsRule; +import com.samskivert.util.StringUtil; +import com.samskivert.util.ValueMarshaller; + +import com.threerings.tools.xml.NestableRuleSet; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.ObjectCreateRule; +import org.apache.commons.digester.Rule; + +import org.xml.sax.Attributes; + +import com.threerings.whirled.spot.data.Location; import com.threerings.whirled.spot.data.Portal; import com.threerings.whirled.spot.data.SpotSceneModel; import com.threerings.whirled.spot.tools.EditablePortal; @@ -49,10 +60,108 @@ public class SpotSceneRuleSet implements NestableRuleSet digester.addRule(prefix, new SetPropertyFieldsRule()); // create EditablePortal instances when we see - digester.addObjectCreate(prefix + "/portal", - EditablePortal.class.getName()); - digester.addRule(prefix + "/portal", new SetPropertyFieldsRule()); + digester.addRule(prefix + "/portal", new PortalCreateRule(this)); + digester.addRule(prefix + "/portal", new PortalFieldsRule()); digester.addSetNext(prefix + "/portal", "addPortal", Portal.class.getName()); } + + /** + * Create a new instance of the Location class that should be used + * with Portals. + */ + protected Location createNewLocation () + { + return new Location(); + } + + /** + * A rule used to create the portal but also initialize the Location + * property within it. + */ + protected static class PortalCreateRule extends ObjectCreateRule + { + public PortalCreateRule (SpotSceneRuleSet ruleset) + { + super(EditablePortal.class.getName()); + _ruleset = ruleset; + } + + // documentation inherited + public void begin (String namespace, String name, Attributes attributes) + throws Exception + { + super.begin(namespace, name, attributes); + + // create the empty Location in the Portal + Portal p = (Portal) digester.peek(); + p.loc = _ruleset.createNewLocation(); + } + + protected SpotSceneRuleSet _ruleset; + } + + /** + * Set fields in the Portal, or in the Location object + * contained therein. If there are ambiguous attribute names then.. + * well. yeah. + */ + protected static class PortalFieldsRule extends Rule + { + // documentation inherited + public void begin (String namespace, String name, Attributes attrs) + throws Exception + { + Portal portal = (Portal) digester.peek(); + Class portalClass = portal.getClass(); + Location loc = portal.loc; + Class locClass = loc.getClass(); + + // iterate over the attributes, setting public fields where + // applicable + for (int i = 0; i < attrs.getLength(); i++) { + String lname = attrs.getLocalName(i); + if (StringUtil.isBlank(lname)) { + lname = attrs.getQName(i); + } + + // look for a public field with this lname + Field field; + Object container; + try { + field = portalClass.getField(lname); + container = portal; + + } catch (NoSuchFieldException nsfe) { + // if we didn't find the field in the Portal, maybe it's + // in the Location + try { + field = locClass.getField(lname); + container = loc; + + } catch (NoSuchFieldException nsfe2) { + digester.getLogger().warn( + "Skipping property '" + lname + + "' for which there is no field."); + continue; + } + } + + // convert the value into the appropriate object type + String valstr = attrs.getValue(i); + // use the value marshaller to parse the + // property based on the type of the target object field + Object value = ValueMarshaller.unmarshal( + field.getType(), valstr); + + if (digester.getLogger().isDebugEnabled()) { + digester.getLogger().debug(" Setting property '" + lname + + "' to '" + valstr + "'"); + } + + // and finally set the field + field.set(container, value); + } + } + } } diff --git a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneWriter.java b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneWriter.java index eadba183e..50f745d9f 100644 --- a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneWriter.java +++ b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneWriter.java @@ -21,12 +21,15 @@ package com.threerings.whirled.spot.tools.xml; +import java.lang.reflect.Field; + import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import com.megginson.sax.DataWriter; import com.threerings.tools.xml.NestableWriter; +import com.threerings.whirled.spot.Log; import com.threerings.whirled.spot.data.Location; import com.threerings.whirled.spot.data.SpotSceneModel; import com.threerings.whirled.spot.tools.EditablePortal; @@ -81,12 +84,19 @@ public class SpotSceneWriter protected void addPortalLocationAttributes ( Location portalLoc, AttributesImpl attrs) { - // we assume here that the Location is purely 2d. Subclasses - // may write out more information - attrs.addAttribute("", "x", "", "", String.valueOf(portalLoc.x)); - attrs.addAttribute("", "y", "", "", String.valueOf(portalLoc.y)); - attrs.addAttribute("", "orient", "", "", - String.valueOf(portalLoc.orient)); + // we just add all the visible fields of the location, but something + // more sophisticated could be done + Class clazz = portalLoc.getClass(); + Field[] fields = clazz.getFields(); + for (int ii=0; ii < fields.length; ii++) { + try { + attrs.addAttribute("", fields[ii].getName(), "", "", + String.valueOf(fields[ii].get(portalLoc))); + } catch (IllegalAccessException iae) { + Log.warning("Unable to write portal field, skipping " + + "[field=" + fields[ii].getName() + ", e=" + iae + "]."); + } + } } /**