001: /*
002: * JFox - The most lightweight Java EE Application Server!
003: * more details please visit http://www.huihoo.org/jfox or http://www.jfox.org.cn.
004: *
005: * JFox is licenced and re-distributable under GNU LGPL.
006: */
007: package org.jfox.ejb3;
008:
009: import java.lang.reflect.Method;
010: import java.util.ArrayList;
011: import java.util.List;
012: import javax.ejb.EJBException;
013: import javax.ejb.PostActivate;
014: import javax.ejb.PrePassivate;
015: import javax.ejb.Stateful;
016:
017: import org.apache.commons.pool.KeyedPoolableObjectFactory;
018: import org.apache.commons.pool.impl.GenericKeyedObjectPool;
019: import org.jfox.ejb3.dependent.FieldEJBDependence;
020: import org.jfox.ejb3.dependent.FieldResourceDependence;
021: import org.jfox.entity.dependent.FieldPersistenceContextDependence;
022: import org.jfox.entity.dependent.FieldPersistenceUnitDependence;
023: import org.jfox.framework.component.Module;
024: import org.jfox.util.AnnotationUtils;
025: import org.jfox.util.ClassUtils;
026: import org.jfox.util.MethodUtils;
027:
028: /**
029: * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
030: */
031: public class StatefulBucket extends SessionBucket implements
032: KeyedPoolableObjectFactory {
033:
034: /**
035: * ä¿?å˜çš„是StatefulEJBContext, key 为 EJBObjectId
036: */
037: private GenericKeyedObjectPool pool = new GenericKeyedObjectPool(
038: this );
039:
040: protected List<Method> postActivateMethods = new ArrayList<Method>();
041: protected List<Method> prePassivateMethods = new ArrayList<Method>();
042:
043: private volatile static long id = 0;
044:
045: protected StatefulBucket(EJBContainer container,
046: Class<?> beanClass, Module module) {
047: super (container, beanClass, module);
048: // Stateless/Stateful ��的Annotation
049: introspectStateful();
050:
051: injectClassDependents();
052: }
053:
054: protected void introspectStateful() {
055: Stateful stateful = getBeanClass()
056: .getAnnotation(Stateful.class);
057: String name = stateful.name();
058: if (name.equals("")) {
059: name = getBeanClass().getSimpleName();
060: }
061: setEJBName(name);
062:
063: String mappedName = stateful.mappedName();
064: if (mappedName.equals("")) {
065: if (isRemote()) {
066: addMappedName(name + "/remote");
067: }
068: if (isLocal()) {
069: addMappedName(name + "/local");
070: }
071: } else {
072: addMappedName(mappedName);
073: }
074:
075: setDescription(stateful.description());
076:
077: // beanClass is in superClass array
078: Class<?>[] super Classes = ClassUtils
079: .getAllSuperclasses(getBeanClass());
080:
081: List<Long> postActivateMethodHashes = new ArrayList<Long>();
082: List<Long> prePassivateMethodHashes = new ArrayList<Long>();
083: for (Class<?> super Class : super Classes) {
084:
085: // PostConstruct
086: for (Method postActivateMethod : introspectPostActivateMethod(super Class)) {
087: long methodHash = MethodUtils
088: .getMethodHash(postActivateMethod);
089: if (!postActivateMethodHashes.contains(methodHash)) {
090: postActivateMethods.add(0, postActivateMethod);
091: postActivateMethodHashes.add(methodHash);
092: }
093: }
094:
095: // PreDestroy
096: for (Method prePassivateMethod : introspectPrePassivateMethod(super Class)) {
097: long methodHash = MethodUtils
098: .getMethodHash(prePassivateMethod);
099: if (!prePassivateMethodHashes.contains(methodHash)) {
100: prePassivateMethods.add(0, prePassivateMethod);
101: prePassivateMethodHashes.add(methodHash);
102: }
103: }
104: }
105: }
106:
107: protected List<Method> introspectPostActivateMethod(Class super Class) {
108: List<Method> postConstructMethods = new ArrayList<Method>();
109: // PostActivate
110: Method[] _postConstructMethods = AnnotationUtils
111: .getAnnotatedDeclaredMethods(super Class,
112: PostActivate.class);
113: for (Method postConstructMethod : _postConstructMethods) {
114: postConstructMethod.setAccessible(true);
115: postConstructMethods.add(0, postConstructMethod);
116: }
117: return postConstructMethods;
118: }
119:
120: protected List<Method> introspectPrePassivateMethod(Class super Class) {
121: List<Method> postConstructMethods = new ArrayList<Method>();
122: // PrePassivate
123: Method[] _postConstructMethods = AnnotationUtils
124: .getAnnotatedDeclaredMethods(super Class,
125: PrePassivate.class);
126: for (Method postConstructMethod : _postConstructMethods) {
127: postConstructMethod.setAccessible(true);
128: postConstructMethods.add(0, postConstructMethod);
129: }
130: return postConstructMethods;
131: }
132:
133: public boolean isStateful() {
134: return true;
135: }
136:
137: public boolean isWebService() {
138: return false;
139: }
140:
141: public EJBObjectId createEJBObjectId() {
142: return new EJBObjectId(getEJBName(), "" + id++);
143: }
144:
145: public ExtendEJBContext createEJBContext(EJBObjectId ejbObjectId,
146: Object instance) {
147: return new StatefulEJBContextImpl(ejbObjectId, instance);
148: }
149:
150: public ExtendEJBContext getEJBContext(EJBObjectId ejbObjectId) {
151: try {
152: StatefulEJBContextImpl ejbContext = (StatefulEJBContextImpl) pool
153: .borrowObject(ejbObjectId);
154: return ejbContext;
155: } catch (Exception e) {
156: throw new EJBException(
157: "Create EJBContext failed, EJBObjectId="
158: + ejbObjectId, e);
159: }
160: }
161:
162: public void reuseEJBContext(ExtendEJBContext ejbContext) {
163: try {
164: pool.returnObject(ejbContext.getEJBObjectId(), ejbContext);
165: } catch (Exception e) {
166: throw new EJBException("Return EJBContext to pool failed!",
167: e);
168: }
169: }
170:
171: //---- KeyedPoolableObjectFactory --------
172: public void activateObject(Object key, Object obj) throws Exception {
173: }
174:
175: public void passivateObject(Object key, Object obj)
176: throws Exception {
177: }
178:
179: public boolean validateObject(Object key, Object obj) {
180: return true;
181: }
182:
183: public void destroyObject(Object key, Object obj) throws Exception {
184: //TODO: do @PrePassivate when pool destory EJBContext
185: for (Method preDestroyMethod : getPreDestroyMethods()) {
186: logger.debug("PreDestory method for ejb: " + getEJBName()
187: + ", method: " + preDestroyMethod);
188: preDestroyMethod.invoke(((ExtendEJBContext) obj)
189: .getEJBInstance());
190: }
191: }
192:
193: public Object makeObject(Object key) throws Exception {
194: Object obj = getBeanClass().newInstance();
195: ExtendEJBContext ejbContext = createEJBContext(
196: (EJBObjectId) key, obj);
197: // post construct
198: for (Method postConstructMethod : getPostConstructMethods()) {
199: logger
200: .debug("PostConstruct method for ejb: "
201: + getEJBName() + ", method: "
202: + postConstructMethod);
203: postConstructMethod.invoke(ejbContext.getEJBInstance());
204: }
205:
206: // 注入 @EJB
207: for (FieldEJBDependence fieldEJBDependence : fieldEJBdependents) {
208: fieldEJBDependence.inject(ejbContext);
209: }
210:
211: // 注入 @Resource
212: for (FieldResourceDependence fieldResourceDependence : fieldResourcedependents) {
213: fieldResourceDependence.inject(ejbContext);
214: }
215:
216: // 注入 @PersistenceContext
217: for (FieldPersistenceContextDependence fieldPersistenceContextDependence : fieldPersistenceContextDependences) {
218: fieldPersistenceContextDependence.inject(ejbContext);
219: }
220:
221: // 注入 @PersistenceUnit
222: for (FieldPersistenceUnitDependence persistenceUnitDependence : fieldPersistenceUnitDependences) {
223: persistenceUnitDependence.inject(ejbContext);
224: }
225:
226: //返回 EJBContext
227: return ejbContext;
228: }
229:
230: /**
231: * destroy bucket, invoke when container unload ejb
232: */
233: public void stop() {
234: logger.debug("Destroy EJB: " + getEJBName() + ", Module: "
235: + getModule().getName());
236: try {
237: pool.clear();
238: pool.close();
239: } catch (Exception e) {
240: e.printStackTrace();
241: }
242: }
243:
244: class StatefulEJBContextImpl extends EJBContextImpl {
245:
246: public StatefulEJBContextImpl(EJBObjectId ejbObjectId,
247: Object ejbInstance) {
248: super (ejbObjectId, ejbInstance);
249: }
250:
251: }
252:
253: public static void main(String[] args) {
254:
255: }
256: }
|