if (prefix != null
&& prefix.length() > 0) {
throw new SerializationException("Property elements cannot have a namespace prefix.");
}
BeanDictionary beanDictionary = new BeanDictionary(element.value);
if (beanDictionary.isReadOnly(localName)) {
elementType = Element.Type.READ_ONLY_PROPERTY;
value = beanDictionary.get(localName);
assert (value != null) : "Read-only properties cannot be null.";
if (attributes.getLength() > 0
&& !(value instanceof Dictionary<?, ?>)) {
throw new SerializationException("Only read-only dictionaries can have attributes.");
}
} else {
if (attributes.getLength() > 0) {
throw new SerializationException("Writable property elements cannot have attributes.");
}
elementType = Element.Type.WRITABLE_PROPERTY;
}
}
}
// Set the current element
String tagName = localName;
if (prefix != null
&& prefix.length() > 0) {
tagName = prefix + ":" + tagName;
}
Location xmlStreamLocation = reader.getLocation();
element = new Element(element, elementType, tagName, xmlStreamLocation.getLineNumber(),
attributes, value);
// If this is the root, set it
if (element.parent == null) {
root = element.value;
}
break;
}
case XMLStreamConstants.END_ELEMENT: {
String localName = reader.getLocalName();
switch (element.type) {
case INSTANCE:
case INCLUDE: {
String id = null;
ArrayList<Attribute> instancePropertyAttributes = new ArrayList<Attribute>();
ArrayList<Attribute> staticPropertyAttributes = new ArrayList<Attribute>();
if (element.type == Element.Type.INCLUDE) {
// Process attributes looking for wtkx:id, src, resources, asynchronous,
// and static property setters only
String src = null;
Resources resources = this.resources;
for (Attribute attribute : element.attributes) {
if (attribute.prefix != null
&& attribute.prefix.equals(WTKX_PREFIX)) {
if (attribute.localName.equals(ID_ATTRIBUTE)) {
id = attribute.value;
} else {
throw new SerializationException(WTKX_PREFIX + ":" + attribute.localName
+ " is not a valid attribute.");
}
} else {
if (attribute.localName.equals(INCLUDE_SRC_ATTRIBUTE)) {
src = attribute.value;
} else if (attribute.localName.equals(INCLUDE_RESOURCES_ATTRIBUTE)) {
resources = new Resources(resources, attribute.value);
} else if (attribute.localName.equals(INCLUDE_ASYNCHRONOUS_ATTRIBUTE)) {
// TODO
throw new UnsupportedOperationException("Asynchronous includes are not"
+ " yet supported.");
} else {
if (!Character.isUpperCase(attribute.localName.charAt(0))) {
throw new SerializationException("Instance property setters are not"
+ " supported for " + WTKX_PREFIX + ":" + INCLUDE_TAG
+ " " + " tag.");
}
staticPropertyAttributes.add(attribute);
}
}
}
if (src == null) {
throw new SerializationException(INCLUDE_SRC_ATTRIBUTE
+ " attribute is required for " + WTKX_PREFIX + ":" + INCLUDE_TAG
+ " tag.");
}
// Read the object
WTKXSerializer serializer = new WTKXSerializer(resources);
if (id != null) {
includeSerializers.put(id, serializer);
}
if (src.charAt(0) == '/') {
element.value = serializer.readObject(src.substring(1));
} else {
element.value = serializer.readObject(new URL(location, src));
}
if (id == null
&& !serializer.isEmpty()
&& serializer.scriptEngineManager == null) {
System.err.println("Include \"" + src + "\" defines unreachable objects.");
}
} else {
// Process attributes looking for wtkx:id and all property setters
for (Attribute attribute : element.attributes) {
if (attribute.prefix != null
&& attribute.prefix.equals(WTKX_PREFIX)) {
if (attribute.localName.equals(ID_ATTRIBUTE)) {
id = attribute.value;
} else {
throw new SerializationException(WTKX_PREFIX + ":" + attribute.localName
+ " is not a valid attribute.");
}
} else {
if (Character.isUpperCase(attribute.localName.charAt(0))) {
staticPropertyAttributes.add(attribute);
} else {
instancePropertyAttributes.add(attribute);
}
}
}
}
// 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);
}
// Apply instance attributes
Dictionary<String, Object> dictionary;
if (element.value instanceof Dictionary) {
dictionary = (Dictionary<String, Object>)element.value;
} else {
dictionary = new BeanDictionary(element.value);
}
for (Attribute attribute : instancePropertyAttributes) {
dictionary.put(attribute.localName, resolve(attribute.value));
}
// 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);
}
}
}
// Apply static attributes
if (element.value instanceof Dictionary) {
if (staticPropertyAttributes.getLength() > 0) {
throw new SerializationException("Static setters are only supported"
+ " for typed objects.");
}
} else {
for (Attribute attribute : staticPropertyAttributes) {
setStaticProperty(attribute, element.value);
}
}
// 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;
}
break;
}
case READ_ONLY_PROPERTY: {
if (element.value instanceof Dictionary<?, ?>) {
// Process attributes looking for instance property setters
for (Attribute attribute : element.attributes) {
if (Character.isUpperCase(attribute.localName.charAt(0))) {
throw new SerializationException("Static setters are not supported"
+ " for read-only properties.");
}
Dictionary<String, Object> dictionary =
(Dictionary<String, Object>)element.value;
dictionary.put(attribute.localName, resolve(attribute.value));
}
}
break;
}
case WRITABLE_PROPERTY: {
BeanDictionary beanDictionary = new BeanDictionary(element.parent.value);
beanDictionary.put(localName, element.value);
break;
}
case SCRIPT: {
// Load the script engine manager