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: EasyBeansResourceAdapter.java 2080 2007-12-04 11:22:57Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.server.ra;
025:
026: import java.io.File;
027: import java.lang.reflect.InvocationTargetException;
028: import java.lang.reflect.Method;
029: import java.net.URL;
030:
031: import javax.naming.Context;
032: import javax.naming.InitialContext;
033: import javax.naming.NamingException;
034: import javax.resource.ResourceException;
035: import javax.resource.spi.ActivationSpec;
036: import javax.resource.spi.BootstrapContext;
037: import javax.resource.spi.ResourceAdapterInternalException;
038: import javax.resource.spi.endpoint.MessageEndpointFactory;
039: import javax.rmi.PortableRemoteObject;
040: import javax.transaction.xa.XAResource;
041:
042: import org.ow2.easybeans.container.mdb.helper.JOnAS4ResourceAdapterFinder;
043: import org.ow2.easybeans.container.mdb.helper.MDBResourceAdapterHelper;
044: import org.ow2.easybeans.deployable.DeployerFactory;
045: import org.ow2.easybeans.deployer.JOnASDeployer;
046: import org.ow2.easybeans.security.api.EZBSecurityCurrent;
047: import org.ow2.easybeans.security.propagation.jonas.JOnASSecurityCurrent;
048: import org.ow2.easybeans.server.EasyBeans;
049: import org.ow2.easybeans.server.Embedded;
050: import org.ow2.easybeans.server.EmbeddedConfigurator;
051: import org.ow2.easybeans.server.EmbeddedException;
052: import org.ow2.easybeans.server.ServerConfig;
053: import org.ow2.easybeans.util.loader.ClassUtils;
054: import org.ow2.util.log.Log;
055: import org.ow2.util.log.LogFactory;
056:
057: /**
058: * Defines a resource adapter which allow to embed the EJB3 server in Application Server.
059: * application server.
060: * @author Florent Benoit
061: */
062: public class EasyBeansResourceAdapter implements
063: javax.resource.spi.ResourceAdapter {
064:
065: /**
066: * Default XML file.
067: */
068: public static final String DEFAULT_XML_FILE = "org/ow2/easybeans/server/ra/easybeans-ra.xml";
069:
070: /**
071: * JOnAS ADM interface.
072: */
073: public static final String JONAS_ADM_ITF = "org.objectweb.jonas.adm.AdmInterface";
074:
075: /**
076: * Logger.
077: */
078: private static Log logger = LogFactory
079: .getLog(EasyBeansResourceAdapter.class);
080:
081: /**
082: * Embedded instance.
083: */
084: private Embedded embedded = null;
085:
086: /**
087: * Starts the embedded server.
088: * @param ctx - a bootstrap context containing references to useful
089: * facilities that could be used by a resource adapter instance.
090: * @throws ResourceAdapterInternalException indicates bootstrap failure.
091: */
092: public void start(final BootstrapContext ctx)
093: throws ResourceAdapterInternalException {
094: // user configuration ?
095: URL xmlConfigurationURL = Thread.currentThread()
096: .getContextClassLoader().getResource(
097: EasyBeans.USER_XML_FILE);
098:
099: if (xmlConfigurationURL == null) {
100: logger
101: .warn(
102: "No {0} resource found in classpath, use default settings",
103: EasyBeans.USER_XML_FILE);
104: xmlConfigurationURL = Thread.currentThread()
105: .getContextClassLoader().getResource(
106: DEFAULT_XML_FILE);
107: }
108: try {
109: embedded = EmbeddedConfigurator.create(xmlConfigurationURL);
110: } catch (EmbeddedException e) {
111: throw new IllegalStateException(
112: "Cannot create the embedded server", e);
113: }
114:
115: // Update configuration
116: ServerConfig serverConfig = embedded.getServerConfig();
117: String jBase = System.getProperty("jonas.base");
118: if (jBase == null) {
119: throw new ResourceAdapterInternalException(
120: "No JONAS_BASE found, cannot continue.");
121: }
122: File workDir = new File(jBase + File.separator
123: + Embedded.DEFAULT_DEPLOY_DIRECTORY);
124: workDir.mkdir();
125: serverConfig.addDeployDirectory(workDir);
126: serverConfig.setShouldWait(false);
127: serverConfig.setUseMBeans(true);
128: serverConfig.setUseNaming(false);
129: serverConfig.setInitJACC(false);
130:
131: // Use JOnAS deployer
132: DeployerFactory.setClassName(JOnASDeployer.class.getName());
133:
134: // Use JOnAS 4.x MDB Helper
135: MDBResourceAdapterHelper
136: .setResourceAdapterFinder(new JOnAS4ResourceAdapterFinder());
137:
138: // Defines JOnAS security
139: System.setProperty(
140: EZBSecurityCurrent.SECURITY_CURRENT_PROPERTY,
141: JOnASSecurityCurrent.class.getName());
142:
143: // start of the embedded object will be delayed until JOnAS is started.
144: // This is because Datasource could be deployed after this adapter and
145: // then datasource won't be found.
146: new EmbeddedStarter().start();
147:
148: }
149:
150: /**
151: * Stopp the embedded server.
152: */
153: public void stop() {
154: try {
155: embedded.stop();
156: } catch (EmbeddedException e) {
157: throw new IllegalStateException(
158: "Cannot stop the embedded server", e);
159: } finally {
160: embedded = null;
161: }
162: }
163:
164: /**
165: * This is called during the activation of a message endpoint.
166: * @param endpointFactory - a message endpoint factory instance.
167: * @param spec an activation spec JavaBean instance.
168: * @throws ResourceException - indicates message endpoint activation
169: * rejection due to incorrect activation setup information.
170: */
171: public void endpointActivation(
172: final MessageEndpointFactory endpointFactory,
173: final ActivationSpec spec) throws ResourceException {
174:
175: }
176:
177: /**
178: * This is called when a message endpoint is deactivated. The instances
179: * passed as arguments to this method call should be identical to those
180: * passed in for the corresponding endpointActivation call. This causes the
181: * resource adapter to stop delivering messages to the message endpoint. Any
182: * exception thrown by this method is ignored. After this method call, the
183: * endpoint is deemed inactive.
184: * @param endpointFactory a message endpoint factory instance.
185: * @param spec an activation spec JavaBean instance.
186: */
187: public void endpointDeactivation(
188: final MessageEndpointFactory endpointFactory,
189: final ActivationSpec spec) {
190:
191: }
192:
193: /**
194: * This method is called by the application server during crash recovery.
195: * @param specs an array of ActivationSpec JavaBeans each of which
196: * corresponds to an deployed endpoint application that was active
197: * prior to the system crash.
198: * @return an array of XAResource objects each of which represents a unique
199: * resource manager.
200: * @throws ResourceException generic exception if operation fails due to an
201: * error condition.
202: */
203: public XAResource[] getXAResources(final ActivationSpec[] specs)
204: throws ResourceException {
205:
206: return null;
207: }
208:
209: /**
210: * Gets the embedded object.
211: * @return embedded server.
212: */
213: protected Embedded getEmbedded() {
214: return embedded;
215: }
216:
217: /**
218: * This inner class will wait until the JOnAS server is ready and start the
219: * embedded server.
220: * @author Florent Benoit
221: */
222: public class EmbeddedStarter extends Thread {
223:
224: /**
225: * Sleep time for this waiter thread (1 second).
226: */
227: private static final int SLEEP_TIME = 1000;
228:
229: /**
230: * Logger.
231: */
232: private Log logger = LogFactory.getLog(EmbeddedStarter.class);
233:
234: /**
235: * Wait until JOnAS is started.<br>
236: * Then, start embedded object.
237: */
238: @Override
239: public void run() {
240: boolean embeddedStarted = false;
241:
242: while (!embeddedStarted) {
243:
244: try {
245: Thread.sleep(SLEEP_TIME);
246: } catch (InterruptedException e) {
247: throw new RuntimeException("Thread fail to sleep");
248: }
249:
250: if (jonasIsReady()) {
251: try {
252: getEmbedded().start();
253: } catch (EmbeddedException e) {
254: logger.error(
255: "Cannot start the embedded server", e);
256: }
257: embeddedStarted = true;
258: }
259: }
260: }
261:
262: /**
263: * @return true if the JOnAS server is ready, else false
264: */
265: private boolean jonasIsReady() {
266: String jonasName = System
267: .getProperty("jonas.name", "jonas");
268:
269: // Get Adm object
270: String admName = jonasName + "_Adm";
271: Context initialContext = null;
272: try {
273: initialContext = new InitialContext();
274: } catch (NamingException e) {
275: logger.error("Cannot get an initial context", e);
276: return false;
277: }
278: Object adm = null;
279: try {
280: adm = initialContext.lookup(admName);
281: } catch (NamingException e) {
282: logger.error(
283: "No {0} object found in the initial context",
284: admName, e);
285: return false;
286: }
287:
288: // Cast object into Adm object
289: // Load Adm interface
290: Class<?> admItfClass;
291: try {
292: admItfClass = ClassUtils.forName(JONAS_ADM_ITF);
293: } catch (ClassNotFoundException e) {
294: logger.error("Cannot load the class ''{0}''",
295: JONAS_ADM_ITF, e);
296: return false;
297: }
298: adm = PortableRemoteObject.narrow(adm, admItfClass);
299:
300: // Try to see if there is a method getServerState on this object
301: Method getStateMethod;
302: String methodName = "getServerState";
303: try {
304: getStateMethod = adm.getClass().getMethod(methodName);
305: } catch (SecurityException e) {
306: logger.error("Cannot get method name {0}", methodName,
307: e);
308: return false;
309: } catch (NoSuchMethodException e) {
310: logger.error("Cannot get method name {0}", methodName,
311: e);
312: return false;
313: }
314:
315: if (getStateMethod == null) {
316: logger
317: .warn(
318: "No method getStateMethod() found on object {0}",
319: adm);
320: return false;
321: }
322:
323: Integer state = null;
324: try {
325: state = (Integer) getStateMethod.invoke(adm);
326: } catch (IllegalArgumentException e) {
327: logger.error("Cannot call method {0} on object {1}.",
328: methodName, adm, e);
329: return false;
330: } catch (IllegalAccessException e) {
331: logger.error("Cannot call method {0} on object {1}.",
332: methodName, adm, e);
333: return false;
334: } catch (InvocationTargetException e) {
335: logger.error("Cannot call method {0} on object {1}.",
336: methodName, adm, e);
337: return false;
338: }
339:
340: // check the status
341: if (state.intValue() == 1) {
342: logger
343: .info("JOnAS has been started, EasyBeans is now starting.");
344: // JOnAS is ready, can start embedded !
345: return true;
346: }
347:
348: return false;
349:
350: }
351:
352: }
353:
354: }
|