001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.synapse.mediators.ext;
021:
022: import org.apache.axiom.om.OMAbstractFactory;
023: import org.apache.axiom.om.OMElement;
024: import org.apache.axiom.om.OMNode;
025: import org.apache.synapse.Command;
026: import org.apache.synapse.MessageContext;
027: import org.apache.synapse.mediators.AbstractMediator;
028: import org.apache.synapse.mediators.eip.EIPUtils;
029: import org.apache.synapse.util.xpath.SynapseXPath;
030: import org.jaxen.JaxenException;
031:
032: import java.lang.reflect.InvocationTargetException;
033: import java.lang.reflect.Method;
034: import java.util.HashMap;
035: import java.util.Iterator;
036: import java.util.List;
037: import java.util.Map;
038:
039: /**
040: * This mediator will use the specified command object and execute the command after setting
041: * the properties specified to it through the configuraiton. The specified command object may or
042: * may not implement the Command interface. If the Command object has not implemented the Command
043: * interface then this will use reflection to find a method called execute() and execute it.
044: *
045: * @see org.apache.synapse.Command interface
046: */
047: public class POJOCommandMediator extends AbstractMediator {
048:
049: /**
050: * This will hold the command object to be executed
051: */
052: private Class command = null;
053:
054: /**
055: * 'static' properties whose values are constant and does not depend
056: * on the current message (i.e. and XPath over it)
057: */
058: private Map<String, Object> staticSetterProperties = new HashMap<String, Object>();
059:
060: /**
061: * 'dynamic' properties whose values are dynamically evaluated before each
062: * invocation of the command, by evaluating an XPath against the current message
063: */
064: private Map<String, SynapseXPath> messageSetterProperties = new HashMap<String, SynapseXPath>();
065:
066: /**
067: * 'dynamic' properties whose values are dynamically evaluated before each
068: * invocation of the command, by getting a property from the message context
069: */
070: private Map<String, String> contextSetterProperties = new HashMap<String, String>();
071:
072: /**
073: * 'context' properties whose values are set back to the message context as message
074: * context properties
075: */
076: private Map<String, String> contextGetterProperties = new HashMap<String, String>();
077:
078: /**
079: * 'messsage' properties whose values are set back to the current message, from the command
080: * and as specified by the XPATH
081: */
082: private Map<String, SynapseXPath> messageGetterProperties = new HashMap<String, SynapseXPath>();
083:
084: /**
085: * Implements the mediate method of the Mediator interface. This method will instantiate
086: * a new instance of the POJO class, set all specified properties from the current runtime
087: * state (and message context) and call the execute method of the Command object.
088: *
089: * @param synCtx - Synapse MessageContext to be mediated
090: * @return boolean true since this will not stop exection chain
091: */
092: public boolean mediate(MessageContext synCtx) {
093:
094: boolean traceOn = isTraceOn(synCtx);
095: boolean traceOrDebugOn = isTraceOrDebugOn(traceOn);
096:
097: if (traceOrDebugOn) {
098: traceOrDebug(traceOn, "Start : POJOCommand mediator");
099:
100: if (traceOn && trace.isTraceEnabled()) {
101: trace.trace("Message : " + synCtx.getEnvelope());
102: }
103: }
104:
105: if (traceOrDebugOn) {
106: traceOrDebug(traceOn,
107: "Creating a new instance of POJO class : "
108: + command.getClass());
109: }
110:
111: Object commandObject = null;
112: try {
113: // instantiate a new command object each time
114: commandObject = command.newInstance();
115: } catch (Exception e) {
116: handleException(
117: "Error creating an instance of the POJO command class : "
118: + command.getClass(), e, synCtx);
119: }
120:
121: if (traceOrDebugOn) {
122: traceOrDebug(traceOn,
123: "Instance created, setting static and dynamic properties");
124: }
125:
126: // then set the static/constant properties first
127: for (Iterator iter = staticSetterProperties.keySet().iterator(); iter
128: .hasNext();) {
129: String name = (String) iter.next();
130: setInstanceProperty(name, staticSetterProperties.get(name),
131: commandObject, synCtx);
132: }
133:
134: // now set the any dynamic properties from the message context properties
135: for (Iterator iter = contextSetterProperties.keySet()
136: .iterator(); iter.hasNext();) {
137: String name = (String) iter.next();
138: setInstanceProperty(name, synCtx
139: .getProperty(contextSetterProperties.get(name)),
140: commandObject, synCtx);
141: }
142:
143: // now set the any dynamic properties evaluating XPath's on the current message
144: for (Iterator iter = messageSetterProperties.keySet()
145: .iterator(); iter.hasNext();) {
146:
147: String name = (String) iter.next();
148: SynapseXPath xpath = messageSetterProperties.get(name);
149: String value = xpath.getStringValue(synCtx);
150:
151: setInstanceProperty(name, value, commandObject, synCtx);
152: }
153:
154: if (traceOrDebugOn) {
155: traceOrDebug(traceOn,
156: "POJO initialized successfully, invoking the execute() method");
157: }
158:
159: // then call the execute method if the Command interface is implemented
160: if (commandObject instanceof Command) {
161: try {
162: ((Command) commandObject).execute();
163: } catch (Exception e) {
164: handleException("Error invoking POJO command class : "
165: + command.getClass(), e, synCtx);
166: }
167:
168: } else {
169:
170: Method exeMethod = null;
171: try {
172: exeMethod = command
173: .getMethod("execute", new Class[] {});
174: exeMethod.invoke(commandObject, new Object[] {});
175: } catch (NoSuchMethodException e) {
176: handleException(
177: "Cannot locate an execute() method on POJO class : "
178: + command.getClass(), e, synCtx);
179: } catch (Exception e) {
180: handleException(
181: "Error invoking the execute() method on POJO class : "
182: + command.getClass(), e, synCtx);
183: }
184: }
185:
186: // then set the context properties back to the messageContext from the command
187: for (Iterator iter = contextGetterProperties.keySet()
188: .iterator(); iter.hasNext();) {
189: String name = (String) iter.next();
190: synCtx.setProperty(contextGetterProperties.get(name),
191: getInstanceProperty(name, commandObject, synCtx));
192: }
193:
194: // now set the any message properties evaluating XPath's on the current message back
195: // to the message from the command
196: for (Iterator iter = messageGetterProperties.keySet()
197: .iterator(); iter.hasNext();) {
198:
199: String name = (String) iter.next();
200: SynapseXPath xpath = messageGetterProperties.get(name);
201:
202: Object resultValue = getInstanceProperty(name,
203: commandObject, synCtx);
204:
205: try {
206: List list = EIPUtils.getMatchingElements(synCtx
207: .getEnvelope(), xpath);
208: if (list.size() > 0) {
209: Object o = list.get(0);
210: if (resultValue instanceof String) {
211: OMAbstractFactory.getOMFactory().createOMText(
212: ((OMNode) o).getParent(),
213: (String) resultValue);
214: ((OMNode) o).detach();
215: } else if (resultValue instanceof OMNode) {
216: ((OMNode) o)
217: .insertSiblingAfter((OMNode) resultValue);
218: ((OMNode) o).detach();
219: }
220:
221: } else {
222: if (traceOrDebugOn) {
223: traceOrDebug(
224: traceOn,
225: "Unable to set the message property "
226: + resultValue
227: + "back to the message : Specified element by the xpath "
228: + xpath + " can not be found");
229: }
230: }
231: } catch (JaxenException e) {
232: handleException("Unable to set the command property "
233: + name + " back to the message", e, synCtx);
234: }
235: }
236:
237: if (traceOrDebugOn) {
238: traceOrDebug(traceOn, "End : POJOCommand mediator");
239: }
240: return true;
241: }
242:
243: /**
244: * Find and invoke the getter method with the name of form getXXX and returns the value given
245: * on the POJO object
246: *
247: * @param name name of the getter field
248: * @param obj POJO instance
249: * @param synCtx current message
250: * @return object representing the value of the getter method
251: */
252: private Object getInstanceProperty(String name, Object obj,
253: MessageContext synCtx) {
254:
255: String mName = "get" + Character.toUpperCase(name.charAt(0))
256: + name.substring(1);
257: try {
258: Method[] methods = obj.getClass().getMethods();
259:
260: for (Method method : methods) {
261: if (mName.equals(method.getName())) {
262: return method.invoke(obj);
263: }
264: }
265: } catch (InvocationTargetException e) {
266: handleException("Unable to get the command property '"
267: + name + "' back to the message", e, synCtx);
268: } catch (IllegalAccessException e) {
269: handleException("Unable to get the command property '"
270: + name + "' back to the message", e, synCtx);
271: }
272:
273: return null;
274: }
275:
276: /**
277: * Find and invoke the setter method with the name of form setXXX passing in the value given
278: * on the POJO object
279: *
280: * @param name name of the setter field
281: * @param value value to be set
282: * @param obj POJO instance
283: * @param synCtx current message
284: */
285: protected void setInstanceProperty(String name, Object value,
286: Object obj, MessageContext synCtx) {
287:
288: String mName = "set" + Character.toUpperCase(name.charAt(0))
289: + name.substring(1);
290: Method method = null;
291:
292: try {
293: Method[] methods = obj.getClass().getMethods();
294: boolean invoked = false;
295:
296: for (int i = 0; i < methods.length; i++) {
297: if (mName.equals(methods[i].getName())) {
298: Class[] params = methods[i].getParameterTypes();
299: if (params.length != 1) {
300: handleException(
301: "Did not find a setter method named : "
302: + mName
303: + "() that takes a single String, int, long, float, double "
304: + "or boolean or OMElement parameter",
305: synCtx);
306: } else if (value instanceof String) {
307: if (params[0].equals(String.class)) {
308: method = obj.getClass().getMethod(mName,
309: new Class[] { String.class });
310: method.invoke(obj,
311: new String[] { (String) value });
312: } else if (params[0].equals(int.class)) {
313: method = obj.getClass().getMethod(mName,
314: new Class[] { int.class });
315: method.invoke(obj,
316: new Integer[] { new Integer(
317: (String) value) });
318: } else if (params[0].equals(long.class)) {
319: method = obj.getClass().getMethod(mName,
320: new Class[] { long.class });
321: method.invoke(obj, new Long[] { new Long(
322: (String) value) });
323: } else if (params[0].equals(float.class)) {
324: method = obj.getClass().getMethod(mName,
325: new Class[] { float.class });
326: method.invoke(obj, new Float[] { new Float(
327: (String) value) });
328: } else if (params[0].equals(double.class)) {
329: method = obj.getClass().getMethod(mName,
330: new Class[] { double.class });
331: method.invoke(obj,
332: new Double[] { new Double(
333: (String) value) });
334: } else if (params[0].equals(boolean.class)) {
335: method = obj.getClass().getMethod(mName,
336: new Class[] { boolean.class });
337: method.invoke(obj,
338: new Boolean[] { new Boolean(
339: (String) value) });
340: } else {
341: handleException(
342: "Did not find a setter method named : "
343: + mName
344: + "() that takes a single String, int, long, float, double "
345: + "or boolean parameter",
346: synCtx);
347: }
348: } else if (value instanceof OMElement) {
349: if (params[0].equals(OMElement.class)) {
350: method = obj.getClass().getMethod(mName,
351: new Class[] { OMElement.class });
352: method
353: .invoke(
354: obj,
355: new OMElement[] { (OMElement) value });
356: } else {
357: handleException(
358: "Did not find a setter method named : "
359: + mName
360: + "() that takes an OMElement as the parameter",
361: synCtx);
362: }
363: } else {
364: handleException(
365: "Can not handle the value type : "
366: + value.getClass(), synCtx);
367: }
368: invoked = true;
369: }
370: }
371:
372: if (!invoked) {
373: handleException(
374: "Did not find a setter method named : "
375: + mName
376: + "() that takes a single String, int, long, float, double "
377: + "or boolean parameter", synCtx);
378: }
379:
380: } catch (Exception e) {
381: handleException(
382: "Error invoking setter method named : "
383: + mName
384: + "() that takes a single String, int, long, float, double "
385: + "or boolean parameter", e, synCtx);
386: }
387: }
388:
389: public Class getCommand() {
390: return command;
391: }
392:
393: public void setCommand(Class command) {
394: this .command = command;
395: }
396:
397: public void addStaticSetterProperty(String name, Object value) {
398: this .staticSetterProperties.put(name, value);
399: }
400:
401: public void addMessageSetterProperty(String name, SynapseXPath xpath) {
402: this .messageSetterProperties.put(name, xpath);
403: }
404:
405: public void addContextSetterProperty(String name, String ctxName) {
406: this .contextSetterProperties.put(name, ctxName);
407: }
408:
409: public void addContextGetterProperty(String name, String value) {
410: this .contextGetterProperties.put(name, value);
411: }
412:
413: public void addMessageGetterProperty(String name, SynapseXPath xpath) {
414: this .messageGetterProperties.put(name, xpath);
415: }
416:
417: public Map<String, Object> getStaticSetterProperties() {
418: return this .staticSetterProperties;
419: }
420:
421: public Map<String, SynapseXPath> getMessageSetterProperties() {
422: return this .messageSetterProperties;
423: }
424:
425: public Map<String, String> getContextSetterProperties() {
426: return this .contextSetterProperties;
427: }
428:
429: public Map<String, String> getContextGetterProperties() {
430: return this .contextGetterProperties;
431: }
432:
433: public Map<String, SynapseXPath> getMessageGetterProperties() {
434: return this.messageGetterProperties;
435: }
436: }
|