001: package org.mockejb;
002:
003: import java.io.Serializable;
004: import java.util.ArrayList;
005: import java.util.Collection;
006: import java.util.Iterator;
007:
008: import javax.ejb.*;
009:
010: import org.apache.commons.logging.*;
011:
012: import org.mockejb.interceptor.*;
013:
014: /**
015: * Intercepts the calls to the BMP find methods,
016: * checks if the returned PK (or elements of the pk collection) is in the EntityDatabase,
017: * if not, creates a new entity and calls "ejbLoad", and adds it to the EntityDatabase.
018: * Returns the entity or entity collection to the client
019: *
020: * @author Alexander Ananiev
021: */
022: public class BMPFinderHandler implements Aspect, Serializable {
023:
024: // logger for this class
025: private static Log logger = LogFactory
026: .getLog(BMPFinderHandler.class.getName());
027:
028: protected EntityDatabase entityDatabase;
029:
030: public BMPFinderHandler(final EntityDatabase entityDatabase) {
031: this .entityDatabase = entityDatabase;
032: }
033:
034: public Pointcut getPointcut() {
035: // we're only interested in EntityBeans and ejbFind... methods
036: return PointcutPair.and(new MethodPatternPointcut("ejbFind"),
037: new ClassPointcut(EntityBean.class, true));
038: }
039:
040: /**
041: * Intercepts and handles finders.
042: */
043: public void intercept(InvocationContext invocationContext)
044: throws Exception {
045:
046: // we wnat to proceed in any case
047: invocationContext.proceed();
048:
049: // get the descriptor
050: BasicEjbDescriptor ejbDescriptor = (BasicEjbDescriptor) invocationContext
051: .getPropertyValue("descriptor");
052: MockEjbContext ejbContext = (MockEjbContext) invocationContext
053: .getPropertyValue(MockEjbContext.class.getName());
054:
055: // handle only CMP entity beans
056: if (ejbDescriptor instanceof EntityBeanDescriptor
057: && !((EntityBeanDescriptor) ejbDescriptor).isCMP()) {
058:
059: EntityBeanDescriptor descriptor = (EntityBeanDescriptor) ejbDescriptor;
060:
061: // call finder
062: invocationContext.proceed();
063:
064: logger.debug("Intercepted "
065: + invocationContext.getProxyMethod());
066:
067: Object pkOrPkCollection = invocationContext
068: .getReturnObject();
069:
070: // if it's a simple PK
071: if (!(pkOrPkCollection instanceof Collection)
072: && !(pkOrPkCollection instanceof EJBObject)
073: && !(pkOrPkCollection instanceof EJBLocalObject)) {
074:
075: Object entity = findInCacheOrCreate(descriptor,
076: ejbContext, pkOrPkCollection);
077: invocationContext.setReturnObject(entity);
078:
079: } else if (pkOrPkCollection instanceof Collection) { // this is a collection of PKs
080:
081: Collection pks = (Collection) pkOrPkCollection;
082: Iterator i = pks.iterator();
083: Collection resultingCollection = new ArrayList();
084: while (i.hasNext()) {
085: Object pk = i.next();
086: if (!(pk instanceof EJBObject)
087: && !(pk instanceof EJBLocalObject)) {
088:
089: Object entity = findInCacheOrCreate(descriptor,
090: ejbContext, pk);
091: resultingCollection.add(entity);
092: }
093: }
094: invocationContext.setReturnObject(resultingCollection);
095: } // end of if collection
096: }
097: }
098:
099: protected Object findInCacheOrCreate(
100: EntityBeanDescriptor descriptor, MockEjbContext ejbContext,
101: Object pk) throws Exception {
102:
103: // check in the cache
104: // TODO: we can use context instead
105: Object newEntity = entityDatabase.find(descriptor
106: .getHomeClass(), pk);
107:
108: if (newEntity == null) {
109: logger
110: .debug("Entity "
111: + descriptor.getIfaceClass().getName()
112: + " for PK "
113: + pk
114: + " was not found in the EntityDatabase. Will try to create the new entity and call ejbLoad");
115:
116: // not in cache -- create
117: // get our home
118: GenericHome home = (GenericHome) ejbContext
119: .getEJBLocalHome();
120: newEntity = home.genericCreate();
121: // call ejbLoad
122: EjbBeanAccess beanAccess = (EjbBeanAccess) newEntity;
123: Object bean = beanAccess.getBean();
124: if (!(bean instanceof EntityBean)) {
125: throw new EJBException(
126: "Can't call ejbLoad on the "
127: + bean.getClass().getName()
128: + " because it does not implement EntityBean interface. You can avod this error by"
129: + " adding the entity with PK " + pk
130: + " to the EntityDatabase.");
131: }
132: // set the PK on the context of this entity
133: MockEjbContext newEntityContext = beanAccess
134: .getEjbContext();
135: newEntityContext.setPrimaryKey(pk);
136: EntityBean entityBean = (EntityBean) bean;
137: entityBean.ejbLoad();
138: }
139:
140: return newEntity;
141: }
142:
143: /**
144: * This class does not have state, so all instances of this class
145: * are considered equal
146: */
147: public boolean equals(Object obj) {
148:
149: if (obj instanceof BMPFinderHandler
150: && entityDatabase
151: .equals(((BMPFinderHandler) obj).entityDatabase))
152: return true;
153: else
154: return false;
155:
156: }
157:
158: public int hashCode() {
159: return this.getClass().hashCode() + entityDatabase.hashCode();
160: }
161:
162: }
|