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: package org.apache.axis2.rpc.receivers.ejb;
020:
021: import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
022: import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
023: import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
024: import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
025: import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
026: import org.apache.axis2.AxisFault;
027: import org.apache.axis2.context.MessageContext;
028: import org.apache.axis2.description.AxisService;
029: import org.apache.axis2.description.Parameter;
030: import org.apache.axis2.util.threadpool.DefaultThreadFactory;
031:
032: import javax.naming.Context;
033: import javax.naming.InitialContext;
034: import java.lang.reflect.Method;
035: import java.security.AccessController;
036: import java.security.PrivilegedAction;
037: import java.util.Properties;
038:
039: public class EJBUtil {
040: public static final java.lang.String EJB_JNDI_NAME = "beanJndiName";
041: public static final java.lang.String EJB_HOME_INTERFACE_NAME = "homeInterfaceName";
042: public static final java.lang.String EJB_REMOTE_INTERFACE_NAME = "remoteInterfaceName";
043: public static final java.lang.String EJB_LOCAL_HOME_INTERFACE_NAME = "localHomeInterfaceName";
044: public static final java.lang.String EJB_LOCAL_INTERFACE_NAME = "localInterfaceName";
045: public static final java.lang.String EJB_INITIAL_CONTEXT_FACTORY = "jndiContextClass";
046: public static final java.lang.String EJB_PROVIDER_URL = "providerUrl";
047: public static final java.lang.String EJB_JNDI_USERNAME = "jndiUser";
048: public static final java.lang.String EJB_JNDI_PASSWORD = "jndiPassword";
049:
050: private static ExecutorService workerPool = null;
051:
052: static {
053: workerPool = new ThreadPoolExecutor(1, 50, 150L,
054: TimeUnit.SECONDS, new LinkedBlockingQueue(),
055: new DefaultThreadFactory(new ThreadGroup(
056: "EJB provider thread group"), "EJBProvider"));
057: }
058:
059: /**
060: * Return a object which implements the service.
061: *
062: * @param msgContext the message context
063: * @return an object that implements the service
064: * @throws AxisFault if fails
065: */
066: protected static Object makeNewServiceObject(
067: MessageContext msgContext) throws AxisFault {
068: CountDownLatch startLatch = new CountDownLatch(1);
069: CountDownLatch stopLatch = new CountDownLatch(1);
070: EJBClientWorker worker = new EJBClientWorker(msgContext,
071: startLatch, stopLatch);
072: workerPool.execute(worker);
073: startLatch.countDown();
074: try {
075: stopLatch.await();
076: } catch (InterruptedException e) {
077: throw AxisFault.makeFault(e);
078: }
079:
080: if (worker.getException() != null) {
081: throw AxisFault.makeFault(worker.getException());
082: }
083:
084: return worker.getReturnedValue();
085: }
086:
087: private static class EJBClientWorker implements Runnable {
088:
089: private MessageContext msgContext = null;
090: private CountDownLatch startLatch = null;
091: private CountDownLatch stopLatch = null;
092: protected static final Class[] empty_class_array = new Class[0];
093: protected static final Object[] empty_object_array = new Object[0];
094: private static InitialContext cached_context = null;
095: private Exception exception = null;
096: private Object returnedValue = null;
097:
098: public EJBClientWorker(MessageContext msgContext,
099: CountDownLatch startLatch, CountDownLatch stopLatch) {
100: this .msgContext = msgContext;
101: this .startLatch = startLatch;
102: this .stopLatch = stopLatch;
103: }
104:
105: public void run() {
106: try {
107: startLatch.await();
108: final AxisService service = msgContext.getAxisService();
109: AccessController.doPrivileged(new PrivilegedAction() {
110: public Object run() {
111: Thread.currentThread().setContextClassLoader(
112: service.getClassLoader());
113: return null;
114: }
115: });
116: Parameter remoteHomeName = service
117: .getParameter(EJB_HOME_INTERFACE_NAME);
118: Parameter localHomeName = service
119: .getParameter(EJB_LOCAL_HOME_INTERFACE_NAME);
120: Parameter jndiName = service
121: .getParameter(EJB_JNDI_NAME);
122: Parameter homeName = (remoteHomeName != null ? remoteHomeName
123: : localHomeName);
124:
125: if (jndiName == null || jndiName.getValue() == null) {
126: throw new AxisFault("jndi name is not specified");
127: } else if (homeName == null
128: || homeName.getValue() == null) {
129: // cannot find both remote home and local home
130: throw new AxisFault(
131: "ejb remote/local home class name is not specified");
132: }
133:
134: // we create either the ejb using either the RemoteHome or LocalHome object
135: if (remoteHomeName != null)
136: returnedValue = createRemoteEJB(msgContext,
137: ((String) jndiName.getValue()).trim(),
138: ((String) homeName.getValue()).trim());
139: else
140: returnedValue = createLocalEJB(msgContext,
141: ((String) jndiName.getValue()).trim(),
142: ((String) homeName.getValue()).trim());
143: } catch (Exception e) {
144: e.printStackTrace();
145: exception = e;
146: } finally {
147: stopLatch.countDown();
148: }
149: }
150:
151: /**
152: * Create an EJB using a remote home object
153: *
154: * @param msgContext the message context
155: * @param beanJndiName The JNDI name of the EJB remote home class
156: * @param homeName the name of the home interface class
157: * @return an EJB
158: * @throws Exception If fails
159: */
160: private Object createRemoteEJB(MessageContext msgContext,
161: String beanJndiName, String homeName) throws Exception {
162: // Get the EJB Home object from JNDI
163: Object ejbHome = getEJBHome(msgContext.getAxisService(),
164: beanJndiName);
165: Class cls = getContextClassLoader().loadClass(homeName);
166: Object ehome = javax.rmi.PortableRemoteObject.narrow(
167: ejbHome, cls);
168:
169: // Invoke the create method of the ejbHome class without actually
170: // touching any EJB classes (i.e. no cast to EJBHome)
171: Method createMethod = cls.getMethod("create",
172: empty_class_array);
173:
174: return createMethod.invoke(ehome, empty_object_array);
175: }
176:
177: /**
178: * Create an EJB using a local home object
179: *
180: * @param msgContext the message context
181: * @param beanJndiName The JNDI name of the EJB local home class
182: * @param homeName the name of the home interface class
183: * @return an EJB
184: * @throws Exception if fails
185: */
186: private Object createLocalEJB(MessageContext msgContext,
187: String beanJndiName, String homeName) throws Exception {
188: // Get the EJB Home object from JNDI
189: Object ejbHome = getEJBHome(msgContext.getAxisService(),
190: beanJndiName);
191:
192: // the home object is a local home object
193: Object ehome;
194:
195: Class cls = getContextClassLoader().loadClass(homeName);
196:
197: if (cls.isInstance(ejbHome))
198: ehome = ejbHome;
199: else {
200: throw new ClassCastException("bad ejb home type");
201: }
202:
203: // Invoke the create method of the ejbHome class without actually
204: // touching any EJB classes (i.e. no cast to EJBLocalHome)
205: Method createMethod = cls.getMethod("create",
206: empty_class_array);
207:
208: return createMethod.invoke(ehome, empty_object_array);
209: }
210:
211: /**
212: * Common routine to do the JNDI lookup on the Home interface object username and password
213: * for jndi lookup are got from the configuration or from the messageContext if not found in
214: * the configuration
215: *
216: * @param service AxisService object
217: * @param beanJndiName JNDI name of the EJB home object
218: * @return EJB home object
219: * @throws AxisFault If fals
220: */
221: private Object getEJBHome(AxisService service,
222: String beanJndiName) throws AxisFault {
223: Object ejbHome;
224:
225: // Set up an InitialContext and use it get the beanJndiName from JNDI
226: try {
227: Properties properties = null;
228:
229: // collect all the properties we need to access JNDI:
230: // username, password, factoryclass, contextUrl
231:
232: // username
233: Parameter username = service
234: .getParameter(EJB_JNDI_USERNAME);
235: if (username != null) {
236: if (properties == null)
237: properties = new Properties();
238: properties.setProperty(Context.SECURITY_PRINCIPAL,
239: ((String) username.getValue()).trim());
240: }
241:
242: // password
243: Parameter password = service
244: .getParameter(EJB_JNDI_PASSWORD);
245: if (password != null) {
246: if (properties == null)
247: properties = new Properties();
248: properties.setProperty(
249: Context.SECURITY_CREDENTIALS,
250: ((String) password.getValue()).trim());
251: }
252:
253: // factory class
254: Parameter factoryClass = service
255: .getParameter(EJB_INITIAL_CONTEXT_FACTORY);
256: if (factoryClass != null) {
257: if (properties == null)
258: properties = new Properties();
259: properties.setProperty(
260: Context.INITIAL_CONTEXT_FACTORY,
261: ((String) factoryClass.getValue()).trim());
262: }
263:
264: // contextUrl
265: Parameter contextUrl = service
266: .getParameter(EJB_PROVIDER_URL);
267: if (contextUrl != null) {
268: if (properties == null)
269: properties = new Properties();
270: properties.setProperty(Context.PROVIDER_URL,
271: ((String) contextUrl.getValue()).trim());
272: }
273:
274: // get context using these properties
275: InitialContext context = getContext(properties);
276:
277: // if we didn't get a context, fail
278: if (context == null)
279: throw new AxisFault("cannot create initial context");
280:
281: ejbHome = getEJBHome(context, beanJndiName);
282:
283: if (ejbHome == null)
284: throw new AxisFault("cannot find jndi home");
285: } catch (Exception exception) {
286: throw AxisFault.makeFault(exception);
287: }
288:
289: return ejbHome;
290: }
291:
292: private InitialContext getCachedContext()
293: throws javax.naming.NamingException {
294: if (cached_context == null)
295: cached_context = new InitialContext();
296: return cached_context;
297: }
298:
299: private InitialContext getContext(Properties properties)
300: throws AxisFault, javax.naming.NamingException {
301: return ((properties == null) ? getCachedContext()
302: : new InitialContext(properties));
303: }
304:
305: private Object getEJBHome(InitialContext context,
306: String beanJndiName) throws AxisFault,
307: javax.naming.NamingException {
308: return context.lookup(beanJndiName);
309: }
310:
311: private ClassLoader getContextClassLoader() {
312: return (ClassLoader) AccessController
313: .doPrivileged(new PrivilegedAction() {
314: public Object run() {
315: return Thread.currentThread()
316: .getContextClassLoader();
317: }
318: });
319: }
320:
321: public Exception getException() {
322: return exception;
323: }
324:
325: public Object getReturnedValue() {
326: return returnedValue;
327: }
328: }
329: }
|