001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a 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.ejb.plugins;
023:
024: import org.jboss.ejb.Container;
025: import org.jboss.ejb.EntityCache;
026: import org.jboss.ejb.EntityContainer;
027: import org.jboss.ejb.EntityEnterpriseContext;
028: import org.jboss.ejb.EntityPersistenceManager;
029: import org.jboss.ejb.AllowedOperationsAssociation;
030: import org.jboss.ejb.GenericEntityObjectFactory;
031: import org.jboss.logging.Logger;
032:
033: import javax.ejb.CreateException;
034: import javax.ejb.EJBException;
035: import javax.ejb.EntityBean;
036: import javax.ejb.FinderException;
037: import javax.ejb.RemoveException;
038: import java.lang.reflect.InvocationTargetException;
039: import java.lang.reflect.Method;
040: import java.rmi.RemoteException;
041: import java.util.ArrayList;
042: import java.util.Collection;
043: import java.util.Enumeration;
044: import java.util.HashMap;
045: import java.util.Iterator;
046:
047: /**
048: * Persistence manager for BMP entites. All calls are simply deligated
049: * to the entity implementation class.
050: *
051: * @author <a href="mailto:rickard.oberg@telkel.com">Rickard Öberg</a>
052: * @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
053: * @author <a href="mailto:andreas.schaefer@madplanet.com">Andreas Schaefer</a>
054: * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
055: * @version $Revision: 57209 $
056: */
057: public class BMPPersistenceManager implements EntityPersistenceManager {
058: // Constants -----------------------------------------------------
059: private final static Object[] EMPTY_OBJECT_ARRAY = new Object[0];
060: // Attributes ----------------------------------------------------
061: Logger log = Logger.getLogger(BMPPersistenceManager.class);
062:
063: EntityContainer con;
064:
065: Method ejbLoad;
066: Method ejbStore;
067: Method ejbActivate;
068: Method ejbPassivate;
069: Method ejbRemove;
070:
071: /**
072: * Optional isModified method used by storeEntity
073: */
074: Method isModified;
075:
076: HashMap createMethods = new HashMap();
077: HashMap postCreateMethods = new HashMap();
078: HashMap finderMethods = new HashMap();
079:
080: // Static --------------------------------------------------------
081:
082: // Constructors --------------------------------------------------
083:
084: // Public --------------------------------------------------------
085: public void setContainer(Container c) {
086: con = (EntityContainer) c;
087: }
088:
089: public void create() throws Exception {
090: ejbLoad = EntityBean.class.getMethod("ejbLoad", new Class[0]);
091: ejbStore = EntityBean.class.getMethod("ejbStore", new Class[0]);
092: ejbActivate = EntityBean.class.getMethod("ejbActivate",
093: new Class[0]);
094: ejbPassivate = EntityBean.class.getMethod("ejbPassivate",
095: new Class[0]);
096: ejbRemove = EntityBean.class.getMethod("ejbRemove",
097: new Class[0]);
098:
099: // Create cache of create methods
100: if (con.getHomeClass() != null) {
101: Method[] methods = con.getHomeClass().getMethods();
102: createMethodCache(methods);
103: }
104: if (con.getLocalHomeClass() != null) {
105: Method[] methods = con.getLocalHomeClass().getMethods();
106: createMethodCache(methods);
107: }
108:
109: try {
110: isModified = con.getBeanClass().getMethod("isModified",
111: new Class[0]);
112: if (!isModified.getReturnType().equals(Boolean.TYPE))
113: isModified = null; // Has to have "boolean" as return type!
114: } catch (NoSuchMethodException ignored) {
115: }
116: }
117:
118: /**
119: * Returns a new instance of the bean class or a subclass of the bean class.
120: *
121: * @return the new instance
122: */
123: public Object createBeanClassInstance() throws Exception {
124: return con.getBeanClass().newInstance();
125: }
126:
127: private void createMethodCache(Method[] methods)
128: throws NoSuchMethodException {
129: for (int i = 0; i < methods.length; i++) {
130: String name = methods[i].getName();
131: if (name.startsWith("create")) {
132: String nameSuffix = name.substring(0, 1).toUpperCase()
133: + name.substring(1);
134: try {
135: createMethods.put(methods[i], con.getBeanClass()
136: .getMethod("ejb" + nameSuffix,
137: methods[i].getParameterTypes()));
138: } catch (NoSuchMethodException e) {
139: log.error("Home Method " + methods[i]
140: + " not implemented in bean class "
141: + con.getBeanClass()
142: + " looking for method named: ejb"
143: + nameSuffix);
144:
145: throw e;
146: }
147: try {
148: postCreateMethods.put(methods[i], con
149: .getBeanClass().getMethod(
150: "ejbPost" + nameSuffix,
151: methods[i].getParameterTypes()));
152: } catch (NoSuchMethodException e) {
153: log.error("Home Method " + methods[i]
154: + " not implemented in bean class "
155: + con.getBeanClass()
156: + " looking for method named: ejbPost"
157: + nameSuffix);
158: throw e;
159: }
160: }
161: }
162:
163: // Create cache of finder methods
164: for (int i = 0; i < methods.length; i++) {
165: if (methods[i].getName().startsWith("find")) {
166: try {
167: finderMethods.put(methods[i], con.getBeanClass()
168: .getMethod(
169: "ejbF"
170: + methods[i].getName()
171: .substring(1),
172: methods[i].getParameterTypes()));
173: } catch (NoSuchMethodException e) {
174: log.error("Home Method " + methods[i]
175: + " not implemented in bean class");
176: throw e;
177: }
178: }
179: }
180: }
181:
182: public void start() {
183: }
184:
185: public void stop() {
186: }
187:
188: public void destroy() {
189: }
190:
191: public void createEntity(Method m, Object[] args,
192: EntityEnterpriseContext ctx) throws Exception {
193:
194: Object id = null;
195: try {
196: // Call ejbCreate<METHOD)
197: AllowedOperationsAssociation
198: .pushInMethodFlag(IN_EJB_CREATE);
199: Method createMethod = (Method) createMethods.get(m);
200: id = createMethod.invoke(ctx.getInstance(), args);
201: } catch (IllegalAccessException e) {
202: // Throw this as a bean exception...(?)
203: throw new EJBException(e);
204: } catch (InvocationTargetException ite) {
205: Throwable e = ite.getTargetException();
206: if (e instanceof CreateException) {
207: // Rethrow exception
208: throw (CreateException) e;
209: } else if (e instanceof RemoteException) {
210: // Rethrow exception
211: throw (RemoteException) e;
212: } else if (e instanceof EJBException) {
213: // Rethrow exception
214: throw (EJBException) e;
215: } else if (e instanceof RuntimeException) {
216: // Wrap runtime exceptions
217: throw new EJBException((Exception) e);
218: } else if (e instanceof Exception) {
219: throw (Exception) e;
220: } else {
221: throw (Error) e;
222: }
223: } finally {
224: AllowedOperationsAssociation.popInMethodFlag();
225: }
226:
227: // set the id
228: ctx.setId(id);
229:
230: // Create a new CacheKey
231: Object cacheKey = ((EntityCache) con.getInstanceCache())
232: .createCacheKey(id);
233:
234: // Give it to the context
235: ctx.setCacheKey(cacheKey);
236: }
237:
238: public void postCreateEntity(Method m, Object[] args,
239: EntityEnterpriseContext ctx) throws Exception {
240: try {
241: AllowedOperationsAssociation
242: .pushInMethodFlag(IN_EJB_POST_CREATE);
243: Method postCreateMethod = (Method) postCreateMethods.get(m);
244: postCreateMethod.invoke(ctx.getInstance(), args);
245: } catch (IllegalAccessException e) {
246: // Throw this as a bean exception...(?)
247: throw new EJBException(e);
248: } catch (InvocationTargetException ite) {
249: Throwable e = ite.getTargetException();
250: if (e instanceof CreateException) {
251: // Rethrow exception
252: throw (CreateException) e;
253: } else if (e instanceof RemoteException) {
254: // Rethrow exception
255: throw (RemoteException) e;
256: } else if (e instanceof EJBException) {
257: // Rethrow exception
258: throw (EJBException) e;
259: } else if (e instanceof RuntimeException) {
260: // Wrap runtime exceptions
261: throw new EJBException((Exception) e);
262: } else if (e instanceof Exception) {
263: throw (Exception) e;
264: } else {
265: throw (Error) e;
266: }
267: } finally {
268: AllowedOperationsAssociation.popInMethodFlag();
269: }
270: }
271:
272: public Object findEntity(Method finderMethod, Object[] args,
273: EntityEnterpriseContext ctx,
274: GenericEntityObjectFactory factory) throws Exception {
275: try {
276: AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_FIND);
277:
278: // call the finder method
279: Object objectId = callFinderMethod(finderMethod, args, ctx);
280:
281: final Object cacheKey = ((EntityCache) con
282: .getInstanceCache()).createCacheKey(objectId);
283: return factory.getEntityEJBObject(cacheKey);
284: } finally {
285: AllowedOperationsAssociation.popInMethodFlag();
286: }
287: }
288:
289: public Collection findEntities(Method finderMethod, Object[] args,
290: EntityEnterpriseContext ctx,
291: GenericEntityObjectFactory factory) throws Exception {
292: // call the finder method
293: Object result;
294: try {
295: AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_FIND);
296: result = callFinderMethod(finderMethod, args, ctx);
297: } finally {
298: AllowedOperationsAssociation.popInMethodFlag();
299: }
300:
301: if (result == null) {
302: // for EJB 1.0 compliance
303: // if the bean couldn't find any matching entities
304: // it returns null, so we return an empty collection
305: return new ArrayList();
306: }
307:
308: if (result instanceof java.util.Enumeration) {
309: // to preserve 1.0 spec compatiblity
310: ArrayList array = new ArrayList();
311: Enumeration e = (Enumeration) result;
312: while (e.hasMoreElements() == true) {
313: // Wrap a cache key around the given object id/primary key
314: final Object cacheKey = ((EntityCache) con
315: .getInstanceCache()).createCacheKey(e
316: .nextElement());
317: Object o = factory.getEntityEJBObject(cacheKey);
318: array.add(o);
319: }
320: return array;
321: } else if (result instanceof java.util.Collection) {
322:
323: ArrayList array = new ArrayList(((Collection) result)
324: .size());
325: Iterator i = ((Collection) result).iterator();
326: while (i.hasNext()) {
327: // Wrap a cache key around the given object id/primary key
328: final Object cacheKey = ((EntityCache) con
329: .getInstanceCache()).createCacheKey(i.next());
330: Object o = factory.getEntityEJBObject(cacheKey);
331: array.add(o);
332: }
333: return array;
334: } else {
335: // so we received something that's not valid
336: // throw an exception reporting it
337: throw new EJBException(
338: "result of finder method is not a valid "
339: + "return type: " + result.getClass());
340: }
341: }
342:
343: public void activateEntity(EntityEnterpriseContext ctx)
344: throws RemoteException {
345: // Create a new CacheKey
346: Object id = ctx.getId();
347: Object cacheKey = ((EntityCache) con.getInstanceCache())
348: .createCacheKey(id);
349:
350: // Give it to the context
351: ctx.setCacheKey(cacheKey);
352:
353: try {
354: AllowedOperationsAssociation
355: .pushInMethodFlag(IN_EJB_ACTIVATE);
356: ejbActivate.invoke(ctx.getInstance(), EMPTY_OBJECT_ARRAY);
357: } catch (IllegalAccessException e) {
358: // Throw this as a bean exception...(?)
359: throw new EJBException(e);
360: } catch (InvocationTargetException ite) {
361: Throwable e = ite.getTargetException();
362: if (e instanceof RemoteException) {
363: // Rethrow exception
364: throw (RemoteException) e;
365: } else if (e instanceof EJBException) {
366: // Rethrow exception
367: throw (EJBException) e;
368: } else if (e instanceof RuntimeException) {
369: // Wrap runtime exceptions
370: throw new EJBException((Exception) e);
371: }
372: } finally {
373: AllowedOperationsAssociation.popInMethodFlag();
374: }
375: }
376:
377: public void loadEntity(EntityEnterpriseContext ctx)
378: throws RemoteException {
379: try {
380: AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_LOAD);
381: ejbLoad.invoke(ctx.getInstance(), EMPTY_OBJECT_ARRAY);
382: } catch (IllegalAccessException e) {
383: // Throw this as a bean exception...(?)
384: throw new EJBException(e);
385: } catch (InvocationTargetException ite) {
386: Throwable e = ite.getTargetException();
387: if (e instanceof RemoteException) {
388: // Rethrow exception
389: throw (RemoteException) e;
390: } else if (e instanceof EJBException) {
391: // Rethrow exception
392: throw (EJBException) e;
393: } else if (e instanceof RuntimeException) {
394: // Wrap runtime exceptions
395: throw new EJBException((Exception) e);
396: }
397: } finally {
398: AllowedOperationsAssociation.popInMethodFlag();
399: }
400: }
401:
402: public boolean isStoreRequired(EntityEnterpriseContext ctx)
403: throws Exception {
404: if (isModified == null) {
405: return true;
406: }
407:
408: Boolean modified = (Boolean) isModified.invoke(ctx
409: .getInstance(), EMPTY_OBJECT_ARRAY);
410: return modified.booleanValue();
411: }
412:
413: public boolean isModified(EntityEnterpriseContext ctx)
414: throws Exception {
415: return isStoreRequired(ctx);
416: }
417:
418: public void invokeEjbStore(EntityEnterpriseContext ctx)
419: throws RemoteException {
420: try {
421: if (!isStoreRequired(ctx)) {
422: return;
423: }
424: } catch (Exception e) {
425: throw new EJBException("Failed to invoke isModified().", e);
426: }
427:
428: try {
429: AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_STORE);
430: ejbStore.invoke(ctx.getInstance(), EMPTY_OBJECT_ARRAY);
431: } catch (IllegalAccessException e) {
432: // Throw this as a bean exception...(?)
433: throw new EJBException(e);
434: } catch (InvocationTargetException ite) {
435: Throwable e = ite.getTargetException();
436: if (e instanceof RemoteException) {
437: // Rethrow exception
438: throw (RemoteException) e;
439: } else if (e instanceof EJBException) {
440: // Rethrow exception
441: throw (EJBException) e;
442: } else if (e instanceof RuntimeException) {
443: // Wrap runtime exceptions
444: throw new EJBException((Exception) e);
445: }
446: } finally {
447: AllowedOperationsAssociation.popInMethodFlag();
448: }
449: }
450:
451: public void storeEntity(EntityEnterpriseContext ctx)
452: throws RemoteException {
453: }
454:
455: public void passivateEntity(EntityEnterpriseContext ctx)
456: throws RemoteException {
457: try {
458: AllowedOperationsAssociation
459: .pushInMethodFlag(IN_EJB_PASSIVATE);
460: ejbPassivate.invoke(ctx.getInstance(), EMPTY_OBJECT_ARRAY);
461: } catch (IllegalAccessException e) {
462: // Throw this as a bean exception...(?)
463: throw new EJBException(e);
464: } catch (InvocationTargetException ite) {
465: Throwable e = ite.getTargetException();
466: if (e instanceof RemoteException) {
467: // Rethrow exception
468: throw (RemoteException) e;
469: } else if (e instanceof EJBException) {
470: // Rethrow exception
471: throw (EJBException) e;
472: } else if (e instanceof RuntimeException) {
473: // Wrap runtime exceptions
474: throw new EJBException((Exception) e);
475: }
476: } finally {
477: AllowedOperationsAssociation.popInMethodFlag();
478: }
479: ctx.setEJBObject(null);
480: ctx.setEJBLocalObject(null);
481: }
482:
483: public void removeEntity(EntityEnterpriseContext ctx)
484: throws RemoteException, RemoveException {
485: try {
486: AllowedOperationsAssociation
487: .pushInMethodFlag(IN_EJB_REMOVE);
488: ejbRemove.invoke(ctx.getInstance(), EMPTY_OBJECT_ARRAY);
489: } catch (IllegalAccessException e) {
490: // Throw this as a bean exception...(?)
491: throw new EJBException(e);
492: } catch (InvocationTargetException ite) {
493: Throwable e = ite.getTargetException();
494: if (e instanceof RemoveException) {
495: // Rethrow exception
496: throw (RemoveException) e;
497: } else if (e instanceof RemoteException) {
498: // Rethrow exception
499: throw (RemoteException) e;
500: } else if (e instanceof EJBException) {
501: // Rethrow exception
502: throw (EJBException) e;
503: } else if (e instanceof RuntimeException) {
504: // Wrap runtime exceptions
505: throw new EJBException((Exception) e);
506: }
507: } finally {
508: AllowedOperationsAssociation.popInMethodFlag();
509: }
510: }
511:
512: // Z implementation ----------------------------------------------
513:
514: // Package protected ---------------------------------------------
515:
516: // Protected -----------------------------------------------------
517:
518: // Private -------------------------------------------------------
519: private Object callFinderMethod(Method finderMethod, Object[] args,
520: EntityEnterpriseContext ctx) throws Exception {
521: // get the finder method
522: Method callMethod = (Method) finderMethods.get(finderMethod);
523:
524: if (callMethod == null) {
525: throw new EJBException(
526: "couldn't find finder method in bean class. "
527: + finderMethod.toString());
528: }
529:
530: // invoke the finder method
531: Object result = null;
532: try {
533: result = callMethod.invoke(ctx.getInstance(), args);
534: } catch (IllegalAccessException e) {
535: // Throw this as a bean exception...(?)
536: throw new EJBException(e);
537: } catch (InvocationTargetException ite) {
538: Throwable e = ite.getTargetException();
539: if (e instanceof FinderException) {
540: // Rethrow exception
541: throw (FinderException) e;
542: } else if (e instanceof RemoteException) {
543: // Rethrow exception
544: throw (RemoteException) e;
545: } else if (e instanceof EJBException) {
546: // Rethrow exception
547: throw (EJBException) e;
548: } else if (e instanceof RuntimeException) {
549: // Wrap runtime exceptions
550: throw new EJBException((Exception) e);
551: } else if (e instanceof Exception) {
552: throw (Exception) e;
553: } else {
554: throw (Error) e;
555: }
556: }
557:
558: return result;
559: }
560:
561: // Inner classes -------------------------------------------------
562: }
|