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: Embedded.java 2137 2007-12-10 18:26:53Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.server;
025:
026: import java.io.File;
027: import java.net.URL;
028: import java.rmi.RemoteException;
029: import java.util.ArrayList;
030: import java.util.List;
031: import java.util.ListIterator;
032: import java.util.Map;
033: import java.util.concurrent.ConcurrentHashMap;
034:
035: import javax.naming.Context;
036: import javax.naming.InitialContext;
037: import javax.naming.NamingException;
038:
039: import org.ow2.easybeans.api.EZBContainer;
040: import org.ow2.easybeans.api.EZBContainerConfig;
041: import org.ow2.easybeans.api.EZBServer;
042: import org.ow2.easybeans.api.EmbeddedManager;
043: import org.ow2.easybeans.component.ComponentManager;
044: import org.ow2.easybeans.component.Components;
045: import org.ow2.easybeans.component.api.EZBComponent;
046: import org.ow2.easybeans.component.api.EZBComponentException;
047: import org.ow2.easybeans.component.itf.RegistryComponent;
048: import org.ow2.easybeans.container.JContainer3;
049: import org.ow2.easybeans.container.JContainerConfig;
050: import org.ow2.easybeans.deployer.IRemoteDeployer;
051: import org.ow2.easybeans.deployer.RemoteDeployer;
052: import org.ow2.easybeans.jmx.CommonsModelerException;
053: import org.ow2.easybeans.jmx.CommonsModelerHelper;
054: import org.ow2.easybeans.jmx.JMXRemoteException;
055: import org.ow2.easybeans.jmx.JMXRemoteHelper;
056: import org.ow2.easybeans.jmx.MBeanServerException;
057: import org.ow2.easybeans.jmx.MBeanServerHelper;
058: import org.ow2.easybeans.jmx.MBeansException;
059: import org.ow2.easybeans.jmx.MBeansHelper;
060: import org.ow2.easybeans.rpc.rmi.server.RMIServerRPC;
061: import org.ow2.easybeans.rpc.rmi.server.RMIServerRPCImpl;
062: import org.ow2.easybeans.security.jacc.PolicyProvider;
063: import org.ow2.util.ee.deploy.api.archive.IArchive;
064: import org.ow2.util.ee.deploy.api.deployer.DeployerException;
065: import org.ow2.util.log.Log;
066: import org.ow2.util.log.LogFactory;
067:
068: /**
069: * Allows to create an embedded EJB3 server.
070: * @author Florent Benoit
071: */
072: public class Embedded implements EZBServer {
073:
074: /**
075: * Default sleep value (for server loop).
076: */
077: private static final int SLEEP_VALUE = 10000;
078:
079: /**
080: * Core XML file (that will load Quartz component, etc).
081: */
082: public static final String CORE_XML_FILE = "org/ow2/easybeans/server/easybeans-core.xml";
083:
084: /**
085: * Default deployment directory.
086: */
087: public static final String DEFAULT_DEPLOY_DIRECTORY = "easybeans-deploy";
088:
089: /**
090: * Deprecated default deployment directory.
091: */
092: public static final String DEPRECATED_DEFAULT_DEPLOY_DIRECTORY = "ejb3s";
093:
094: /**
095: * Logger.
096: */
097: private static Log logger = LogFactory.getLog(Embedded.class);
098:
099: /**
100: * Internal (global) counter of all embedded instance created.
101: */
102: private static int counter = 0;
103:
104: /**
105: * ID of this embedded server.
106: */
107: private Integer id = null;
108:
109: /**
110: * Configuration of this server.
111: */
112: private ServerConfig serverConfig = null;
113:
114: /**
115: * Map of managed ejb3 containers.
116: */
117: private Map<String, EZBContainer> containers = null;
118:
119: /**
120: * Deployer instance.
121: */
122: private RemoteDeployer deployer = null;
123:
124: /**
125: * List of components that have been defined.
126: */
127: private Components components = null;
128:
129: /**
130: * Manager of components.
131: */
132: private ComponentManager componentManager = null;
133:
134: /**
135: * Server started ?
136: */
137: private boolean started = false;
138:
139: /**
140: * Monitor of the containers.
141: */
142: private ContainersMonitor monitor = null;
143:
144: /**
145: * Creates a new Embedded server.<br>
146: * It will take default values of configuration.
147: */
148: public Embedded() {
149: this .id = Integer.valueOf(counter++);
150: this .containers = new ConcurrentHashMap<String, EZBContainer>();
151: this .serverConfig = new ServerConfig();
152:
153: // register to the list
154: EmbeddedManager.addEmbedded(this );
155:
156: // Init components
157: this .components = new Components();
158:
159: // Create component manager around components
160: this .componentManager = new ComponentManager(components);
161: }
162:
163: /**
164: * Starts the EJB3 server.
165: * @throws EmbeddedException if there is a failure while starting the
166: * server.
167: */
168: public void start() throws EmbeddedException {
169: long tStart = System.currentTimeMillis();
170:
171: // Add default components like Quartz Timer service, etc.
172: if (serverConfig.addEmbeddedComponents()) {
173: // Get URL
174: URL xmlConfigurationURL = Thread.currentThread()
175: .getContextClassLoader().getResource(CORE_XML_FILE);
176:
177: // Configure the given embedded instance (= this)
178: try {
179: EmbeddedConfigurator.init(this , xmlConfigurationURL);
180: } catch (EmbeddedException e) {
181: throw new EmbeddedException(
182: "Cannot add the core components on the embedded server",
183: e);
184: }
185: }
186:
187: // Init JACC
188: if (serverConfig.initJACC()) {
189: PolicyProvider.init();
190: }
191:
192: // configure
193: configure();
194:
195: if (serverConfig.isAutoConfigureComponents()) {
196: // Init components
197: try {
198: componentManager.initComponents();
199: } catch (EZBComponentException e) {
200: throw new EmbeddedException("Cannot init components", e);
201: }
202:
203: // Start components
204: try {
205: componentManager.startComponents();
206: } catch (EZBComponentException e) {
207: throw new EmbeddedException("Cannot start components",
208: e);
209: }
210: }
211:
212: if (serverConfig.isUsingNaming()) {
213: // url.pkg for java:
214: System.setProperty(Context.URL_PKG_PREFIXES,
215: "org.ow2.easybeans.naming.pkg");
216: }
217:
218: // set the deployer used for this component.
219: try {
220: deployer = new RemoteDeployer(this );
221: } catch (DeployerException e) {
222: throw new EmbeddedException(
223: "Cannot build a remote deployer.", e);
224: }
225:
226: MBeansHelper.getInstance().activate(
227: serverConfig.isUsingMBeans());
228: if (serverConfig.isUsingMBeans()) {
229:
230: // init Modeler Registry
231: try {
232: CommonsModelerHelper.initRegistry();
233: } catch (CommonsModelerException e) {
234: throw new EmbeddedException("Cannot init MBean server",
235: e);
236: }
237:
238: // Start MBeanServer (if any)
239: try {
240: MBeanServerHelper.startMBeanServer();
241: } catch (MBeanServerException e) {
242: throw new EmbeddedException(
243: "Cannot start MBean server", e);
244: }
245:
246: if (serverConfig.isStartJMXConnector()) {
247: try {
248: JMXRemoteHelper
249: .startConnector((RegistryComponent) this
250: .getComponent("org.ow2.easybeans.component.carol.CarolComponent"));
251: } catch (JMXRemoteException e) {
252: throw new EmbeddedException(
253: "Cannot start JMX Remote connector", e);
254: }
255: }
256:
257: // register the Deployer
258: if (serverConfig.isRegisterDeployerMBean()) {
259: try {
260: MBeansHelper.getInstance().registerMBean(deployer);
261: } catch (MBeansException e) {
262: throw new EmbeddedException("Cannot init MBeans", e);
263: }
264: }
265:
266: // register the Server
267: if (serverConfig.isRegisterJ2EEServerMBean()) {
268: try {
269: MBeansHelper.getInstance().registerMBean(this );
270: } catch (MBeansException e) {
271: throw new EmbeddedException("Cannot init MBeans", e);
272: }
273: }
274: }
275:
276: // Bind the RPC object
277: RMIServerRPC invoker = null;
278: try {
279: invoker = new RMIServerRPCImpl(this );
280: } catch (RemoteException e) {
281: throw new EmbeddedException("Cannot build RPC invoker", e);
282: }
283: try {
284: new InitialContext().rebind(RMIServerRPC.RPC_JNDI_NAME,
285: invoker);
286: } catch (NamingException e) {
287: throw new EmbeddedException("Cannot bind the RPC invoker",
288: e);
289: }
290:
291: if (serverConfig.isDirectoryScanningEnabled()) {
292: if (serverConfig.isUsingOldDeployer()) {
293: // add a thread which monitor containers file
294: monitor = new ContainersMonitor(this );
295: } else {
296: // use the new one
297: monitor = new DirectoryDeployerMonitor(this );
298: }
299: monitor.init();
300: }
301:
302: logger.info("Embedded.start.startup", Version.getVersion(),
303: Long.valueOf(System.currentTimeMillis() - tStart));
304: logger.debug("Embedded.start.created", Integer
305: .valueOf(containers.size()));
306: if (serverConfig.isDirectoryScanningEnabled()) {
307: monitor.start();
308: }
309:
310: // It is started
311: started = true;
312:
313: if (serverConfig.shouldWait()) {
314: logger.info("Embedded.start.waiting");
315: while (true) {
316: try {
317: Thread.sleep(SLEEP_VALUE);
318: } catch (InterruptedException e) {
319: logger.error("Cannot sleep in the thread", e);
320: }
321: }
322: }
323: }
324:
325: /**
326: * Stops the EJB3 server.
327: * @throws EmbeddedException if container cannot be stopped.
328: */
329: public synchronized void stop() throws EmbeddedException {
330: // ensure started
331: if (!started) {
332: throw new EmbeddedException(
333: "Cannot stop the server as it is not started.");
334: }
335:
336: // Stop the containers
337: // Use a ListIterator to allow us to safely remove EZBContainers
338: // from the List being processed.
339: List<EZBContainer> containersList = new ArrayList<EZBContainer>(
340: this .containers.values());
341: ListIterator<EZBContainer> li = containersList.listIterator();
342: while (li.hasNext()) {
343: EZBContainer container = li.next();
344: container.stop();
345: removeContainer(container);
346: }
347:
348: if (serverConfig.isDirectoryScanningEnabled()) {
349: monitor.stopOrder();
350: }
351:
352: // Unregister MBeans
353: if (serverConfig.isUsingMBeans()) {
354:
355: if (serverConfig.isStartJMXConnector()) {
356: // Stop the JMX Connector
357: try {
358: JMXRemoteHelper.stopConnector();
359: } catch (JMXRemoteException e) {
360: // Only log the Exception
361: logger.debug("Cannot stop JMX Remote connector", e);
362: // and continue ...
363: }
364: }
365:
366: // Unregister the Deployer
367: if (serverConfig.isRegisterDeployerMBean()) {
368: try {
369: MBeansHelper.getInstance()
370: .unregisterMBean(deployer);
371: } catch (MBeansException e) {
372: // Only log the Exception
373: logger.error("Cannot unregister Deployer MBean", e);
374: }
375: }
376:
377: // Unregister the Server
378: if (serverConfig.isRegisterJ2EEServerMBean()) {
379: try {
380: MBeansHelper.getInstance().unregisterMBean(this );
381: } catch (MBeansException e) {
382: // Only log the Exception
383: logger.error("Cannot unregister Embedded MBean", e);
384: }
385: }
386: }
387:
388: // Unbind the RPCInvoker Remote Object
389: try {
390: new InitialContext().unbind(RMIServerRPC.RPC_JNDI_NAME);
391: } catch (NamingException e) {
392: // Only log the Exception
393: logger.error("Cannot unbind the RPC invoker", e);
394: }
395:
396: // Stop the components
397: componentManager.stopComponents();
398:
399: logger.info("Embedded.stop.stopped", Version.getVersion());
400: }
401:
402: /**
403: * Sets the server configuration (not the components).
404: * @param serverConfig the given configuration
405: */
406: public void setServerConfig(final ServerConfig serverConfig) {
407: // check status
408: if (started) {
409: throw new IllegalStateException(
410: "Cannot set the server configuration when server has been started.");
411: }
412: this .serverConfig = serverConfig;
413: }
414:
415: /**
416: * Gets a container managed by this server.
417: * @param id the container id.
418: * @return the container if it is found, else null.
419: */
420: public EZBContainer getContainer(final String id) {
421: return containers.get(id);
422: }
423:
424: /**
425: * Gets a container managed by this server.
426: * @param archive the archive used by the given container.
427: * @return the container if it is found, else null.
428: */
429: public EZBContainer findContainer(final IArchive archive) {
430: // Invalid archive
431: if (archive == null) {
432: return null;
433: }
434: // Search a container for the given archive.
435: for (EZBContainer container : containers.values()) {
436: if (archive.equals(container.getArchive())) {
437: return container;
438: }
439: }
440: return null;
441: }
442:
443: /**
444: * Configure the server by using the given configuration.
445: */
446: private void configure() {
447:
448: // get deploy directories
449: List<File> deployDirectories = serverConfig
450: .getDeployDirectories();
451:
452: // Check deploy directories
453: for (File deployDirectory : deployDirectories) {
454: if (!deployDirectory.exists()) {
455: if (deployDirectory.mkdir()) {
456: logger.warn("Directory '"
457: + deployDirectory.getAbsolutePath()
458: + "' created.");
459: } else {
460: throw new IllegalStateException(
461: "Cannot make directory '"
462: + deployDirectory.getAbsolutePath()
463: + "'.");
464: }
465: }
466: }
467:
468: // if deprecated path is found, add it
469: if (deployDirectories.size() == 1) {
470: File deprecatedDir = new File(deployDirectories.get(0)
471: .getParentFile(),
472: DEPRECATED_DEFAULT_DEPLOY_DIRECTORY);
473: if (deprecatedDir.exists()) {
474: logger
475: .warn(
476: "DEPRECATED directory ''{0}'' found. New deploy directory with the name ''{1}'' has to be used instead.",
477: deprecatedDir, DEFAULT_DEPLOY_DIRECTORY);
478: serverConfig.getDeployDirectories().add(deprecatedDir);
479: }
480: }
481:
482: if (serverConfig.getDeployDirectories().size() > 0) {
483: logger.info(
484: "Using directories ''{0}'' as deploy directories",
485: deployDirectories);
486: }
487: }
488:
489: /**
490: * Creates and adds an ejb3 container to the managed container.
491: * @param archive jar file or exploded archive.
492: * @return the created container.
493: */
494: public EZBContainer createContainer(final IArchive archive) {
495: EZBContainerConfig jConfig = new JContainerConfig(archive);
496: jConfig.setEZBServer(this );
497: EZBContainer container = new JContainer3(jConfig);
498: addContainer(container);
499:
500: return container;
501: }
502:
503: /**
504: * Add an already created container.
505: * @param container the EZBContainer to be added.
506: */
507: public void addContainer(final EZBContainer container) {
508: // Add extensions
509: callJContainerConfigExtensions(container.getConfiguration());
510:
511: String id = container.getId();
512: containers.put(id, container);
513: }
514:
515: /**
516: * Remove a given container.
517: * @param container the container to be removed.
518: */
519: public void removeContainer(final EZBContainer container) {
520: containers.remove(container.getId());
521:
522: logger.info("Container ''{0}'' removed", container.getArchive()
523: .getName());
524: }
525:
526: /**
527: * Adapt the JContainerConfig for all
528: * {@link EasyBeansConfigurationExtension}.
529: * @param jcc the JContainerConfig to adapt.
530: */
531: private void callJContainerConfigExtensions(
532: final EZBContainerConfig jcc) {
533:
534: for (EasyBeansConfigurationExtension extension : this .serverConfig
535: .getExtensionFactories()) {
536: try {
537: extension.configure(jcc);
538: } catch (Throwable t) {
539: // prevent malicious code to break everything ...
540: logger
541: .info(
542: "Failed to configure JContainerConfig with {0}",
543: extension.getClass().getName());
544: }
545: }
546: }
547:
548: /**
549: * @return the configuration of this server.
550: */
551: public ServerConfig getServerConfig() {
552: return serverConfig;
553: }
554:
555: /**
556: * @return the containers managed by this server.
557: */
558: public Map<String, EZBContainer> getContainers() {
559: return containers;
560: }
561:
562: /**
563: * Gets the id of this embedded server.
564: * @return the id of this server.
565: */
566: public Integer getID() {
567: return id;
568: }
569:
570: /**
571: * @return the Remote deployer instance.
572: */
573: public IRemoteDeployer getDeployer() {
574: return deployer;
575: }
576:
577: /**
578: * Gets the components that have been defined for this embedded server.
579: * @return the components.
580: */
581: public Components getComponents() {
582: return this .components;
583: }
584:
585: /**
586: * Sets the components that needs to be launched.
587: * @param components the set of components.
588: */
589: public void setComponents(final Components components) {
590: this .components = components;
591: }
592:
593: /**
594: * Gets component with the given name.
595: * @param componentName the name of the component.
596: * @return the component (if any)
597: */
598: public EZBComponent getComponent(final String componentName) {
599: // ask registry if present.
600: if (componentManager != null) {
601: return componentManager.getComponentRegistry()
602: .getComponent(componentName);
603: }
604: return null;
605: }
606:
607: /**
608: * @return Returns the ComponentManager used by this instance.
609: */
610: public ComponentManager getComponentManager() {
611: return componentManager;
612: }
613: }
|