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.HashMap;
011: import java.util.Map;
012: import javax.ejb.ActivationConfigProperty;
013: import javax.ejb.EJBException;
014: import javax.ejb.EJBObject;
015: import javax.ejb.MessageDriven;
016: import javax.ejb.RemoveException;
017: import javax.ejb.TimerService;
018: import javax.jms.Message;
019: import javax.jms.MessageListener;
020: import javax.jms.Topic;
021:
022: import org.apache.commons.pool.PoolableObjectFactory;
023: import org.apache.commons.pool.impl.GenericObjectPool;
024: import org.jfox.ejb3.dependent.FieldEJBDependence;
025: import org.jfox.ejb3.dependent.FieldResourceDependence;
026: import org.jfox.entity.dependent.FieldPersistenceContextDependence;
027: import org.jfox.entity.dependent.FieldPersistenceUnitDependence;
028: import org.jfox.framework.component.Module;
029: import org.jfox.jms.MessageListenerUtils;
030: import org.jfox.jms.MessageService;
031: import org.jfox.jms.destination.JMSDestination;
032: import org.jfox.mvc.SessionContext;
033:
034: /**
035: * Container of MessageDriven EJB,store all Meta data, and as EJB Factory
036: *
037: * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
038: */
039: public class MDBBucket extends SessionBucket implements
040: PoolableObjectFactory, MessageListener {
041:
042: private EJBObjectId ejbObjectId;
043:
044: private MessageDrivenEJBContextImpl messageDrivenEJBContext;
045:
046: /**
047: * cache EJB proxy stub, stateless EJB have only one stub
048: */
049: private EJBObject proxyStub = null;
050:
051: /**
052: * cache EJB instances
053: */
054: private final GenericObjectPool pool = new GenericObjectPool(this );
055:
056: private JMSDestination destination;
057: private boolean isQueue = true;
058:
059: public MDBBucket(EJBContainer container, Class<?> beanClass,
060: Module module) {
061: super (container, beanClass, module);
062:
063: introspectMDB();
064: injectClassDependents();
065: }
066:
067: private void introspectMDB() {
068: MessageDriven messageDriven = getBeanClass().getAnnotation(
069: MessageDriven.class);
070: String name = messageDriven.name();
071: if (name.equals("")) {
072: name = getBeanClass().getSimpleName();
073: }
074: setEJBName(name);
075:
076: String mappedName = messageDriven.mappedName();
077: if (mappedName.equals("")) {
078: if (isRemote()) {
079: addMappedName(name + "/remote");
080: }
081: if (isLocal()) {
082: addMappedName(name + "/local");
083: }
084: } else {
085: addMappedName(mappedName);
086: }
087:
088: setDescription(messageDriven.description());
089:
090: // initialize Message Service
091: Map<String, String> activationConfigMap = new HashMap<String, String>();
092: ActivationConfigProperty[] activationConfigProperties = messageDriven
093: .activationConfig();
094: for (ActivationConfigProperty property : activationConfigProperties) {
095: activationConfigMap.put(property.propertyName(), property
096: .propertyValue());
097: }
098: String destination = activationConfigMap.get("destination");
099: String destinationType = activationConfigMap
100: .get("destinationType");
101: try {
102: if (destinationType.equals(Topic.class.getName())) { //Topic
103: isQueue = false;
104: MessageService messageService = getEJBContainer()
105: .getMessageService();
106: this .destination = messageService
107: .createTopic(destination);
108: } else { // Queue
109: isQueue = true;
110: MessageService messageService = getEJBContainer()
111: .getMessageService();
112: this .destination = messageService
113: .createQueue(destination);
114: }
115: } catch (Exception e) {
116: throw new EJBException(
117: "Could not initialize MessageDriven Bean: "
118: + getEJBName(), e);
119: }
120: }
121:
122: public JMSDestination getDestination() {
123: return destination;
124: }
125:
126: public boolean isLocal() {
127: return true;
128: }
129:
130: public boolean isRemote() {
131: return false;
132: }
133:
134: public boolean isSession() {
135: return false;
136: }
137:
138: /**
139: * 从 Pool ä¸å¾—到一个新的 Bean 实例
140: *
141: * @param ejbObjectId ejb object id
142: * @throws javax.ejb.EJBException exception
143: */
144: public ExtendEJBContext getEJBContext(EJBObjectId ejbObjectId)
145: throws EJBException {
146: try {
147: EJBContextImpl ejbContext = (EJBContextImpl) pool
148: .borrowObject();
149: return ejbContext;
150: } catch (Exception e) {
151: throw new EJBException("Create EJBContext failed.", e);
152: }
153: }
154:
155: /**
156: * 将实例返回给 pool
157: *
158: * @param ejbContext ejb context
159: */
160: public void reuseEJBContext(ExtendEJBContext ejbContext) {
161: try {
162: pool.returnObject(ejbContext);
163: } catch (Exception e) {
164: throw new EJBException("Return EJBContext to pool failed!",
165: e);
166: }
167: }
168:
169: public ExtendEJBContext createEJBContext(EJBObjectId ejbObjectId,
170: Object instance) {
171: if (messageDrivenEJBContext == null) {
172: messageDrivenEJBContext = new MessageDrivenEJBContextImpl(
173: ejbObjectId, instance);
174: }
175: return messageDrivenEJBContext;
176: }
177:
178: /**
179: * �个Stateless Bucket�有一个 EJBObjectId
180: */
181: public synchronized EJBObjectId createEJBObjectId() {
182: if (ejbObjectId == null) {
183: ejbObjectId = new EJBObjectId(getEJBName());
184: }
185: return ejbObjectId;
186: }
187:
188: public boolean isStateful() {
189: return false;
190: }
191:
192: public boolean isWebService() {
193: return false;
194: }
195:
196: public void start() {
197: // register MessageListener to Destination
198: getDestination().registerMessageListener(this );
199: /*
200: try {
201:
202: MessageService connectionFactory = getEJBContainer().getMessageService();
203: if (isQueue) {
204: QueueConnection connection = connectionFactory.createQueueConnection();
205: QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
206: QueueReceiver receiver = session.createReceiver((Queue)getDestination());
207: receiver.setMessageListener(this);
208: connection.start();
209:
210: }
211: else {
212: TopicConnection connection = connectionFactory.createTopicConnection();
213: TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
214: TopicSubscriber receiver = session.createSubscriber((Topic)getDestination());
215: receiver.setMessageListener(this);
216: connection.start();
217: }
218: }
219: catch (Exception e) {
220: throw new EJBException(e);
221: }
222: */
223:
224: }
225:
226: /**
227: * destroy bucket, invoke when container unload ejb
228: */
229: public void stop() {
230: logger.debug("Destroy EJB: " + getEJBName() + ", Module: "
231: + getModule().getName());
232: try {
233: //maybe close by JMS Connection
234: getDestination().unregisterMessageListener(this );
235: pool.clear();
236: pool.close();
237: } catch (Exception e) {
238: e.printStackTrace();
239: }
240: }
241:
242: /**
243: * 生�基于动�代�的 Stub
244: */
245: public synchronized EJBObject createProxyStub() {
246: if (proxyStub == null) {
247: proxyStub = super .createProxyStub();
248: }
249: return proxyStub;
250: }
251:
252: public void onMessage(Message message) {
253: try {
254: //TODO: How to get corret SessionContext
255: getEJBContainer().invokeEJB(createEJBObjectId(),
256: MessageListenerUtils.getOnMessageMethod(),
257: new Object[] { message },
258: SessionContext.getCurrentThreadSessionContext());
259: } catch (EJBException e) {
260: throw e;
261: } catch (Exception e) {
262: throw new EJBException(e);
263: }
264:
265: }
266:
267: //--- jakarta commons-pool PoolableObjectFactory ---
268: public Object makeObject() throws Exception {
269: Object obj = getBeanClass().newInstance();
270: ExtendEJBContext ejbContext = createEJBContext(
271: createEJBObjectId(), obj);
272: // post construct
273: for (Method postConstructMethod : getPostConstructMethods()) {
274: logger
275: .debug("PostConstruct method for ejb: "
276: + getEJBName() + ", method: "
277: + postConstructMethod);
278: postConstructMethod.invoke(ejbContext.getEJBInstance());
279: }
280:
281: // 注入 @EJB
282: for (FieldEJBDependence fieldEJBDependence : fieldEJBdependents) {
283: fieldEJBDependence.inject(ejbContext);
284: }
285:
286: // 注入 @Resource
287: for (FieldResourceDependence fieldResourceDependence : fieldResourcedependents) {
288: fieldResourceDependence.inject(ejbContext);
289: }
290:
291: // 注入 @PersistenceContext
292: for (FieldPersistenceContextDependence fieldPersistenceContextDependence : fieldPersistenceContextDependences) {
293: fieldPersistenceContextDependence.inject(ejbContext);
294: }
295:
296: // 注入 @PersistenceUnit
297: for (FieldPersistenceUnitDependence persistenceUnitDependence : fieldPersistenceUnitDependences) {
298: persistenceUnitDependence.inject(ejbContext);
299: }
300:
301: //返回 EJBContext
302: return ejbContext;
303: }
304:
305: public boolean validateObject(Object obj) {
306: return true;
307: }
308:
309: public void activateObject(Object obj) throws Exception {
310: }
311:
312: public void passivateObject(Object obj) throws Exception {
313: }
314:
315: public void destroyObject(Object obj) throws Exception {
316: for (Method preDestroyMethod : getPreDestroyMethods()) {
317: logger.debug("PreDestory method for ejb: " + getEJBName()
318: + ", method: " + preDestroyMethod);
319: preDestroyMethod.invoke(((ExtendEJBContext) obj)
320: .getEJBInstance());
321: }
322: }
323:
324: // EJBContext Implementation
325: @SuppressWarnings({"deprecation"})
326: public class MessageDrivenEJBContextImpl extends EJBContextImpl {
327:
328: public MessageDrivenEJBContextImpl(EJBObjectId ejbObjectId,
329: Object ejbInstance) {
330: super (ejbObjectId, ejbInstance);
331: }
332:
333: public TimerService getTimerService()
334: throws IllegalStateException {
335: return null;
336: }
337:
338: // SessionContext
339: public <T> T getBusinessObject(Class<T> businessInterface)
340: throws IllegalStateException {
341: return (T) proxyStub;
342: }
343:
344: // EJBObject & EJBLocalObject
345: public void remove() throws RemoveException {
346: try {
347: destroyObject(getEJBInstance());
348: } catch (Exception e) {
349: String msg = "Remove EJB instance failed!";
350: logger.warn(msg, e);
351: throw new RemoveException(msg);
352: }
353: }
354: }
355:
356: }
|