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: MDBMessageEndPointFactory.java 1970 2007-10-16 11:49:25Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.container.mdb;
025:
026: import java.lang.reflect.InvocationTargetException;
027: import java.lang.reflect.Method;
028: import java.util.List;
029:
030: import javax.ejb.ActivationConfigProperty;
031: import javax.ejb.EJBException;
032: import javax.ejb.Timer;
033: import javax.resource.ResourceException;
034: import javax.resource.spi.ActivationSpec;
035: import javax.resource.spi.InvalidPropertyException;
036: import javax.resource.spi.ResourceAdapter;
037: import javax.resource.spi.UnavailableException;
038: import javax.resource.spi.endpoint.MessageEndpoint;
039: import javax.resource.spi.endpoint.MessageEndpointFactory;
040: import javax.transaction.xa.XAResource;
041:
042: import org.ow2.easybeans.api.EZBContainer;
043: import org.ow2.easybeans.api.FactoryException;
044: import org.ow2.easybeans.api.bean.EasyBeansMDB;
045: import org.ow2.easybeans.api.pool.PoolException;
046:
047: /**
048: * Defines a class that will manage the message end point factory for the MDB.
049: * The super class will manage the pool of message end point.
050: * @author Florent Benoit
051: */
052: public class MDBMessageEndPointFactory extends MDBFactory implements
053: MessageEndpointFactory {
054:
055: /**
056: * Default name of the activation spec (JORAM).
057: */
058: public static final String DEFAULT_ACTIVATION_SPEC_NAME = "joramActivationSpec";
059:
060: /**
061: * ActivationSpec object linked to this factory (used to activate or
062: * deactive an endpoint factory (us).
063: */
064: private ActivationSpec activationSpec = null;
065:
066: /**
067: * Resource adapter that provides the activation spec implementation.
068: */
069: private ResourceAdapter resourceAdapter = null;
070:
071: /**
072: * Default constructor (delegate to super class).
073: * @param className name of this factory (name of class that is managed)
074: * @param container the root component of this factory.
075: * @param activationSpec the activation Spec object used for
076: * activating/deactivating.
077: * @param resourceAdapter the resource adapter used to activate/deactivate
078: * ourself.
079: * @throws FactoryException if super constructor fails
080: */
081: public MDBMessageEndPointFactory(final String className,
082: final EZBContainer container,
083: final ActivationSpec activationSpec,
084: final ResourceAdapter resourceAdapter)
085: throws FactoryException {
086: super (className, container);
087: this .activationSpec = activationSpec;
088: this .resourceAdapter = resourceAdapter;
089: }
090:
091: /**
092: * Init the factory.
093: * @throws FactoryException if the initialization fails.
094: */
095: @Override
096: public void init() throws FactoryException {
097: initActivationSpec();
098:
099: validateActivationSpec();
100:
101: activate();
102: }
103:
104: /**
105: * Call setters method on the activation spec object.
106: * @throws FactoryException if activation spec object is not configured.
107: */
108: private void initActivationSpec() throws FactoryException {
109: // Call setter method for each property found in the activation
110: // properties
111: List<ActivationConfigProperty> properties = getMessageDrivenInfo()
112: .getActivationConfigProperties();
113: if (properties != null) {
114: for (ActivationConfigProperty property : properties) {
115: // get property name
116: String key = property.propertyName();
117: // and value
118: String value = property.propertyValue();
119:
120: // define setter method name
121: String methodName = "set"
122: + key.substring(0, 1).toUpperCase()
123: + key.substring(1);
124:
125: // get Method (reflection)
126: Method m = null;
127: try {
128: m = activationSpec.getClass().getMethod(methodName,
129: new Class[] { String.class });
130: } catch (SecurityException e) {
131: throw new FactoryException(
132: "Cannot get a method named '" + methodName
133: + "' on activation spec object '"
134: + activationSpec + "'.", e);
135: } catch (NoSuchMethodException e) {
136: throw new FactoryException(
137: "Cannot get a method named '" + methodName
138: + "' on activation spec object '"
139: + activationSpec + "'.", e);
140: }
141:
142: // invoke method
143: try {
144: m.invoke(activationSpec, value);
145: } catch (IllegalArgumentException e) {
146: throw new FactoryException(
147: "Cannot invoke method named '" + methodName
148: + "' with value '" + value
149: + "' on activation spec object '"
150: + activationSpec + "'.", e);
151: } catch (IllegalAccessException e) {
152: throw new FactoryException(
153: "Cannot invoke method named '" + methodName
154: + "' with value '" + value
155: + "' on activation spec object '"
156: + activationSpec + "'.", e);
157: } catch (InvocationTargetException e) {
158: throw new FactoryException(
159: "Cannot invoke method named '" + methodName
160: + "' with value '" + value
161: + "' on activation spec object '"
162: + activationSpec + "'.", e);
163: }
164:
165: }
166: }
167:
168: }
169:
170: /**
171: * Validate the configuration used p, tje activation spec object.
172: * @throws FactoryException if the validation of the activation spec
173: * implementation object fails.
174: */
175: private void validateActivationSpec() throws FactoryException {
176: try {
177: activationSpec.validate();
178: } catch (InvalidPropertyException e) {
179: throw new FactoryException(
180: "Cannot validate the validation spec object", e);
181: }
182: }
183:
184: /**
185: * Activate this endpoint factory on resource adapter with the activation
186: * spec object.
187: * @throws FactoryException if the activation fails.
188: */
189: private void activate() throws FactoryException {
190: try {
191: resourceAdapter.endpointActivation(this , activationSpec);
192: } catch (ResourceException e) {
193: throw new FactoryException(
194: "Cannot activate the activationspec object and us (MessageEndPointFactory) on the resource adapter",
195: e);
196: }
197: }
198:
199: /**
200: * This is used to create a message endpoint. The message endpoint is
201: * expected to implement the correct message listener type.
202: * @param xaResource an optional XAResource instance used to get transaction
203: * notifications when the message delivery is transacted.
204: * @return a message endpoint instance.
205: * @throws UnavailableException indicates a transient failure in creating a
206: * message endpoint. Subsequent attempts to create a message
207: * endpoint might succeed.
208: */
209: public MessageEndpoint createEndpoint(final XAResource xaResource)
210: throws UnavailableException {
211: // Use the internal method (which return a MDBMessageEndPoint object)
212: return createInternalEndpoint(xaResource);
213: }
214:
215: /**
216: * This is used to create a message endpoint. The message endpoint is
217: * expected to implement the correct message listener type.
218: * @param xaResource an optional XAResource instance used to get transaction
219: * notifications when the message delivery is transacted.
220: * @return a message endpoint instance.
221: * @throws UnavailableException indicates a transient failure in creating a
222: * message endpoint. Subsequent attempts to create a message
223: * endpoint might succeed.
224: */
225: public MDBMessageEndPoint createInternalEndpoint(
226: final XAResource xaResource) throws UnavailableException {
227: // Instance that implements the MessageEndpoint interface
228: MDBMessageEndPoint messageEndpoint = null;
229:
230: // get an instance of MDB
231: EasyBeansMDB easyBeansMDB = null;
232: try {
233: easyBeansMDB = getPool().get();
234: } catch (PoolException e) {
235: throw new UnavailableException(
236: "Cannot get instance in the pool", e);
237: }
238:
239: // Build a wrapper around this mdb instance
240: // TODO: For now, this is only for JMS, needs to be changed.
241: messageEndpoint = new MDBMessageListenerEndPoint(this ,
242: easyBeansMDB);
243:
244: // Set XAResource of the message endpoint.
245: messageEndpoint.setXaResource(xaResource);
246:
247: return messageEndpoint;
248: }
249:
250: /**
251: * Release an endpoint created by this factory.
252: * @param mdbMessageEndPoint the endpoint to release.
253: */
254: protected void releaseEndPoint(
255: final MDBMessageEndPoint mdbMessageEndPoint) {
256: // Release the wrapped message driven bean
257: try {
258: getPool().release(mdbMessageEndPoint.getEasyBeansMDB());
259: } catch (PoolException e) {
260: throw new IllegalStateException(
261: "Cannot release the given message end point", e);
262: }
263: }
264:
265: /**
266: * This is used to find out whether message deliveries to a target method on
267: * a message listener interface that is implemented by a message endpoint
268: * will be transacted or not. The message endpoint may indicate its
269: * transacted delivery preferences (at a per method level) through its
270: * deployment descriptor. The message delivery preferences must not change
271: * during the lifetime of a message endpoint.
272: * @param method description of a target method. This information about the
273: * intended target method allows an application server to find out
274: * whether the target method call will be transacted or not.
275: * @return boolean whether the specified method is transacted
276: * @throws NoSuchMethodException exception to throw
277: */
278: public boolean isDeliveryTransacted(final Method method)
279: throws NoSuchMethodException {
280: // TODO : Not yet implemented
281: return false;
282: }
283:
284: /**
285: * Stops the factory.
286: */
287: @Override
288: public void stop() {
289: // stop the pool.
290: super .stop();
291:
292: // deactivate this factory
293: resourceAdapter.endpointDeactivation(this , activationSpec);
294:
295: }
296:
297: /**
298: * Notified when the timer service send a Timer object.
299: * It has to call the Timed method.
300: * @param timer the given timer object that will be given to the timer method.
301: */
302: public void notifyTimeout(final Timer timer) {
303: // Get an EndPoint
304: MDBMessageEndPoint mdbMessageEndPoint = null;
305: try {
306: mdbMessageEndPoint = createInternalEndpoint(null);
307: } catch (UnavailableException e) {
308: throw new EJBException(
309: "Cannot get an endpoint for notifying the timeout",
310: e);
311: }
312:
313: // Call the timeout method
314: try {
315: mdbMessageEndPoint.notifyTimeout(timer);
316: } finally {
317: // release the endpoint
318: releaseEndPoint(mdbMessageEndPoint);
319: }
320:
321: }
322:
323: // /**
324: // * Notify a timeout for this bean
325: // * @param timer timer whose expiration caused this notification.
326: // */
327: // public void notifyTimeout(Timer timer) {
328: // if (stopped) {
329: // TraceEjb.mdb.log(BasicLevel.WARN, "Container stopped");
330: // return;
331: // }
332: // String methName = "notifyTimeout: ";
333: // if (TraceEjb.isDebugJms()) {
334: // TraceEjb.mdb.log(BasicLevel.DEBUG, methName);
335: // }
336: //
337: // // We need an instance from the pool to process the timeout.
338: // JMessageEndpoint ep = null;
339: // try {
340: // ep = getNewInstance(null);
341: // } catch (Exception e) {
342: // TraceEjb.mdb.log(BasicLevel.ERROR, methName + "exception:" + e);
343: // throw new EJBException("Cannot deliver the timeout", e);
344: // }
345: //
346: // // deliver the timeout to the bean
347: // ep.deliverTimeout(timer);
348: //
349: // // release the instance
350: // releaseEndpoint(ep);
351: // }
352: // }
353: }
|