001: /*
002: * JBoss, Home of Professional Open Source
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors as indicated
004: * by the @authors tag. See the copyright.txt in the distribution for a
005: * full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb3.client;
023:
024: import java.lang.annotation.Annotation;
025: import java.lang.reflect.AccessibleObject;
026: import java.lang.reflect.Field;
027: import java.lang.reflect.InvocationTargetException;
028: import java.lang.reflect.Method;
029: import java.lang.reflect.Modifier;
030: import java.util.ArrayList;
031: import java.util.Collection;
032: import java.util.HashMap;
033: import java.util.List;
034: import java.util.Map;
035:
036: import javax.annotation.PostConstruct;
037: import javax.naming.Context;
038: import javax.naming.InitialContext;
039: import javax.naming.NameClassPair;
040: import javax.naming.NameNotFoundException;
041: import javax.naming.NamingEnumeration;
042:
043: import org.jboss.ejb3.Container;
044: import org.jboss.ejb3.DependencyPolicy;
045: import org.jboss.ejb3.entity.PersistenceUnitDeployment;
046: import org.jboss.ejb3.metamodel.ApplicationClientDD;
047: import org.jboss.ejb3.metamodel.LifecycleCallback;
048: import org.jboss.injection.DependsHandler;
049: import org.jboss.injection.EJBHandler;
050: import org.jboss.injection.EncInjector;
051: import org.jboss.injection.InjectionContainer;
052: import org.jboss.injection.InjectionHandler;
053: import org.jboss.injection.InjectionUtil;
054: import org.jboss.injection.Injector;
055: import org.jboss.injection.JndiInjectHandler;
056: import org.jboss.injection.PersistenceContextHandler;
057: import org.jboss.injection.PersistenceUnitHandler;
058: import org.jboss.injection.ResourceHandler;
059: import org.jboss.injection.WebServiceRefHandler;
060: import org.jboss.logging.Logger;
061: import org.jboss.metamodel.descriptor.EnvironmentRefGroup;
062: import org.jboss.util.NotImplementedException;
063:
064: //import org.jboss.virtual.VirtualFile;
065:
066: /**
067: * Injection of the application client main class is handled from here.
068: *
069: * @author <a href="mailto:carlo.dewolf@jboss.com">Carlo de Wolf</a>
070: * @version $Revision: $
071: */
072: public class ClientContainer implements InjectionContainer {
073: private static final Logger log = Logger
074: .getLogger(ClientContainer.class);
075:
076: private Class<?> mainClass;
077: private ApplicationClientDD xml;
078: private String applicationClientName;
079:
080: // for performance there is an array.
081: private List<Injector> injectors = new ArrayList<Injector>();
082: private Map<String, Map<AccessibleObject, Injector>> encInjections = new HashMap<String, Map<AccessibleObject, Injector>>();
083: private Map<String, EncInjector> encInjectors = new HashMap<String, EncInjector>();
084:
085: private Context enc;
086: private Context encEnv;
087:
088: private List<Method> postConstructs = new ArrayList<Method>();
089:
090: public ClientContainer(ApplicationClientDD xml, Class<?> mainClass,
091: String applicationClientName) throws Exception {
092: this .xml = xml;
093: this .mainClass = mainClass;
094: this .applicationClientName = applicationClientName;
095:
096: //Context ctx = getInitialContext();
097: Context ctx = new InitialContext();
098: enc = (Context) ctx.lookup(applicationClientName);
099: NamingEnumeration<NameClassPair> e = enc.list("");
100: while (e.hasMore()) {
101: NameClassPair ncp = e.next();
102: log.debug(" " + ncp);
103: }
104: encEnv = (Context) enc.lookup("env");
105: // enc = ThreadLocalENCFactory.create(ctx);
106: // encEnv = Util.createSubcontext(enc, "env");
107:
108: processMetadata(null);
109:
110: // for (EncInjector injector : encInjectors.values())
111: // {
112: // log.trace("encInjector: " + injector);
113: // injector.inject(this);
114: // }
115:
116: for (Injector injector : injectors) {
117: log.trace("injector: " + injector);
118: injector.inject((Object) null);
119: }
120:
121: postConstruct();
122: }
123:
124: /* (non-Javadoc)
125: * @see org.jboss.injection.InjectionContainer#getAnnotation(java.lang.Class, java.lang.Class)
126: */
127: public <T extends Annotation> T getAnnotation(
128: Class<T> annotationClass, Class<?> clazz) {
129: return clazz.getAnnotation(annotationClass);
130: }
131:
132: /* (non-Javadoc)
133: * @see org.jboss.injection.InjectionContainer#getAnnotation(java.lang.Class, java.lang.Class, java.lang.reflect.Method)
134: */
135: public <T extends Annotation> T getAnnotation(
136: Class<T> annotationClass, Class<?> clazz, Method method) {
137: return method.getAnnotation(annotationClass);
138: }
139:
140: /* (non-Javadoc)
141: * @see org.jboss.injection.InjectionContainer#getAnnotation(java.lang.Class, java.lang.reflect.Method)
142: */
143: public <T extends Annotation> T getAnnotation(
144: Class<T> annotationClass, Method method) {
145: return method.getAnnotation(annotationClass);
146: }
147:
148: /* (non-Javadoc)
149: * @see org.jboss.injection.InjectionContainer#getAnnotation(java.lang.Class, java.lang.Class, java.lang.reflect.Field)
150: */
151: public <T extends Annotation> T getAnnotation(
152: Class<T> annotationClass, Class<?> clazz, Field field) {
153: return field.getAnnotation(annotationClass);
154: }
155:
156: /* (non-Javadoc)
157: * @see org.jboss.injection.InjectionContainer#getAnnotation(java.lang.Class, java.lang.reflect.Field)
158: */
159: public <T extends Annotation> T getAnnotation(
160: Class<T> annotationClass, Field field) {
161: return field.getAnnotation(annotationClass);
162: }
163:
164: /* (non-Javadoc)
165: * @see org.jboss.injection.InjectionContainer#getClassloader()
166: */
167: public ClassLoader getClassloader() {
168: //throw new RuntimeException("NYI");
169: return Thread.currentThread().getContextClassLoader();
170: }
171:
172: /* (non-Javadoc)
173: * @see org.jboss.injection.InjectionContainer#getDependencyPolicy()
174: */
175: public DependencyPolicy getDependencyPolicy() {
176: throw new RuntimeException("NYI");
177: }
178:
179: /* (non-Javadoc)
180: * @see org.jboss.injection.InjectionContainer#getDeploymentDescriptorType()
181: */
182: public String getDeploymentDescriptorType() {
183: return "application-client.xml";
184: }
185:
186: /* (non-Javadoc)
187: * @see org.jboss.injection.InjectionContainer#getEjbJndiName(java.lang.Class)
188: */
189: public String getEjbJndiName(Class businessInterface)
190: throws NameNotFoundException {
191: throw new RuntimeException("NYI");
192: //return null;
193: }
194:
195: /* (non-Javadoc)
196: * @see org.jboss.injection.InjectionContainer#getEjbJndiName(java.lang.String, java.lang.Class)
197: */
198: public String getEjbJndiName(String link, Class businessInterface) {
199: throw new NotImplementedException();
200: //return "java:comp/env/" + link + "/remote";
201: //return applicationClientName + "/" + link + "/remote";
202: //return null;
203: }
204:
205: /* (non-Javadoc)
206: * @see org.jboss.injection.InjectionContainer#getEnc()
207: */
208: public Context getEnc() {
209: return enc;
210: }
211:
212: /* (non-Javadoc)
213: * @see org.jboss.injection.InjectionContainer#getEncInjections()
214: */
215: public Map<String, Map<AccessibleObject, Injector>> getEncInjections() {
216: return encInjections;
217: }
218:
219: /* (non-Javadoc)
220: * @see org.jboss.injection.InjectionContainer#getEncInjectors()
221: */
222: public Map<String, EncInjector> getEncInjectors() {
223: return encInjectors;
224: }
225:
226: /* (non-Javadoc)
227: * @see org.jboss.injection.InjectionContainer#getEnvironmentRefGroup()
228: */
229: public EnvironmentRefGroup getEnvironmentRefGroup() {
230: return xml;
231: }
232:
233: /* (non-Javadoc)
234: * @see org.jboss.injection.InjectionContainer#getIdentifier()
235: */
236: public String getIdentifier() {
237: // throw new NotImplementedException;
238: // FIXME: return the real identifier
239: //return "client-identifier";
240: return applicationClientName;
241: }
242:
243: /* (non-Javadoc)
244: * @see org.jboss.injection.InjectionContainer#getInjectors()
245: */
246: public List<Injector> getInjectors() {
247: throw new NotImplementedException();
248: }
249:
250: public Class<?> getMainClass() {
251: return mainClass;
252: }
253:
254: /* (non-Javadoc)
255: * @see org.jboss.injection.InjectionContainer#getPersistenceUnitDeployment(java.lang.String)
256: */
257: public PersistenceUnitDeployment getPersistenceUnitDeployment(
258: String unitName) throws NameNotFoundException {
259: throw new NotImplementedException();
260: }
261:
262: public void invokeMain(String args[]) throws SecurityException,
263: NoSuchMethodException, IllegalArgumentException,
264: IllegalAccessException, InvocationTargetException {
265: Class parameterTypes[] = { args.getClass() };
266: Method method = mainClass.getDeclaredMethod("main",
267: parameterTypes);
268: method.invoke(null, (Object) args);
269: }
270:
271: /**
272: * Call post construct methods.
273: * @throws IllegalAccessException
274: * @throws InstantiationException
275: * @throws InvocationTargetException
276: * @throws IllegalArgumentException
277: *
278: */
279: private void postConstruct() throws InstantiationException,
280: IllegalAccessException, IllegalArgumentException,
281: InvocationTargetException {
282: log.info("postConstructs = " + postConstructs);
283: for (Method method : postConstructs) {
284: method.setAccessible(true);
285: Object instance;
286: if (Modifier.isStatic(method.getModifiers()))
287: instance = null;
288: else
289: instance = method.getDeclaringClass().newInstance();
290: Object args[] = null;
291: method.invoke(instance, args);
292: }
293: }
294:
295: private void processMetadata(DependencyPolicy dependencyPolicy)
296: throws Exception {
297: processPostConstructs();
298:
299: // TODO: check which handlers a client container should support
300: Collection<InjectionHandler> handlers = new ArrayList<InjectionHandler>();
301: handlers.add(new EJBHandler());
302: //handlers.add(new ClientEJBHandler());
303: handlers.add(new DependsHandler());
304: handlers.add(new JndiInjectHandler());
305: handlers.add(new PersistenceContextHandler());
306: handlers.add(new PersistenceUnitHandler());
307: handlers.add(new ResourceHandler());
308: handlers.add(new WebServiceRefHandler());
309:
310: // TODO: we're going to use a jar class loader
311: // ClassLoader old = Thread.currentThread().getContextClassLoader();
312: // Thread.currentThread().setContextClassLoader(classloader);
313: try {
314: // EJB container's XML must be processed before interceptor's as it may override interceptor's references
315: for (InjectionHandler handler : handlers)
316: handler.loadXml(xml, this );
317:
318: Map<AccessibleObject, Injector> tmp = InjectionUtil
319: .processAnnotations(this , handlers, getMainClass());
320: injectors.addAll(tmp.values());
321:
322: // initialiseInterceptors();
323: // for (InterceptorInfo interceptorInfo : applicableInterceptors)
324: // {
325: // for (InjectionHandler handler : handlers)
326: // {
327: // handler.loadXml(interceptorInfo.getXml(), this);
328: // }
329: // }
330: // for (InterceptorInfo interceptorInfo : applicableInterceptors)
331: // {
332: // Map<AccessibleObject, Injector> tmpInterceptor = InjectionUtil.processAnnotations(this, handlers, interceptorInfo.getClazz());
333: // InterceptorInjector injector = new InterceptorInjector(this, interceptorInfo, tmpInterceptor);
334: // interceptorInjectors.put(interceptorInfo.getClazz(), injector);
335: // }
336: } finally {
337: // Thread.currentThread().setContextClassLoader(old);
338: }
339: }
340:
341: /**
342: * Create dummy dd for PostConstruct annotations.
343: * @throws ClassNotFoundException
344: * @throws NoSuchMethodException
345: * @throws SecurityException
346: *
347: */
348: private void processPostConstructs() throws ClassNotFoundException,
349: SecurityException, NoSuchMethodException {
350: processPostConstructs(mainClass);
351:
352: for (LifecycleCallback callback : xml.getPostConstructs()) {
353: String className = callback.getLifecycleCallbackClass();
354: String methodName = callback.getLifecycleCallbackMethod();
355: Class lifecycleClass;
356: if (className == null)
357: lifecycleClass = mainClass;
358: else
359: lifecycleClass = Thread.currentThread()
360: .getContextClassLoader().loadClass(className);
361: Class parameterTypes[] = new Class[0];
362: Method method = lifecycleClass.getDeclaredMethod(
363: methodName, parameterTypes);
364: postConstructs.add(method);
365: }
366: }
367:
368: private void processPostConstructs(Class<?> cls) {
369: if (cls == null)
370: return;
371:
372: for (Method method : cls.getDeclaredMethods()) {
373: PostConstruct postConstruct = method
374: .getAnnotation(PostConstruct.class);
375: if (postConstruct != null) {
376: // TODO: sure?
377: // http://java.sun.com/javase/6/docs/api/javax/annotation/PostConstruct.html
378: if (postConstructs.size() > 0)
379: throw new IllegalStateException(
380: "only one @PostConstruct allowed");
381: postConstructs.add(method);
382: }
383: }
384:
385: processPostConstructs(cls.getSuperclass());
386: }
387:
388: /* (non-Javadoc)
389: * @see org.jboss.injection.InjectionContainer#resolveEjbContainer(java.lang.String, java.lang.Class)
390: */
391: public Container resolveEjbContainer(String link, Class businessIntf) {
392: log.warn("resolveEjbContainer(" + link + ", " + businessIntf
393: + ") not implemented");
394: return null;
395: }
396:
397: /* (non-Javadoc)
398: * @see org.jboss.injection.InjectionContainer#resolveEjbContainer(java.lang.Class)
399: */
400: public Container resolveEjbContainer(Class businessIntf)
401: throws NameNotFoundException {
402: return null;
403: }
404:
405: // public VirtualFile getRootFile()
406: // {
407: // throw new NotImplementedException();
408: // }
409: }
|