resources = new Resources(resources, attribute.value);
} else if (attribute.localName.equals(INCLUDE_INLINE_ATTRIBUTE)) {
inline = Boolean.parseBoolean(attribute.value);
} 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;
if (inline) {
serializer = new WTKXSerializer(resources, this);
} else {
serializer = new WTKXSerializer(resources);
}
if (element.id != null) {
if (namedSerializers.containsKey(element.id)) {
throw new SerializationException("Namespace ID " + element.id
+ " is already in use.");
}
namedSerializers.put(element.id, serializer);
}
if (src.charAt(0) == '/') {
element.value = serializer.readObject(src.substring(1));
} else {
element.value = serializer.readObject(new URL(location, src));
}
} else {
// Process attributes looking for all property setters
for (Attribute attribute : element.attributes) {
if (Character.isUpperCase(attribute.localName.charAt(0))) {
staticPropertyAttributes.add(attribute);
} else {
instancePropertyAttributes.add(attribute);
}
}
}
// Add the value to the named objects map
if (element.id != null) {
if (namedObjects.containsKey(element.id)) {
throw new SerializationException("Element ID " + element.id
+ " is already in use.");
}
namedObjects.put(element.id, element.value);
}
// Apply instance attributes
Dictionary<String, Object> dictionary;
if (element.value instanceof Dictionary<?, ?>) {
dictionary = (Dictionary<String, Object>)element.value;
} else {
dictionary = new BeanAdapter(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) {
// Determine the type of the attribute
String propertyClassName = attribute.namespaceURI + "."
+ attribute.localName.substring(0, attribute.localName.lastIndexOf("."));
Class<?> propertyClass = null;
try {
propertyClass = Class.forName(propertyClassName);
} catch (ClassNotFoundException exception) {
throw new SerializationException(exception);
}
if (propertyClass.isInterface()) {
// The attribute represents an event listener
String listenerClassName = propertyClassName.substring(propertyClassName.lastIndexOf('.') + 1);
String getListenerListMethodName = "get" + Character.toUpperCase(listenerClassName.charAt(0))
+ listenerClassName.substring(1) + "s";
// Get the listener list
Method getListenerListMethod;
try {
Class<?> type = element.value.getClass();
getListenerListMethod = type.getMethod(getListenerListMethodName);
} catch (NoSuchMethodException exception) {
throw new SerializationException(exception);
}
Object listenerList;
try {
listenerList = getListenerListMethod.invoke(element.value);
} catch (InvocationTargetException exception) {
throw new SerializationException(exception);
} catch (IllegalAccessException exception) {
throw new SerializationException(exception);
}
// Create an invocation handler for this listener
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(language);
AttributeInvocationHandler handler =
new AttributeInvocationHandler(scriptEngine,
attribute.localName.substring(attribute.localName.lastIndexOf(".") + 1),
attribute.value);
Object listener = Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
new Class<?>[]{propertyClass}, handler);
// Add the listener
Class<?> listenerListClass = listenerList.getClass();
Method addMethod;
try {
addMethod = listenerListClass.getMethod("add", Object.class);
} catch (NoSuchMethodException exception) {
throw new RuntimeException(exception);
}
try {
addMethod.invoke(listenerList, listener);
} catch (IllegalAccessException exception) {
throw new SerializationException(exception);
} catch (InvocationTargetException exception) {
throw new SerializationException(exception);
}
} else {
// The attribute reprsents a static setter
Object value = resolve(attribute.value);
Class<?> objectType = element.value.getClass();
String propertyName = attribute.localName.substring(attribute.localName.lastIndexOf(".") + 1);
propertyName = Character.toUpperCase(propertyName.charAt(0)) +
propertyName.substring(1);
Method setterMethod = null;
if (value != null) {
setterMethod = getStaticSetterMethod(propertyClass, propertyName,
objectType, value.getClass());
}
if (setterMethod == null) {
Method getterMethod = getStaticGetterMethod(propertyClass, propertyName, objectType);
if (getterMethod != null) {
Class<?> propertyType = getterMethod.getReturnType();
setterMethod = getStaticSetterMethod(propertyClass, propertyName,
objectType, propertyType);
if (value instanceof String) {
value = BeanAdapter.coerce((String)value, propertyType);
}
}
}
if (setterMethod == null) {
throw new SerializationException(attribute.localName + " is not valid static property.");
}
// Invoke the setter
try {
setterMethod.invoke(null, element.value, value);
} catch (Exception exception) {
throw new SerializationException(exception);
}
}
}
}
// 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: {
BeanAdapter beanAdapter = new BeanAdapter(element.parent.value);
beanAdapter.put(localName, element.value);
break;
}
case SCRIPT: {
// Process attributes looking for src and language
String src = null;
String language = this.language;
for (Attribute attribute : element.attributes) {
if (attribute.localName.equals(SCRIPT_SRC_ATTRIBUTE)) {
src = attribute.value;
} else if (attribute.localName.equals(SCRIPT_LANGUAGE_ATTRIBUTE)) {
language = attribute.value;
} else {
throw new SerializationException(attribute.localName + " is not a valid"
+ " attribute for the " + WTKX_PREFIX + ":" + SCRIPT_TAG + " tag.");
}
}
Bindings bindings;
if (element.parent.value instanceof ListenerList<?>) {
// Don't pollute the engine namespace with the listener functions
bindings = new SimpleBindings();
} else {
bindings = scriptEngineManager.getBindings();
}
// Execute script
final ScriptEngine scriptEngine;
if (src != null) {
// The script is located in an external file
int i = src.lastIndexOf(".");
if (i == -1) {
throw new SerializationException("Cannot determine type of script \""
+ src + "\".");
}
String extension = src.substring(i + 1);
scriptEngine = scriptEngineManager.getEngineByExtension(extension);
if (scriptEngine == null) {
throw new SerializationException("Unable to find scripting engine for"
+ " extension " + extension + ".");
}
scriptEngine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
try {
URL scriptLocation;
if (src.charAt(0) == '/') {
ClassLoader classLoader = ThreadUtilities.getClassLoader();
scriptLocation = classLoader.getResource(src);
} else {
scriptLocation = new URL(location, src);
}
BufferedReader scriptReader = null;
try {
scriptReader = new BufferedReader(new InputStreamReader(scriptLocation.openStream()));
scriptEngine.eval(scriptReader);
} catch(ScriptException exception) {
exception.printStackTrace();
} finally {
if (scriptReader != null) {
scriptReader.close();
}
}
} catch (IOException exception) {
throw new SerializationException(exception);
}
} else {
// The script is inline
scriptEngine = scriptEngineManager.getEngineByName(language);
if (scriptEngine == null) {
throw new SerializationException("Unable to find scripting engine for"
+ " language \"" + language + "\".");
}
scriptEngine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
String script = (String)element.value;
if (script != null) {
try {
scriptEngine.eval(script);
} catch (ScriptException exception) {
System.err.println(exception);
System.err.println(script);
}
}
}
if (element.parent.value instanceof ListenerList<?>) {
// Create the listener and add it to the list
Class<?> listenerListClass = element.parent.value.getClass();
java.lang.reflect.Type[] genericInterfaces = listenerListClass.getGenericInterfaces();
Class<?> listenerClass = (Class<?>)genericInterfaces[0];
ElementInvocationHandler handler = new ElementInvocationHandler(scriptEngine);
Method addMethod;
try {
addMethod = listenerListClass.getMethod("add", Object.class);
} catch (NoSuchMethodException exception) {
throw new RuntimeException(exception);
}
Object listener = Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
new Class<?>[]{listenerClass}, handler);
try {
addMethod.invoke(element.parent.value, listener);
} catch (IllegalAccessException exception) {
throw new SerializationException(exception);
} catch (InvocationTargetException exception) {
throw new SerializationException(exception);
}
}
break;
}