001: /**
002: * EasyBeans
003: * Copyright (C) 2006-2007 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library 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 GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: AbsFactory.java 1970 2007-10-16 11:49:25Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.container;
025:
026: import java.lang.reflect.Method;
027: import java.util.List;
028: import java.util.Map;
029:
030: import javax.ejb.TimerService;
031: import javax.naming.Context;
032: import javax.naming.NamingException;
033:
034: import org.ow2.easybeans.api.EZBContainer;
035: import org.ow2.easybeans.api.Factory;
036: import org.ow2.easybeans.api.FactoryException;
037: import org.ow2.easybeans.api.bean.EasyBeansBean;
038: import org.ow2.easybeans.api.components.EZBComponentRegistry;
039: import org.ow2.easybeans.api.injection.EasyBeansInjectionException;
040: import org.ow2.easybeans.api.injection.ResourceInjector;
041: import org.ow2.easybeans.api.pool.Pool;
042: import org.ow2.easybeans.api.pool.PoolException;
043: import org.ow2.easybeans.component.itf.TimerComponent;
044: import org.ow2.easybeans.naming.NamingManager;
045: import org.ow2.easybeans.naming.interceptors.ENCManager;
046: import org.ow2.easybeans.rpc.api.EJBRequest;
047: import org.ow2.easybeans.rpc.api.EJBResponse;
048: import org.ow2.easybeans.rpc.util.Hash;
049: import org.ow2.util.log.Log;
050: import org.ow2.util.log.LogFactory;
051:
052: /**
053: * Abstract factory which implements common and defaults methods.<br>
054: * It should be extended by Bean factories.
055: * @param <PoolType> the type of bean instance.
056: * @author Florent Benoit
057: */
058: public abstract class AbsFactory<PoolType extends EasyBeansBean>
059: implements Factory<PoolType, Long> {
060:
061: /**
062: * Logger.
063: */
064: private static Log logger = LogFactory.getLog(AbsFactory.class);
065:
066: /**
067: * Name of the class of the managed bean.
068: */
069: private String className = null;
070:
071: /**
072: * Container that created this factory.
073: */
074: private EZBContainer container = null;
075:
076: /**
077: * Pool that manage beans instance.
078: */
079: private Pool<PoolType, Long> pool = null;
080:
081: /**
082: * Class used to build bean's instance.
083: */
084: private Class<PoolType> beanClass = null;
085:
086: /**
087: * Context for java: lookups.
088: */
089: private Context javaContext = null;
090:
091: /**
092: * Reference on the naming manager.
093: */
094: private static NamingManager namingManager = null;
095:
096: /**
097: * List of external Resources injectors.
098: */
099: private List<ResourceInjector> injectors = null;
100:
101: /**
102: * Keep a direct reference to the method so that we don't need to compute
103: * each time the method object to invoke.<br>
104: * http://java.sun.com/j2se/1.5.0/docs/guide/rmi/spec/rmi-stubs24.html
105: */
106: private Map<Long, Method> hashes = null;
107:
108: /**
109: * Id of this container.
110: */
111: private String id = null;
112:
113: /**
114: * Timer Service for this factory.
115: */
116: private TimerService timerService = null;
117:
118: /**
119: * Builds a new factory with a given name and its container.
120: * @param className name of this factory (name of class that is managed)
121: * @param container the root component of this factory.
122: * @throws FactoryException if class can't be loaded.
123: */
124: @SuppressWarnings("unchecked")
125: public AbsFactory(final String className,
126: final EZBContainer container) throws FactoryException {
127: this .className = className;
128: this .container = container;
129: this .id = String.valueOf(System.identityHashCode(this ));
130: Class clazz = null;
131: try {
132: clazz = getContainer().getClassLoader().loadClass(
133: getClassName());
134: } catch (ClassNotFoundException e) {
135: throw new FactoryException(
136: "Cannot load the class for class name '"
137: + getClassName() + "'", e);
138: }
139: setBeanClass(clazz);
140: setHashes(Hash.hashClass(clazz));
141:
142: try {
143: namingManager = NamingManager.getInstance();
144: } catch (NamingException e) {
145: throw new FactoryException(
146: "Cannot get instance of the naming manager", e);
147: }
148:
149: this .injectors = container.getConfiguration().getInjectors();
150:
151: // Get a timer service if a timer component is present.
152: EZBComponentRegistry registry = container.getConfiguration()
153: .getEZBServer().getComponentManager()
154: .getComponentRegistry();
155: List<TimerComponent> timerComponents = registry
156: .getComponents(TimerComponent.class);
157:
158: // use the first one if there is at least once
159: if (timerComponents.size() > 0) {
160: TimerComponent timerComponent = timerComponents.get(0);
161: if (timerComponents.size() > 1) {
162: logger
163: .warn(
164: "There are {0} timer components running on this server. Only the first one will be used",
165: new Integer(timerComponents.size()));
166: }
167:
168: // Build a new timer service
169: this .timerService = timerComponent.getTimerService(this );
170: }
171:
172: }
173:
174: /**
175: * Callback called when object is gonna be removed.
176: * @param instance that is being removed from the pool.
177: */
178: public void remove(final PoolType instance) {
179: ClassLoader oldClassLoader = Thread.currentThread()
180: .getContextClassLoader();
181: Thread.currentThread().setContextClassLoader(
182: getContainer().getClassLoader());
183: try {
184: // call callbacks
185: instance.preDestroyEasyBeansLifeCycle();
186: } catch (Exception e) {
187: logger.error(
188: "Could not complete preDestroy method on instance",
189: e);
190: } finally {
191: Thread.currentThread()
192: .setContextClassLoader(oldClassLoader);
193: }
194: }
195:
196: /**
197: * Injects Resources into the Bean.
198: * @param instance The Bean instance to be injected.
199: * @throws PoolException if resources cannot be injected.
200: */
201: protected void injectResources(final PoolType instance)
202: throws PoolException {
203:
204: // call external resources injectors
205: for (ResourceInjector injector : injectors) {
206: try {
207: injector.preEasyBeansInject(instance);
208: } catch (Throwable t) {
209: // Protection from malicious code
210: logger.error("preEasyBeansInject() for {0} failed",
211: injector.getClass().getName(), t);
212: }
213: }
214:
215: // call dependency injection
216: try {
217: instance.injectedByEasyBeans();
218: } catch (EasyBeansInjectionException e) {
219: throw new PoolException(
220: "Cannot inject resources in the created bean", e);
221: }
222:
223: // call external resources injectors
224: for (ResourceInjector injector : injectors) {
225: try {
226: injector.postEasyBeansInject(instance);
227: } catch (Throwable t) {
228: // Protection from malicious code
229: logger.error("postEasyBeansInject() for {0} failed",
230: injector.getClass().getName(), t);
231: }
232: }
233: }
234:
235: /**
236: * Gets the computed hashes.
237: * @return computed hashes
238: */
239: protected Map<Long, Method> getHashes() {
240: return hashes;
241: }
242:
243: /**
244: * Sets the hashes for the current bean class.
245: * @param hashes method hashes computed as RMI hashes
246: */
247: protected void setHashes(final Map<Long, Method> hashes) {
248: this .hashes = hashes;
249: }
250:
251: /**
252: * Gets the java: context.
253: * @return java: context.
254: */
255: public Context getJavaContext() {
256: return javaContext;
257: }
258:
259: /**
260: * Sets the java: context.
261: * @param javaContext the java: context.
262: */
263: public void setJavaContext(final Context javaContext) {
264: // Can be only set once
265: if (this .javaContext != null) {
266: throw new IllegalStateException(
267: "The javaContext can only be set once. Already set !");
268: }
269: this .javaContext = javaContext;
270:
271: // Set the javaContext used for ENC
272: ENCManager.initContext(this , javaContext);
273: }
274:
275: /**
276: * Gets the bean's class.
277: * @return bean class used to instantiate beans.
278: */
279: public Class<PoolType> getBeanClass() {
280: return beanClass;
281: }
282:
283: /**
284: * Sets the bean class that will be used to build bean's instance.
285: * @param beanClass the instance of the bean class name
286: */
287: protected void setBeanClass(final Class<PoolType> beanClass) {
288: this .beanClass = beanClass;
289: }
290:
291: /**
292: * Sets the pool used by this factory.
293: * @param pool the pool which managed bean instances
294: */
295: protected void setPool(final Pool<PoolType, Long> pool) {
296: this .pool = pool;
297: }
298:
299: /**
300: * Gets the container used by this factory.
301: * @return container of this factory
302: */
303: public EZBContainer getContainer() {
304: return container;
305: }
306:
307: /**
308: * Gets the className used by this factory.
309: * @return classname that will be instantiated to build bean instance.
310: */
311: public String getClassName() {
312: return className;
313: }
314:
315: /**
316: * Gets the reference on the naming manager.
317: * @return the reference on the naming manager.
318: */
319: protected static NamingManager getNamingManager() {
320: return namingManager;
321: }
322:
323: /**
324: * Gets the pool used by this factory.
325: * @return pool.
326: */
327: public Pool<PoolType, Long> getPool() {
328: return pool;
329: }
330:
331: /**
332: * A request comes to the bean factory and needs to be handled.<br>
333: * A response is done which contains the answer.
334: * @param request the EJB request.
335: * @return a response that have been processed by the factory.
336: */
337: public abstract EJBResponse rpcInvoke(final EJBRequest request);
338:
339: /**
340: * Init the factory.
341: * @throws FactoryException if the initialization fails.
342: */
343: public void init() throws FactoryException {
344:
345: }
346:
347: /**
348: * Gets the id of this container.
349: * @return string id.
350: */
351: public String getId() {
352: return id;
353: }
354:
355: /**
356: * Stops the factory.
357: */
358: public void stop() {
359: ENCManager.removeContext(this );
360: }
361:
362: /**
363: * Gets the timer service of this factory.
364: * @return the timer service.
365: */
366: public TimerService getTimerService() {
367: return timerService;
368: }
369:
370: }
|