001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2007 Danet GmbH (www.danet.de), BU BTS.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: EJBInvoker.java,v 1.2 2007/03/27 21:59:43 mlipp Exp $
021: *
022: * $Log: EJBInvoker.java,v $
023: * Revision 1.2 2007/03/27 21:59:43 mlipp
024: * Fixed lots of checkstyle warnings.
025: *
026: * Revision 1.1 2007/03/22 13:50:44 schnelle
027: * Initial release.
028: *
029: */
030: package de.danet.an.workflow.tools;
031:
032: import java.lang.reflect.InvocationTargetException;
033: import java.lang.reflect.Method;
034: import java.rmi.RemoteException;
035: import java.util.HashMap;
036: import java.util.Map;
037:
038: import javax.ejb.EJBHome;
039: import javax.ejb.EJBMetaData;
040: import javax.ejb.EJBObject;
041: import javax.naming.NamingException;
042:
043: import de.danet.an.util.EJBUtil;
044: import de.danet.an.workflow.api.Activity;
045: import de.danet.an.workflow.api.FormalParameter;
046: import de.danet.an.workflow.api.SAXEventBuffer;
047: import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
048: import de.danet.an.workflow.spis.aii.CannotExecuteException;
049: import de.danet.an.workflow.spis.aii.ResultProvider;
050: import de.danet.an.workflow.spis.aii.ToolAgent;
051: import de.danet.an.workflow.util.XPDLUtil;
052:
053: /**
054: * This class provides a facility to call EJBs.
055: *
056: * @author Dirk Schnelle
057: *
058: */
059: public class EJBInvoker implements ToolAgent, ResultProvider {
060: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
061: .getLog(EJBInvoker.class);
062:
063: /** The result container. */
064: private ThreadLocal result = new ThreadLocal();
065:
066: /* (non-Javadoc)
067: * Comment copied from interface or super class.
068: */
069: public void invoke(Activity activity,
070: FormalParameter[] formalParameters, Map actualParameters)
071: throws RemoteException, CannotExecuteException {
072: int len = formalParameters.length;
073: if (len < 3) {
074: throw new CannotExecuteException(
075: "Too few arguments. "
076: + "At least JndiName, HomeClass, and Method are required!");
077: }
078:
079: String jndiName = (String) actualParameters
080: .get(formalParameters[0].id());
081: String homeClassName = (String) actualParameters
082: .get(formalParameters[1].id());
083: String methodName = (String) actualParameters
084: .get(formalParameters[2].id());
085:
086: int numArgs = len - 3;
087: String returnParam = null;
088: if (len > 3) {
089: FormalParameter.Mode lastParamMode = formalParameters[len - 1]
090: .mode();
091: if ((lastParamMode == FormalParameter.Mode.OUT)
092: || (lastParamMode == FormalParameter.Mode.INOUT)) {
093: returnParam = formalParameters[len - 1].id();
094:
095: numArgs--;
096: }
097: }
098:
099: Object[] args = new Object[numArgs];
100: Class[] sig = new Class[numArgs];
101:
102: parseArguments(formalParameters, actualParameters, numArgs,
103: args, sig);
104:
105: Class homeClass;
106: try {
107: ClassLoader cl = Thread.currentThread()
108: .getContextClassLoader();
109: homeClass = cl.loadClass(homeClassName);
110: } catch (ClassNotFoundException e) {
111: throw new CannotExecuteException("cannot load HomeClass '"
112: + homeClassName + "'");
113: }
114:
115: if (logger.isDebugEnabled()) {
116: String str = getDebugMethodCall(formalParameters, jndiName,
117: homeClassName, methodName, numArgs, args, sig);
118:
119: logger.debug(str);
120: }
121:
122: Object callResult;
123: try {
124: callResult = callEJB(jndiName, homeClass, methodName, sig,
125: args);
126: } catch (NamingException e) {
127: throw new CannotExecuteException(e.getMessage(), e);
128: } catch (IllegalArgumentException e) {
129: throw new CannotExecuteException(e.getMessage(), e);
130: } catch (IllegalAccessException e) {
131: throw new CannotExecuteException(e.getMessage(), e);
132: } catch (InvocationTargetException e) {
133: throw new CannotExecuteException(e.getMessage(), e);
134: } catch (NoSuchMethodException e) {
135: throw new CannotExecuteException(e.getMessage(), e);
136: }
137:
138: if (returnParam != null) {
139: Map resData = new HashMap();
140:
141: resData.put(returnParam, callResult);
142:
143: result.set(resData);
144: }
145: }
146:
147: /**
148: * Parses the given arguments to create the signature and the arguments
149: * for the method call.
150: * @param formalParameters formal parameters of the tool
151: * @param actualParameters values for the parameters
152: * @param numArgs number of arguments
153: * @param args values for the method call (must be of size
154: * <code>numArgs</code>
155: * @param sig signature of the method (must be of size
156: * <code>numArgs</code>
157: * @throws CannotExecuteException
158: * Unknown parameter type.
159: */
160: private void parseArguments(FormalParameter[] formalParameters,
161: Map actualParameters, int numArgs, Object[] args,
162: Class[] sig) throws CannotExecuteException {
163: for (int i = 0; i < numArgs; i++) {
164: String id = formalParameters[i + 3].id();
165: args[i] = actualParameters.get(id);
166: Object type = formalParameters[i + 3].type();
167: if (type.equals(Long.class)) {
168: sig[i] = long.class;
169: } else if (type.equals(Boolean.class)) {
170: sig[i] = boolean.class;
171: } else if (type.equals(Double.class)) {
172: sig[i] = double.class;
173: } else if (XPDLUtil.isXMLType(type)) {
174: if (args[i] instanceof SAXEventBuffer) {
175: sig[i] = SAXEventBuffer.class;
176: } else if (args[i] instanceof org.w3c.dom.DocumentFragment) {
177: sig[i] = org.w3c.dom.DocumentFragment.class;
178: } else if (args[i] instanceof org.jdom.Element) {
179: sig[i] = org.jdom.Element.class;
180: } else {
181: String msg = "Got argument of XML type, but cannot"
182: + " recognize value's class: "
183: + args[i].getClass();
184: throw new CannotExecuteException(msg);
185: }
186: } else {
187: sig[i] = (Class) type;
188: }
189: }
190: }
191:
192: /**
193: * Create a human readable output of the method call.
194: * @param formalParameters
195: * @param jndiName
196: * @param homeClassName
197: * @param methodName
198: * @param numArgs
199: * @param args
200: * @param sig
201: * @return
202: */
203: private String getDebugMethodCall(
204: FormalParameter[] formalParameters, String jndiName,
205: String homeClassName, String methodName, int numArgs,
206: Object[] args, Class[] sig) {
207: StringBuffer str = new StringBuffer();
208:
209: str.append("calling ");
210: str.append(homeClassName);
211: str.append(" (");
212: str.append(jndiName);
213: str.append(") ");
214: str.append(methodName);
215: str.append("(");
216: for (int i = 0; i < numArgs; i++) {
217: if (XPDLUtil.isXMLType(formalParameters[i + 3].type())) {
218: str.append("XML");
219: } else {
220: if (sig[i].equals(String.class)) {
221: str.append("\"");
222: }
223: str.append(args[i]);
224: if (sig[i].equals(String.class)) {
225: str.append("\"");
226: }
227: }
228: if (i != numArgs - 1) {
229: str.append(", ");
230: }
231: }
232: str.append(")");
233:
234: return str.toString();
235: }
236:
237: /**
238: * Call the EJB.
239: * @param jndiName the JNDI name of the EJB
240: * @param homeClass the home class of the EJB
241: * @param method the name of the method to call.
242: * @param sig the signature of the method to call
243: * @param args the arguments to provide in the call
244: * @return Result of invocation.
245: * @throws NamingException
246: * JNDI name could not be resolved.
247: * @throws RemoteException
248: * Error accessing the EJB
249: * @throws IllegalArgumentException
250: * Error in the signature.
251: * @throws IllegalAccessException
252: * Method is not accessible.
253: * @throws InvocationTargetException
254: * Error in method call.
255: * @throws NoSuchMethodException
256: * Method is unknown.
257: */
258: private Object callEJB(String jndiName, Class homeClass,
259: String method, Class[] sig, Object[] args)
260: throws NamingException, RemoteException,
261: IllegalArgumentException, IllegalAccessException,
262: InvocationTargetException, NoSuchMethodException {
263: EJBHome home = EJBUtil.lookupEJBHome(homeClass, jndiName);
264: EJBMetaData md = home.getEJBMetaData();
265: EJBObject remote = (EJBObject) invoke(homeClass, home,
266: "create", null, null);
267: Class remoteClass = md.getRemoteInterfaceClass();
268:
269: return invoke(remoteClass, remote, method, sig, args);
270: }
271:
272: /**
273: * Convenience method to call a method on the given object.
274: * @param clazz The class of the object.
275: * @param obj the object.
276: * @param methodName the name of the method to call.
277: * @param sig the signature of the method.
278: * @param args the arguments to provide.
279: * @return result of the method call.
280: * @throws IllegalArgumentException
281: * @throws IllegalAccessException
282: * @throws InvocationTargetException
283: * @throws NoSuchMethodException
284: */
285: private Object invoke(Class clazz, Object obj, String methodName,
286: Class[] sig, Object[] args)
287: throws IllegalArgumentException, IllegalAccessException,
288: InvocationTargetException, NoSuchMethodException {
289: Method method = clazz.getMethod(methodName, sig);
290:
291: return method.invoke(obj, args);
292: }
293:
294: /* (non-Javadoc)
295: * Comment copied from interface or super class.
296: */
297: public void terminate(Activity activity)
298: throws ApplicationNotStoppedException, RemoteException {
299: throw new ApplicationNotStoppedException(
300: "Terminate not implemented for EJBTool.");
301: }
302:
303: /* (non-Javadoc)
304: * Comment copied from interface or super class.
305: */
306: public Object result() {
307: Object res = result.get();
308:
309: result.set(null);
310:
311: return res;
312: }
313: }
|