/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.synapse.mediators.ext;
import org.apache.synapse.Command;
import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.annotations.Namespaces;
import org.apache.synapse.mediators.annotations.ReadAndUpdate;
import org.apache.synapse.mediators.annotations.ReadFromMessage;
import org.apache.synapse.mediators.annotations.UpdateMessage;
import org.apache.synapse.util.xpath.SynapseXPath;
import org.jaxen.JaxenException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
*/
public class AnnotatedCommandMediator extends POJOCommandMediator {
protected Map<Field, SynapseXPath> beforeFields;
protected Map<Method, SynapseXPath> beforeMethods;
protected Map<Field, SynapseXPath> afterFields;
protected Map<Method, SynapseXPath> afterMethods;
@Override
public boolean mediate(MessageContext synCtx) {
boolean traceOn = isTraceOn(synCtx);
boolean traceOrDebugOn = isTraceOrDebugOn(traceOn);
if (traceOrDebugOn) {
traceOrDebug(traceOn, "Start : POJOCommand mediator");
if (traceOn && trace.isTraceEnabled()) {
trace.trace("Message : " + synCtx.getEnvelope());
}
}
if (traceOrDebugOn) {
traceOrDebug(traceOn, "Creating a new instance of POJO class : " + getCommand().getClass());
}
Object commandObject = null;
try {
// instantiate a new command object each time
commandObject = getCommand().newInstance();
} catch (Exception e) {
handleException("Error creating an instance of the POJO command class : " +
getCommand().getClass(), e, synCtx);
}
if (traceOrDebugOn) {
traceOrDebug(traceOn, "Instance created, setting static and dynamic properties");
}
// then set the static/constant properties first
for (Iterator iter = getStaticSetterProperties().keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
setInstanceProperty(name, (String) getStaticSetterProperties().get(name), commandObject, synCtx);
}
for (Field f : beforeFields.keySet()) {
SynapseXPath xpath = beforeFields.get(f);
Object v;
if (f.getType().equals(String.class)) {
v = xpath.stringValueOf(synCtx);
} else {
throw new UnsupportedOperationException("non-String types not supportted yet");
}
try {
f.set(commandObject, v);
} catch (Exception e) {
e.printStackTrace();
}
}
for (Method m : beforeMethods.keySet()) {
SynapseXPath xpath = beforeMethods.get(m);
Object v;
if (m.getParameterTypes().length == 1 && m.getParameterTypes()[0].equals(String.class)) {
v = xpath.stringValueOf(synCtx);
} else {
throw new UnsupportedOperationException("non-String types not supportted yet");
}
try {
m.invoke(commandObject, v);
} catch (Exception e) {
e.printStackTrace();
}
}
if (traceOrDebugOn) {
traceOrDebug(traceOn, "POJO initialized successfully, invoking the execute() method");
}
// then call the execute method if the Command interface is implemented
if (commandObject instanceof Command) {
try {
((Command) commandObject).execute();
} catch (Exception e) {
handleException("Error invoking POJO command class : "
+ getCommand().getClass(), e, synCtx);
}
} else {
Method exeMethod = null;
try {
exeMethod = getCommand().getMethod("execute", new Class[]{});
exeMethod.invoke(commandObject, new Object[]{});
} catch (NoSuchMethodException e) {
handleException("Cannot locate an execute() method on POJO class : " +
getCommand().getClass(), e, synCtx);
} catch (Exception e) {
handleException("Error invoking the execute() method on POJO class : " +
getCommand().getClass(), e, synCtx);
}
}
// TODO: now update the MessageContext from the commandObject
if (traceOrDebugOn) {
traceOrDebug(traceOn, "End : POJOCommand mediator");
}
return true;
}
@Override
public void setCommand(Class commandClass) {
super.setCommand(commandClass);
introspectClass(commandClass);
}
/**
* Introspect the command class annotations
*/
protected void introspectClass(Class<?> commandClass) {
beforeFields = new HashMap<Field, SynapseXPath>();
afterFields = new HashMap<Field, SynapseXPath>();
beforeMethods = new HashMap<Method, SynapseXPath>();
afterMethods = new HashMap<Method, SynapseXPath>();
for (Field f : commandClass.getDeclaredFields()) {
ReadFromMessage readFromMessage = f.getAnnotation(ReadFromMessage.class);
if (readFromMessage != null) {
SynapseXPath axiomXpath = createSynapseXPATH(readFromMessage.value(), f.getAnnotation(Namespaces.class));
beforeFields.put(f, axiomXpath);
}
UpdateMessage updateMessage = f.getAnnotation(UpdateMessage.class);
if (updateMessage != null) {
SynapseXPath axiomXpath = createSynapseXPATH(updateMessage.value(), f.getAnnotation(Namespaces.class));
afterFields.put(f, axiomXpath);
}
ReadAndUpdate readAndUpdate = f.getAnnotation(ReadAndUpdate.class);
if (readAndUpdate != null) {
SynapseXPath axiomXpath = createSynapseXPATH(readAndUpdate.value(), f.getAnnotation(Namespaces.class));
beforeFields.put(f, axiomXpath);
afterFields.put(f, axiomXpath);
}
}
for (Method m : commandClass.getDeclaredMethods()) {
ReadFromMessage readFromMessage = m.getAnnotation(ReadFromMessage.class);
if (readFromMessage != null) {
SynapseXPath axiomXpath = createSynapseXPATH(readFromMessage.value(), m.getAnnotation(Namespaces.class));
beforeMethods.put(m, axiomXpath);
}
UpdateMessage updateMessage = m.getAnnotation(UpdateMessage.class);
if (updateMessage != null) {
SynapseXPath axiomXpath = createSynapseXPATH(updateMessage.value(), m.getAnnotation(Namespaces.class));
afterMethods.put(m, axiomXpath);
}
}
}
/**
* Create an SynapseXPath from an xpath string
*/
protected SynapseXPath createSynapseXPATH(String xpath, Namespaces nsAnnotation) {
Map<String, String> namespaces = getNamespaces(nsAnnotation);
try {
SynapseXPath axiomXPath = new SynapseXPath(xpath);
for (String prefix : namespaces.keySet()) {
axiomXPath.addNamespace(prefix, namespaces.get(prefix));
}
return axiomXPath;
} catch (JaxenException e) {
throw new RuntimeException("Error creating SynapseXPath: " + xpath, e);
}
}
/**
* Creates a Map of namespace prefixes and namespaces from a Namespace annotation
* and the default Namespace annotation on the command class.
*/
protected Map<String, String> getNamespaces(Namespaces namespaces) {
Map<String, String> allNamespaces = new HashMap<String, String>();
Namespaces defaultNamespaces = ((Class<?>)getCommand()).getAnnotation(Namespaces.class);
// First add any default namespaces
if (defaultNamespaces != null) {
for (String namespaceValue : defaultNamespaces.value()) {
int i = namespaceValue.indexOf(':');
if (i > 0) {
String prefix = namespaceValue.substring(0, i);
String namespace = namespaceValue.substring(i+1);
allNamespaces.put(prefix, namespace);
}
}
}
// add any namespaces which will overwrite any previously added default namespaces
if (namespaces != null) {
for (String namespaceValue : namespaces.value()) {
int i = namespaceValue.indexOf(':');
if (i > 0) {
String prefix = namespaceValue.substring(0, i);
String namespace = namespaceValue.substring(i+1);
allNamespaces.put(prefix, namespace);
}
}
}
return allNamespaces;
}
}