try {
Method addMethod = sequence.getClass().getMethod("add",
new Class<?>[] {String.class});
addMethod.invoke(sequence, new Object[] {text});
} catch(NoSuchMethodException exception) {
throw new SerializationException("Text content cannot be added to "
+ sequence.getClass().getName() + ".", exception);
} catch(InvocationTargetException exception) {
throw new SerializationException(exception);
} catch(IllegalAccessException exception) {
throw new SerializationException(exception);
}
}
break;
}
case WRITABLE_PROPERTY: {
element.value = text;
break;
}
}
}
}
break;
}
case XMLStreamConstants.START_ELEMENT: {
String namespaceURI = reader.getNamespaceURI();
String prefix = reader.getPrefix();
String localName = reader.getLocalName();
String id = null;
if (prefix != null
&& prefix.equals(WTKX_PREFIX)) {
if (element == null) {
throw new SerializationException(prefix + ":" + localName
+ " is not a valid root element.");
}
if (localName.equals(INCLUDE_TAG)) {
// The element represents an include
String src = null;
Resources includeResources = resources;
ArrayList<Attribute> attributes = new ArrayList<Attribute>();
for (int i = 0, n = reader.getAttributeCount(); i < n; i++) {
String attributeNamespaceURI = reader.getAttributeNamespace(i);
if (attributeNamespaceURI == null) {
attributeNamespaceURI = reader.getNamespaceURI("");
}
String attributePrefix = reader.getAttributePrefix(i);
String attributeLocalName = reader.getAttributeLocalName(i);
String attributeValue = reader.getAttributeValue(i);
if (attributePrefix != null
&& attributePrefix.equals(WTKX_PREFIX)) {
if (attributeLocalName.equals(ID_ATTRIBUTE)) {
id = attributeValue;
}
} else {
if (attributeLocalName.equals(INCLUDE_SRC_ATTRIBUTE)) {
src = attributeValue;
} else if (attributeLocalName.equals(INCLUDE_RESOURCES_ATTRIBUTE)) {
includeResources = new Resources(attributeValue);
} else {
attributes.add(new Attribute(attributeNamespaceURI,
attributePrefix, attributeLocalName, attributeValue));
}
}
}
if (src == null) {
throw new SerializationException(INCLUDE_SRC_ATTRIBUTE
+ " attribute is required for " + WTKX_PREFIX + ":" + INCLUDE_TAG
+ " tag.");
}
// Process the include
WTKXSerializer serializer = new WTKXSerializer(includeResources);
if (id != null) {
includeSerializers.put(id, serializer);
}
Object value;
if (src.charAt(0) == '/') {
value = serializer.readObject(src.substring(1));
} else {
value = serializer.readObject(new URL(location, src));
}
element = new Element(element, Element.Type.INCLUDE, attributes, value);
} else if (localName.equals(SCRIPT_TAG)) {
// Load the script engine manager if it has not been loaded
if (scriptEngineManager == null) {
try {
scriptEngineManagerClass = Class.forName("javax.script.ScriptEngineManager");
} catch(ClassNotFoundException exception) {
throw new SerializationException("Scripting is not supported on this platform.");
}
try {
scriptEngineManager = scriptEngineManagerClass.newInstance();
Method getBindingsMethod = scriptEngineManagerClass.getMethod
("getBindings", new Class<?>[] {});
scriptEngineBindings = (java.util.Map<String, Object>)
getBindingsMethod.invoke(scriptEngineManager, new Object[] {});
} catch(Exception exception) {
scriptEngineManager = null;
scriptEngineBindings = null;
}
}
// The element represents a script
String src = null;
for (int i = 0, n = reader.getAttributeCount(); i < n; i++) {
String attributeLocalName = reader.getAttributeLocalName(i);
String attributeValue = reader.getAttributeValue(i);
if (attributeLocalName.equals(SCRIPT_SRC_ATTRIBUTE)) {
src = attributeValue;
} else {
throw new SerializationException(attributeLocalName + " is not a valid "
+ " attribute for the " + WTKX_PREFIX + ":" + SCRIPT_TAG + ".");
}
}
if (src == null) {
throw new SerializationException(INCLUDE_SRC_ATTRIBUTE
+ " attribute is required for " + WTKX_PREFIX + ":" + SCRIPT_TAG
+ " tag.");
}
int i = src.lastIndexOf(".");
if (i == -1) {
throw new SerializationException("Cannot determine type of script \""
+ src + "\".");
}
String extension = src.substring(i + 1);
Object scriptEngine = null;
try {
Method getEngineByExtensionMethod =
scriptEngineManagerClass.getMethod("getEngineByExtension", new Class<?>[] {String.class});
scriptEngine = getEngineByExtensionMethod.invoke(scriptEngineManager, new Object[] {extension});
} catch(Exception exception) {
throw new RuntimeException(exception);
}
if (scriptEngine == null) {
throw new SerializationException("Unable to find scripting engine for "
+ " extension " + extension + ".");
}
try {
ClassLoader classLoader = ThreadUtilities.getClassLoader();
URL scriptLocation;
if (src.charAt(0) == '/') {
scriptLocation = classLoader.getResource(src);
} else {
scriptLocation = new URL(location, src);
}
Class<?> bindingsClass = Class.forName("javax.script.Bindings");
Method evalMethod = scriptEngine.getClass().getMethod("eval",
new Class<?>[] {Reader.class, bindingsClass});
Reader scriptReader = new BufferedReader(new InputStreamReader(scriptLocation.openStream()));
evalMethod.invoke(scriptEngine, new Object[] {scriptReader, scriptEngineBindings});
} catch(Exception exception) {
throw new SerializationException(exception);
}
element = new Element(element, Element.Type.SCRIPT, null, null);
} else {
throw new SerializationException(prefix + ":" + localName
+ " is not a valid tag.");
}
} else {
ArrayList<Attribute> attributes = new ArrayList<Attribute>();
for (int i = 0, n = reader.getAttributeCount(); i < n; i++) {
String attributeNamespaceURI = reader.getAttributeNamespace(i);
if (attributeNamespaceURI == null) {
attributeNamespaceURI = reader.getNamespaceURI("");
}
String attributePrefix = reader.getAttributePrefix(i);
String attributeLocalName = reader.getAttributeLocalName(i);
String attributeValue = reader.getAttributeValue(i);
if (attributePrefix != null
&& attributePrefix.equals(WTKX_PREFIX)) {
if (attributeLocalName.equals(ID_ATTRIBUTE)) {
id = attributeValue;
}
} else {
attributes.add(new Attribute(attributeNamespaceURI,
attributePrefix, attributeLocalName, attributeValue));
}
}
if (Character.isUpperCase(localName.charAt(0))) {
// The element represents a typed object
if (namespaceURI == null) {
throw new SerializationException("No XML namespace specified for "
+ localName + " tag.");
}
String className = namespaceURI + "." + localName.replace('.', '$');
try {
Class<?> type = Class.forName(className);
element = new Element(element, Element.Type.INSTANCE, attributes, type.newInstance());
} catch(Exception exception) {
throw new SerializationException(exception);
}
} else {
// This element represents a property
if (element == null) {
throw new SerializationException("Root node must represent a typed object.");
}
BeanDictionary propertyDictionary = new BeanDictionary(element.value);
if (propertyDictionary.isReadOnly(localName)) {
Object value = propertyDictionary.get(localName);
assert (value != null) : "Read-only properties cannot be null.";
element = new Element(element, Element.Type.READ_ONLY_PROPERTY, attributes, value);
} else {
if (attributes.getLength() > 0) {
throw new SerializationException("Writable property elements cannot have attributes.");
}
element = new Element(element, Element.Type.WRITABLE_PROPERTY, null, null);
}
}
}
switch (element.type) {
case INCLUDE:
case INSTANCE: {
// If the element's parent is a sequence or a listener list, add
// the element value to it
if (element.parent != null) {
if (element.parent.value instanceof Sequence) {
Sequence<Object> sequence = (Sequence<Object>)element.parent.value;
sequence.add(element.value);
} else {
if (element.parent.value instanceof ListenerList) {
ListenerList<Object> listenerList = (ListenerList<Object>)element.parent.value;
listenerList.add(element.value);
}
}
}
// If an ID was specified, add the value to the named object map
if (id != null) {
if (id.length() == 0) {
throw new IllegalArgumentException(WTKX_PREFIX + ":" + ID_ATTRIBUTE
+ " must not be null.");
}
namedObjects.put(id, element.value);
if (scriptEngineManager != null) {
try {
Method putMethod = scriptEngineManagerClass.getMethod("put",
new Class<?>[] {String.class, Object.class});
putMethod.invoke(scriptEngineManager, new Object[] {id, namedObjects.get(id)});
} catch(Exception exception) {
throw new RuntimeException(exception);
}
}
}
break;
}
}
break;
}
case XMLStreamConstants.END_ELEMENT: {
String localName = reader.getLocalName();
switch (element.type) {
case WRITABLE_PROPERTY: {
BeanDictionary propertyDictionary = new BeanDictionary(element.parent.value);
propertyDictionary.put(localName, element.value);
break;
}
case SCRIPT: {
break;
}
default: {
if (element.value instanceof Dictionary) {
// The element is an untyped object
Dictionary<String, Object> dictionary = (Dictionary<String, Object>)element.value;
for (Attribute attribute : element.attributes) {
if (Character.isUpperCase(attribute.localName.charAt(0))) {
throw new SerializationException("Static setters are only supported for typed instances.");
}
// Resolve and apply the attribute
dictionary.put(attribute.localName, resolve(attribute.value, null));
}
} else {
// The element represents a typed object; apply the attributes
BeanDictionary valueDictionary = new BeanDictionary(element.value);
for (Attribute attribute : element.attributes) {
if (Character.isUpperCase(attribute.localName.charAt(0))) {
// The property represents an attached value
setStaticProperty(attribute, element.value);
} else {
Class<?> type = valueDictionary.getType(attribute.localName);
if (type != null
&& ListenerList.class.isAssignableFrom(type)) {
// The property represents a listener list
ListenerList<Object> listenerList = (ListenerList<Object>)valueDictionary.get(attribute.localName);
// The attribute value is a comma-separated list of listener IDs
String[] listenerIDs = attribute.value.split(",");
for (int i = 0, n = listenerIDs.length; i < n; i++) {
String listenerID = listenerIDs[i].trim();
if (listenerID.length() > 0) {
listenerID = listenerID.substring(1);
if (listenerID.length() > 0) {
listenerList.add(namedObjectDictionary.get(listenerID));
}
}
}
} else {
valueDictionary.put(attribute.localName,
resolve(attribute.value, valueDictionary.getType(attribute.localName)));
}
}
}
}
// If the parent element is a writable property, set this as its value; it
// will be applied later in the parent's closing tag
if (element.parent != null
&& element.parent.type == Element.Type.WRITABLE_PROPERTY) {
element.parent.value = element.value;
}
}
}
// If this is the top of the stack, return this element's value;
// otherwise, move up the stack
if (element.parent == null) {
object = element.value;
} else {
element = element.parent;
}
break;
}
}
}
reader.close();
} catch(XMLStreamException exception) {
throw new SerializationException(exception);
}
// Clear the location so the previous value won't be re-used in a
// subsequent call to this method
location = null;