001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.jbi.container;
018
019 import java.io.File;
020 import java.util.Calendar;
021 import java.util.Collection;
022 import java.util.EventListener;
023 import java.util.MissingResourceException;
024 import java.util.concurrent.Callable;
025 import java.util.concurrent.FutureTask;
026 import java.util.concurrent.TimeUnit;
027 import java.util.concurrent.atomic.AtomicBoolean;
028 import java.util.logging.Logger;
029
030 import javax.jbi.JBIException;
031 import javax.jbi.component.Component;
032 import javax.jbi.component.ComponentLifeCycle;
033 import javax.jbi.component.ServiceUnitManager;
034 import javax.jbi.management.DeploymentException;
035 import javax.jbi.management.LifeCycleMBean;
036 import javax.jbi.messaging.ExchangeStatus;
037 import javax.jbi.messaging.MessageExchange;
038 import javax.jbi.messaging.MessagingException;
039 import javax.jbi.servicedesc.ServiceEndpoint;
040 import javax.management.JMException;
041 import javax.management.MBeanServer;
042 import javax.management.ObjectName;
043 import javax.naming.InitialContext;
044 import javax.naming.NamingException;
045 import javax.swing.event.EventListenerList;
046 import javax.transaction.TransactionManager;
047 import javax.xml.namespace.QName;
048
049 import org.w3c.dom.DocumentFragment;
050
051 import org.apache.commons.logging.Log;
052 import org.apache.commons.logging.LogFactory;
053 import org.apache.servicemix.JbiConstants;
054 import org.apache.servicemix.components.util.ComponentAdaptor;
055 import org.apache.servicemix.components.util.ComponentAdaptorMEListener;
056 import org.apache.servicemix.components.util.ComponentSupport;
057 import org.apache.servicemix.components.util.PojoLifecycleAdaptor;
058 import org.apache.servicemix.components.util.PojoSupport;
059 import org.apache.servicemix.executors.ExecutorFactory;
060 import org.apache.servicemix.executors.impl.ExecutorFactoryImpl;
061 import org.apache.servicemix.id.IdGenerator;
062 import org.apache.servicemix.jbi.api.Container;
063 import org.apache.servicemix.jbi.event.ComponentListener;
064 import org.apache.servicemix.jbi.event.ContainerAware;
065 import org.apache.servicemix.jbi.event.DeploymentListener;
066 import org.apache.servicemix.jbi.event.EndpointListener;
067 import org.apache.servicemix.jbi.event.ExchangeEvent;
068 import org.apache.servicemix.jbi.event.ExchangeListener;
069 import org.apache.servicemix.jbi.event.ServiceAssemblyListener;
070 import org.apache.servicemix.jbi.event.ServiceUnitListener;
071 import org.apache.servicemix.jbi.framework.AdminCommandsService;
072 import org.apache.servicemix.jbi.framework.AutoDeploymentService;
073 import org.apache.servicemix.jbi.framework.ClientFactory;
074 import org.apache.servicemix.jbi.framework.ComponentContextImpl;
075 import org.apache.servicemix.jbi.framework.ComponentMBeanImpl;
076 import org.apache.servicemix.jbi.framework.ComponentNameSpace;
077 import org.apache.servicemix.jbi.framework.DeploymentService;
078 import org.apache.servicemix.jbi.framework.InstallationService;
079 import org.apache.servicemix.jbi.framework.Registry;
080 import org.apache.servicemix.jbi.listener.MessageExchangeListener;
081 import org.apache.servicemix.jbi.management.BaseLifeCycle;
082 import org.apache.servicemix.jbi.management.BaseSystemService;
083 import org.apache.servicemix.jbi.management.ManagementContext;
084 import org.apache.servicemix.jbi.messaging.MessageExchangeImpl;
085 import org.apache.servicemix.jbi.nmr.Broker;
086 import org.apache.servicemix.jbi.nmr.DefaultBroker;
087 import org.apache.servicemix.jbi.nmr.flow.Flow;
088
089 /**
090 * The main container
091 *
092 * @version $Revision: 3807 $
093 */
094 public class JBIContainer extends BaseLifeCycle implements Container {
095 /**
096 * Default Container name - must be unique if used in a cluster
097 */
098 public static final String DEFAULT_NAME = "ServiceMix";
099
100 private static final Log LOG = LogFactory.getLog(JBIContainer.class);
101
102 protected Broker broker = new DefaultBroker();
103 protected ServiceUnitManager serviceManager;
104 protected ManagementContext managementContext = new ManagementContext();
105 protected EnvironmentContext environmentContext = new EnvironmentContext();
106 protected InstallationService installationService = new InstallationService();
107 protected DeploymentService deploymentService = new DeploymentService();
108 protected AutoDeploymentService autoDeployService = new AutoDeploymentService();
109 protected AdminCommandsService adminCommandsService = new AdminCommandsService();
110 protected BaseSystemService[] services;
111 protected ClientFactory clientFactory = new ClientFactory();
112 protected Registry registry = new Registry();
113 protected boolean autoEnlistInTransaction;
114 protected boolean persistent;
115 protected boolean embedded;
116 protected boolean notifyStatistics;
117 protected EventListenerList listeners = new EventListenerList();
118 protected EventListener[] configuredListeners;
119 protected boolean useShutdownHook = true;
120 protected boolean useNewTransactionModel;
121 protected transient Thread shutdownHook;
122 protected ExecutorFactory executorFactory;
123 private String name = DEFAULT_NAME;
124 private InitialContext namingContext;
125 private MBeanServer mbeanServer;
126 private TransactionManager transactionManager;
127 private String rootDir;
128 private String generatedRootDirPrefix = "target/rootDirs/rootDir";
129 private boolean generateRootDir;
130 private AtomicBoolean started = new AtomicBoolean(false);
131 private AtomicBoolean containerInitialized = new AtomicBoolean(false);
132 private IdGenerator idGenerator = new IdGenerator();
133 private long forceShutdown;
134
135 /**
136 * Default Constructor
137 */
138 public JBIContainer() {
139 }
140
141 /**
142 * @return Returns the unique nam for the Container
143 */
144 public String getName() {
145 return name;
146 }
147
148 /**
149 * @param name The name to set (must be unique within a cluster)
150 */
151 public void setName(String name) {
152 this.name = name;
153 }
154
155 /**
156 * Get the description
157 *
158 * @return descrption
159 */
160 public String getDescription() {
161 return "ServiceMix JBI Container";
162 }
163
164 /**
165 * @return Returns the flowName.
166 */
167 public String getFlowName() {
168 String flowNames = getDefaultBroker().getFlowNames();
169 if (flowNames == null) {
170 return null;
171 }
172 String[] flows = flowNames.split(",");
173 if (flows.length > 1) {
174 throw new IllegalStateException("Multiple flows have been defined");
175 }
176 return flows[0];
177 }
178
179 /**
180 * @param flowName The flow to set.
181 */
182 public void setFlowName(String flowName) {
183 getDefaultBroker().setFlowNames(flowName);
184 }
185
186 /**
187 * @return Returns the flowNames.
188 */
189 public String getFlowNames() {
190 return getDefaultBroker().getFlowNames();
191 }
192
193 /**
194 * @param flowNames The flows to set.
195 */
196 public void setFlowNames(String flowNames) {
197 getDefaultBroker().setFlowNames(flowNames);
198 }
199
200 /**
201 * @return the subscriptionFlowName
202 */
203 public String getSubscriptionFlowName() {
204 return getDefaultBroker().getSubscriptionFlowName();
205 }
206
207 /**
208 * Set the subscription flow name
209 * @param subscriptionFlowName
210 */
211 public void setSubscriptionFlowName(String subscriptionFlowName) {
212 getDefaultBroker().setSubscriptionFlowName(subscriptionFlowName);
213 }
214
215 /**
216 * Set the broker message flow
217 *
218 * @param flow
219 */
220 public void setFlow(Flow flow) {
221 getDefaultBroker().setFlows(new Flow[] {flow });
222 }
223
224 /**
225 * @return the broker message Flow
226 */
227 public Flow getFlow() {
228 Flow[] flows = getDefaultBroker().getFlows();
229 if (flows == null || flows.length == 0) {
230 return null;
231 } else if (flows.length > 1) {
232 throw new IllegalStateException("Multiple flows have been defined");
233 } else {
234 return flows[0];
235 }
236 }
237
238 /**
239 * Set the broker message flows
240 *
241 * @param flows
242 */
243 public void setFlows(Flow[] flows) {
244 getDefaultBroker().setFlows(flows);
245 }
246
247 /**
248 * @return the broker message Flows
249 */
250 public Flow[] getFlows() {
251 return getDefaultBroker().getFlows();
252 }
253
254 public boolean isUseShutdownHook() {
255 return useShutdownHook;
256 }
257
258 /**
259 * Sets whether or not we should use a shutdown handler to close down the
260 * broker cleanly if the JVM is terminated. It is recommended you leave this
261 * enabled.
262 */
263 public void setUseShutdownHook(boolean useShutdownHook) {
264 this.useShutdownHook = useShutdownHook;
265 }
266
267 public boolean isUseNewTransactionModel() {
268 return useNewTransactionModel;
269 }
270
271 /**
272 * Sets whether the new transaction model should be used.
273 * @param useNewTransactionModel
274 */
275 public void setUseNewTransactionModel(boolean useNewTransactionModel) {
276 this.useNewTransactionModel = useNewTransactionModel;
277 }
278
279 /**
280 * @return the services
281 */
282 public BaseSystemService[] getServices() {
283 return services;
284 }
285
286 /**
287 * @param services the services to set
288 */
289 public void setServices(BaseSystemService[] services) {
290 this.services = services;
291 }
292
293 /**
294 * Get the ManagementContext
295 *
296 * @return the ManagementContext
297 */
298 public ManagementContext getManagementContext() {
299 return managementContext;
300 }
301
302 /**
303 * @return Return the EnvironmentContext
304 */
305 public EnvironmentContext getEnvironmentContext() {
306 return environmentContext;
307 }
308
309 /**
310 * @return Return the registry
311 */
312 public Registry getRegistry() {
313 return registry;
314 }
315
316 /**
317 * Return the DefaultBroker instance
318 */
319 public DefaultBroker getDefaultBroker() {
320 if (!(broker instanceof DefaultBroker)) {
321 throw new IllegalStateException("Broker is not a DefaultBroker");
322 }
323 return (DefaultBroker) broker;
324 }
325
326 /**
327 * @return Return the NMR broker
328 */
329 public Broker getBroker() {
330 return broker;
331 }
332
333 /**
334 * Set the Broker to use
335 */
336 public void setBroker(Broker broker) {
337 this.broker = broker;
338 }
339
340 /**
341 * @return true if creates own MBeanServer if none supplied
342 */
343 public boolean isCreateMBeanServer() {
344 return managementContext.isCreateMBeanServer();
345 }
346
347 /**
348 * Set the flag to create own MBeanServer if none supplied
349 *
350 * @param enableJMX
351 */
352 public void setCreateMBeanServer(boolean enableJMX) {
353 managementContext.setCreateMBeanServer(enableJMX);
354 }
355
356 /**
357 * @return Returns the useMBeanServer.
358 */
359 public boolean isUseMBeanServer() {
360 return managementContext.isUseMBeanServer();
361 }
362
363 /**
364 * @param useMBeanServer The useMBeanServer to set.
365 */
366 public void setUseMBeanServer(boolean useMBeanServer) {
367 managementContext.setUseMBeanServer(useMBeanServer);
368 }
369
370 /**
371 * @return Returns the useMBeanServer.
372 */
373 public boolean isCreateJmxConnector() {
374 return managementContext.isCreateJmxConnector();
375 }
376
377 /**
378 * @param createJmxConnector The createJmxConnector to set.
379 */
380 public void setCreateJmxConnector(boolean createJmxConnector) {
381 managementContext.setCreateJmxConnector(createJmxConnector);
382 }
383
384 /**
385 * @return Returns the monitorInstallationDirectory.
386 */
387 public boolean isMonitorInstallationDirectory() {
388 return autoDeployService.isMonitorInstallationDirectory();
389 }
390
391 /**
392 * @param monitorInstallationDirectory The monitorInstallationDirectory to set.
393 */
394 public void setMonitorInstallationDirectory(boolean monitorInstallationDirectory) {
395 autoDeployService.setMonitorInstallationDirectory(monitorInstallationDirectory);
396 }
397
398 /**
399 * @return Returns the monitorDeploymentDirectory.
400 */
401 public boolean isMonitorDeploymentDirectory() {
402 return autoDeployService.isMonitorDeploymentDirectory();
403 }
404
405 /**
406 * @param monitorDeploymentDirectory The monitorDeploymentDirectory to set.
407 */
408 public void setMonitorDeploymentDirectory(boolean monitorDeploymentDirectory) {
409 autoDeployService.setMonitorDeploymentDirectory(monitorDeploymentDirectory);
410 }
411
412 /**
413 * @return Returns the installationDir.
414 */
415 public String getInstallationDirPath() {
416 File dir = environmentContext.getInstallationDir();
417 return dir != null ? dir.getAbsolutePath() : "";
418 }
419
420 /**
421 * Set the installationDir - rge default location is root/<container name>/installation
422 *
423 * @param installationDir
424 */
425 public void setInstallationDirPath(String installationDir) {
426 if (installationDir != null && installationDir.length() > 0) {
427 environmentContext.setInstallationDir(new File(installationDir));
428 }
429 }
430
431 /**
432 * @return Returns the deploymentDir.
433 */
434 public String getDeploymentDirPath() {
435 File dir = environmentContext.getDeploymentDir();
436 return dir != null ? dir.getAbsolutePath() : "";
437 }
438
439 /**
440 * @param deploymentDir The deploymentDir to set.
441 */
442 public void setDeploymentDirPath(String deploymentDir) {
443 if (deploymentDir != null && deploymentDir.length() > 0) {
444 environmentContext.setDeploymentDir(new File(deploymentDir));
445 }
446 }
447
448 /**
449 * @return Returns the monitorInterval (in secs).
450 */
451 public int getMonitorInterval() {
452 return autoDeployService.getMonitorInterval();
453 }
454
455 /**
456 * @param monitorInterval The monitorInterval to set (in secs).
457 */
458 public void setMonitorInterval(int monitorInterval) {
459 autoDeployService.setMonitorInterval(monitorInterval);
460 }
461
462 /**
463 * @return the deploymentExtensions
464 */
465 public String getDeploymentExtensions() {
466 return autoDeployService.getExtensions();
467 }
468
469 /**
470 * @param deploymentExtensions the deploymentExtensions to set
471 */
472 public void setDeploymentExtensions(String deploymentExtensions) {
473 autoDeployService.setExtensions(deploymentExtensions);
474 }
475
476 /**
477 * Install an component from a url
478 *
479 * @param url
480 * @throws DeploymentException
481 */
482 public void installArchive(String url) throws DeploymentException {
483 installationService.install(url, null, true);
484 }
485
486 /**
487 * load an archive from an external location.
488 * The archive can be a Component, Service Assembly or Shared Library.
489 * @param location - can either be a url or filename (if relative - must be relative to the container)
490 * @param autoStart - if true will start the component/service assembly
491 * @throws DeploymentException
492 */
493 public void updateExternalArchive(String location, boolean autoStart) throws DeploymentException {
494 autoDeployService.updateExternalArchive(location, autoStart);
495 }
496
497 /**
498 * load an archive from an external location and starts it
499 * The archive can be a Component, Service Assembly or Shared Library.
500 * @param location - can either be a url or filename (if relative - must be relative to the container)
501 * @throws DeploymentException
502 */
503 public void updateExternalArchive(String location) throws DeploymentException {
504 updateExternalArchive(location, true);
505 }
506
507 /**
508 * @return Returns the deploymentService.
509 */
510 public DeploymentService getDeploymentService() {
511 return deploymentService;
512 }
513
514 /**
515 * @return Returns the installationService.
516 */
517 public InstallationService getInstallationService() {
518 return installationService;
519 }
520
521 /**
522 * @return the AutomDeploymentService
523 */
524 public AutoDeploymentService getAutoDeploymentService() {
525 return autoDeployService;
526 }
527
528 /**
529 *
530 * @return the AdminCommandsService
531 */
532 public AdminCommandsService getAdminCommandsService() {
533 return adminCommandsService;
534 }
535
536 public ClientFactory getClientFactory() {
537 return clientFactory;
538 }
539
540 public String getGeneratedRootDirPrefix() {
541 return generatedRootDirPrefix;
542 }
543
544 /**
545 * Sets the prefix used when auto-creating a rootDir property value
546 * which is useful for integration testing inside JUnit test cases
547 * letting each test case create its own empty servicemix install
548 *
549 * @param generatedRootDirPrefix the prefix used to auto-create the
550 * rootDir
551 * @see #setRootDir(String)
552 * @see #setGeneratedRootDirPrefix(String)
553 */
554 public void setGeneratedRootDirPrefix(String generatedRootDirPrefix) {
555 this.generatedRootDirPrefix = generatedRootDirPrefix;
556 }
557
558 public boolean isGenerateRootDir() {
559 return generateRootDir;
560 }
561
562 public long getForceShutdown() {
563 return forceShutdown;
564 }
565
566 /**
567 * Set the timeout (in ms) before a shutdown is forced by cancelling all pending exchanges.
568 * The default value is 0 -- no forced shutdown
569 *
570 * @param forceShutdown the timeout in ms
571 */
572 public void setForceShutdown(long forceShutdown) {
573 this.forceShutdown = forceShutdown;
574 }
575
576 /**
577 * Creates an auto-generated rootDir which is useful for integration testing
578 * in JUnit test cases allowing installations of deployments inside an empty
579 * installation of ServiceMix
580 *
581 * @param generateRootDir if true this will enable the auto-generation of the rootDir
582 * if the rootDir property is not configured
583 *
584 * @see #setRootDir(String)
585 * @see #setGeneratedRootDirPrefix(String)
586 */
587 public void setGenerateRootDir(boolean generateRootDir) {
588 this.generateRootDir = generateRootDir;
589 }
590
591 /**
592 * light weight initialization - default values for mbeanServer, TransactionManager etc are null
593 *
594 * @throws JBIException
595 */
596 public void init() throws JBIException {
597 if (containerInitialized.compareAndSet(false, true)) {
598 LOG.info("ServiceMix " + EnvironmentContext.getVersion() + " JBI Container (" + getName() + ") is starting");
599 LOG.info("For help or more information please see: http://servicemix.apache.org/");
600 addShutdownHook();
601 if (this.executorFactory == null) {
602 this.executorFactory = createExecutorFactory();
603 }
604 if (this.namingContext == null) {
605 try {
606 this.namingContext = new InitialContext();
607 } catch (NamingException e) {
608 // Log a warning, with exception only in debug
609 if (LOG.isDebugEnabled()) {
610 LOG.warn("Failed to set InitialContext", e);
611 } else {
612 LOG.warn("Failed to set InitialContext");
613 }
614 }
615 }
616 managementContext.init(this, getMBeanServer());
617 mbeanServer = this.managementContext.getMBeanServer(); // just in case ManagementContext creates it
618 environmentContext.init(this, getRootDir());
619 clientFactory.init(this);
620 if (services != null) {
621 for (int i = 0; i < services.length; i++) {
622 services[i].init(this);
623 }
624 }
625 registry.init(this);
626 broker.init(this);
627 installationService.init(this);
628 deploymentService.init(this);
629 autoDeployService.init(this);
630 adminCommandsService.init(this);
631
632 // register self with the ManagementContext
633 try {
634 managementContext.registerMBean(ManagementContext.getContainerObjectName(managementContext.getJmxDomainName(), getName()),
635 this, LifeCycleMBean.class);
636 } catch (JMException e) {
637 throw new JBIException(e);
638 }
639
640 // Initialize listeners after the whole container has been initialized
641 // so that they can register themselves as JMX mbeans for example
642 if (configuredListeners != null) {
643 for (int i = 0; i < configuredListeners.length; i++) {
644 EventListener listener = configuredListeners[i];
645 addListener(listener);
646 }
647 }
648 }
649 }
650
651 /**
652 * start processing
653 *
654 * @throws JBIException
655 */
656 public void start() throws JBIException {
657 checkInitialized();
658 if (started.compareAndSet(false, true)) {
659 managementContext.start();
660 environmentContext.start();
661 clientFactory.start();
662 if (services != null) {
663 for (int i = 0; i < services.length; i++) {
664 services[i].start();
665 }
666 }
667 broker.start();
668 registry.start();
669 installationService.start();
670 deploymentService.start();
671 autoDeployService.start();
672 adminCommandsService.start();
673 super.start();
674 LOG.info("ServiceMix JBI Container (" + getName() + ") started");
675 }
676 }
677
678 /**
679 * stop the container from processing
680 *
681 * @throws JBIException
682 */
683 public void stop() throws JBIException {
684 checkInitialized();
685 if (started.compareAndSet(true, false)) {
686 LOG.info("ServiceMix JBI Container (" + getName() + ") stopping");
687 adminCommandsService.stop();
688 autoDeployService.stop();
689 deploymentService.stop();
690 installationService.stop();
691 registry.stop();
692 broker.stop();
693 if (services != null) {
694 for (int i = services.length - 1; i >= 0; i--) {
695 services[i].stop();
696 }
697 }
698 clientFactory.stop();
699 environmentContext.stop();
700 managementContext.stop();
701 super.stop();
702 }
703 }
704
705 /**
706 * After a shutdown the container will require an init before a start ...
707 *
708 * @throws JBIException
709 */
710 public void shutDown() throws JBIException {
711 if (containerInitialized.compareAndSet(true, false)) {
712 LOG.info("Shutting down ServiceMix JBI Container (" + getName() + ") stopped");
713 removeShutdownHook();
714 adminCommandsService.shutDown();
715 autoDeployService.shutDown();
716 deploymentService.shutDown();
717 installationService.shutDown();
718 shutdownRegistry();
719 broker.shutDown();
720 shutdownServices();
721 clientFactory.shutDown();
722 environmentContext.shutDown();
723 // shutdown the management context last, because it will close the mbean server
724 super.shutDown();
725 managementContext.unregisterMBean(this);
726 managementContext.shutDown();
727 LOG.info("ServiceMix JBI Container (" + getName() + ") stopped");
728 }
729 }
730
731 private void shutdownServices() throws JBIException {
732 if (services != null) {
733 for (int i = services.length - 1; i >= 0; i--) {
734 services[i].shutDown();
735 }
736 }
737 }
738
739 private void shutdownRegistry() throws JBIException {
740 FutureTask<Boolean> shutdown = new FutureTask<Boolean>(new Callable<Boolean>() {
741 public Boolean call() throws Exception {
742 registry.shutDown();
743 return true;
744 };
745 });
746
747 //use daemon thread to run this shutdown task
748 //fix the container hang when shutdown container from the jmx console
749 Thread daemonShutDownThread = new Thread(shutdown);
750 daemonShutDownThread.setDaemon(true);
751 daemonShutDownThread.start();
752
753 try {
754 if (forceShutdown > 0) {
755 LOG.info("Waiting another " + forceShutdown + " ms for complete shutdown of the components and service assemblies");
756 shutdown.get(forceShutdown, TimeUnit.MILLISECONDS);
757 } else {
758 LOG.info("Waiting for complete shutdown of the components and service assemblies");
759 shutdown.get();
760 }
761 LOG.info("Components and service assemblies have been shut down");
762 } catch (Exception e) {
763 forceShutdown(e);
764 }
765 }
766
767 /**
768 * Force a container shutdown by canceling all pending exchanges
769 *
770 * @param e the exception that caused the forced container shutdown
771 */
772 protected void forceShutdown(Exception e) {
773 LOG.warn("Unable to shutdown components and service assemblies normally: " + e, e);
774 LOG.warn("Forcing shutdown by cancelling all pending exchanges");
775 registry.cancelPendingExchanges();
776 }
777
778 protected void addShutdownHook() {
779 if (useShutdownHook) {
780 shutdownHook = new Thread("ServiceMix ShutdownHook") {
781 public void run() {
782 containerShutdown();
783 }
784 };
785 Runtime.getRuntime().addShutdownHook(shutdownHook);
786 }
787 }
788
789 protected void removeShutdownHook() {
790 if (shutdownHook != null) {
791 try {
792 Runtime.getRuntime().removeShutdownHook(shutdownHook);
793 } catch (Exception e) {
794 LOG.debug("Caught exception, must be shutting down: " + e);
795 }
796 }
797 }
798
799 /**
800 * Causes a clean shutdown of the container when the VM is being shut down
801 */
802 protected void containerShutdown() {
803 try {
804 shutDown();
805 } catch (Throwable e) {
806 System.err.println("Failed to shut down: " + e);
807 }
808 }
809
810 /**
811 * @return theMBean server assocated with the JBI
812 */
813 public synchronized MBeanServer getMBeanServer() {
814 return mbeanServer;
815 }
816
817 /**
818 * Set the MBeanServer
819 *
820 * @param mbs
821 */
822 public synchronized void setMBeanServer(MBeanServer mbs) {
823 this.mbeanServer = mbs;
824 }
825
826 /**
827 * @return the naming context
828 */
829 public synchronized InitialContext getNamingContext() {
830 return namingContext;
831 }
832
833 /**
834 * Set the naming context
835 *
836 * @param ic
837 */
838 public synchronized void setNamingContext(InitialContext ic) {
839 this.namingContext = ic;
840 }
841
842 /**
843 * @return the TransactionManager for this implementation
844 */
845 public synchronized Object getTransactionManager() {
846 if (transactionManager == null && namingContext != null) {
847 try {
848 transactionManager = (TransactionManager) namingContext.lookup("java:appserver/TransactionManager");
849 } catch (NamingException e) {
850 LOG.debug("No transaction manager found from naming context: " + e.getMessage());
851 try {
852 transactionManager = (TransactionManager) namingContext.lookup("javax.transaction.TransactionManager");
853 } catch (NamingException e1) {
854 LOG.debug("No transaction manager found from naming context: " + e1.getMessage());
855 }
856 }
857 }
858 return transactionManager;
859 }
860
861 /**
862 * Set the transaction manager
863 *
864 * @param tm
865 */
866 public synchronized void setTransactionManager(Object tm) {
867 this.transactionManager = (TransactionManager) tm;
868 }
869
870 /**
871 * @return the root directory path
872 */
873 public synchronized String getRootDir() {
874 if (rootDir == null) {
875 if (isGenerateRootDir()) {
876 rootDir = createRootDir();
877 } else {
878 rootDir = "." + File.separator + "rootDir";
879 }
880 LOG.debug("Defaulting to rootDir: " + rootDir);
881 }
882 return this.rootDir;
883 }
884
885
886 /**
887 * Set the workspace root
888 *
889 * @param root
890 */
891 public synchronized void setRootDir(String root) {
892 this.rootDir = root;
893 }
894
895 /**
896 * Route an ExchangePacket to a destination
897 *
898 * @param exchange
899 * @throws MessagingException
900 */
901 public void sendExchange(MessageExchangeImpl exchange) throws MessagingException {
902 try {
903 broker.sendExchangePacket(exchange);
904 } catch (MessagingException e) {
905 throw e;
906 } catch (JBIException e) {
907 throw new MessagingException(e);
908 }
909 }
910
911 /**
912 * @param context
913 * @param externalEndpoint
914 * @throws JBIException
915 */
916 public void registerExternalEndpoint(ComponentNameSpace cns, ServiceEndpoint externalEndpoint) throws JBIException {
917 registry.registerExternalEndpoint(cns, externalEndpoint);
918 }
919
920 /**
921 * @param context
922 * @param externalEndpoint
923 * @throws JBIException
924 */
925 public void deregisterExternalEndpoint(ComponentNameSpace cns, ServiceEndpoint externalEndpoint) throws JBIException {
926 registry.deregisterExternalEndpoint(cns, externalEndpoint);
927 }
928
929 /**
930 * @param context
931 * @param epr
932 * @return matching endpoint or null
933 */
934 public ServiceEndpoint resolveEndpointReference(ComponentContextImpl context, DocumentFragment epr) {
935 return registry.resolveEndpointReference(epr);
936 }
937
938 /**
939 * @param context
940 * @param service
941 * @param endpointName
942 * @return the matching endpoint
943 */
944 public ServiceEndpoint getEndpoint(ComponentContextImpl context, QName service, String endpointName) {
945 return registry.getEndpoint(service, endpointName);
946 }
947
948 /**
949 * @param context
950 * @param interfaceName
951 * @return endpoints that match the interface name
952 */
953 public ServiceEndpoint[] getEndpoints(ComponentContextImpl context, QName interfaceName) {
954 return registry.getEndpointsForInterface(interfaceName);
955 }
956
957 /**
958 * @param context
959 * @param serviceName
960 * @return endpoints for a given service
961 */
962 public ServiceEndpoint[] getEndpointsForService(ComponentContextImpl context, QName serviceName) {
963 return registry.getEndpointsForService(serviceName);
964 }
965
966 /**
967 * @param context
968 * @param interfaceName
969 * @return endpoints matching the interface name
970 */
971 public ServiceEndpoint[] getExternalEndpoints(ComponentContextImpl context, QName interfaceName) {
972 return registry.getExternalEndpoints(interfaceName);
973 }
974
975 /**
976 * @param context
977 * @param serviceName
978 * @return external endpoints
979 */
980 public ServiceEndpoint[] getExternalEndpointsForService(ComponentContextImpl context, QName serviceName) {
981 return registry.getExternalEndpointsForService(serviceName);
982 }
983
984 /**
985 * @param suffix
986 * @param resourceBundleName
987 * @return the Logger
988 * @throws MissingResourceException
989 * @throws JBIException
990 */
991 public Logger getLogger(String suffix, String resourceBundleName) throws MissingResourceException, JBIException {
992 try {
993 return Logger.getLogger(suffix, resourceBundleName);
994 } catch (IllegalArgumentException e) {
995 throw new JBIException("A logger can not be created using resource bundle " + resourceBundleName);
996 }
997 }
998
999 /**
1000 * Used for Simple POJO's
1001 *
1002 * @param componentName - the unique component ID
1003 * @throws JBIException
1004 */
1005 public void deactivateComponent(String componentName) throws JBIException {
1006 ComponentMBeanImpl component = registry.getComponent(componentName);
1007 if (component != null) {
1008 component.doShutDown();
1009 component.unregisterMbeans(managementContext);
1010 registry.deregisterComponent(component);
1011 environmentContext.unreregister(component);
1012 component.dispose();
1013 LOG.info("Deactivating component " + componentName);
1014 } else {
1015 throw new JBIException("Could not find component " + componentName);
1016 }
1017 }
1018
1019 /**
1020 * Delete a Component
1021 *
1022 * @param id
1023 * @throws JBIException
1024 */
1025 public void deleteComponent(String id) throws JBIException {
1026 deactivateComponent(id);
1027 environmentContext.removeComponentRootDirectory(id);
1028 }
1029
1030 /**
1031 * Get the component associated with the given component ID
1032 *
1033 * @param componentName
1034 * @return the component
1035 */
1036 public ComponentMBeanImpl getComponent(String componentName) {
1037 return registry.getComponent(componentName);
1038 }
1039
1040 /**
1041 * @return all local ComponentConnectors
1042 */
1043 public Collection getLocalComponentConnectors() {
1044 return registry.getComponents();
1045 }
1046
1047 /**
1048 * Activates a new component
1049 *
1050 * @param activationSpec
1051 * @return Component
1052 * @throws JBIException
1053 */
1054 public Component activateComponent(ActivationSpec activationSpec) throws JBIException {
1055 if (activationSpec.getId() == null) {
1056 if (activationSpec.getComponentName() == null) {
1057 // lets generate one
1058 activationSpec.setId(createComponentID());
1059 } else {
1060 activationSpec.setId(activationSpec.getComponentName());
1061 }
1062 }
1063 String id = activationSpec.getId();
1064 if (id == null) {
1065 throw new IllegalArgumentException("A Registration must have an ID");
1066 }
1067 if (activationSpec.getEndpoint() == null && activationSpec.getService() != null) {
1068 // lets default to the ID
1069 activationSpec.setEndpoint(id);
1070 }
1071 if (activationSpec.getComponentName() == null) {
1072 activationSpec.setComponentName(id);
1073 }
1074 Object bean = activationSpec.getComponent();
1075 if (bean == null) {
1076 throw new IllegalArgumentException("A Registration must have a component associated with it");
1077 }
1078 if (bean instanceof Component) {
1079 Component component = (Component) bean;
1080 if (component instanceof ComponentSupport) {
1081 defaultComponentServiceAndEndpoint((ComponentSupport) component, activationSpec);
1082 }
1083 activateComponent(component, activationSpec);
1084 return component;
1085 } else if (bean instanceof ComponentLifeCycle) {
1086 // lets support just plain lifecycle pojos
1087 ComponentLifeCycle lifeCycle = (ComponentLifeCycle) bean;
1088 if (bean instanceof PojoSupport) {
1089 defaultComponentServiceAndEndpoint((PojoSupport) bean, activationSpec);
1090 }
1091 Component adaptor = createComponentAdaptor(lifeCycle, activationSpec);
1092 activateComponent(adaptor, activationSpec);
1093 return adaptor;
1094 } else if (bean instanceof MessageExchangeListener) {
1095 // lets support just plain listener pojos
1096 MessageExchangeListener listener = (MessageExchangeListener) bean;
1097 Component adaptor = createComponentAdaptor(listener, activationSpec);
1098 activateComponent(adaptor, activationSpec);
1099 return adaptor;
1100 } else {
1101 throw new IllegalArgumentException("Component name: " + id
1102 + " is bound to an object which is not a JBI component, it is of type: " + bean.getClass().getName());
1103 }
1104 }
1105
1106 /**
1107 * Activate a POJO Component
1108 *
1109 * @param component
1110 * @param componentName
1111 * @return the ObjectName of the MBean for the Component
1112 * @throws JBIException
1113 */
1114 public ObjectName activateComponent(Component component, String componentName) throws JBIException {
1115 ActivationSpec activationSpec = new ActivationSpec();
1116 ComponentNameSpace cns = new ComponentNameSpace(getName(), componentName);
1117 activationSpec.setComponent(component);
1118 activationSpec.setComponentName(cns.getName());
1119 return activateComponent(component, activationSpec);
1120 }
1121
1122 /**
1123 * Activate A POJO Component
1124 *
1125 * @param component
1126 * @param activationSpec
1127 * @return the ObjectName of the MBean for the Component
1128 * @throws JBIException
1129 */
1130 public ObjectName activateComponent(Component component, ActivationSpec activationSpec) throws JBIException {
1131 return activateComponent(component, "POJO Component", activationSpec, true, false, false, null);
1132 }
1133
1134 /**
1135 * Called by the Installer MBean
1136 *
1137 * @param installDir
1138 * @param component
1139 * @param description
1140 * @param context
1141 * @param binding
1142 * @param service
1143 * @return the ObjectName of the Component's MBean
1144 * @throws JBIException
1145 */
1146 public ObjectName activateComponent(File installDir, Component component, String description, ComponentContextImpl context,
1147 boolean binding, boolean service, String[] sharedLibraries) throws JBIException {
1148 ComponentNameSpace cns = context.getComponentNameSpace();
1149 ActivationSpec activationSpec = new ActivationSpec();
1150 activationSpec.setComponent(component);
1151 activationSpec.setComponentName(cns.getName());
1152 return activateComponent(installDir, component, description, context, activationSpec, false, binding, service, sharedLibraries);
1153 }
1154
1155 /**
1156 * @param component
1157 * @param description
1158 * @param activationSpec
1159 * @param pojo
1160 * @param binding
1161 * @param service
1162 * @return the ObjectName of the Component's MBean
1163 * @throws JBIException
1164 */
1165 public ObjectName activateComponent(Component component, String description, ActivationSpec activationSpec, boolean pojo,
1166 boolean binding, boolean service, String[] sharedLibraries) throws JBIException {
1167 ComponentNameSpace cns = new ComponentNameSpace(getName(), activationSpec.getComponentName());
1168 if (registry.getComponent(cns) != null) {
1169 throw new JBIException("A component is already registered for " + cns);
1170 }
1171 ComponentContextImpl context = new ComponentContextImpl(this, cns);
1172 return activateComponent(new File("."), component, description, context, activationSpec, pojo, binding, service, sharedLibraries);
1173 }
1174
1175 /**
1176 * @param installationDir
1177 * @param component
1178 * @param description
1179 * @param context
1180 * @param activationSpec
1181 * @param pojo
1182 * @param binding
1183 * @param service
1184 * @return the ObjectName of the Component's MBean
1185 * @throws JBIException
1186 */
1187 public ObjectName activateComponent(File installationDir, Component component,
1188 String description, ComponentContextImpl context,
1189 ActivationSpec activationSpec, boolean pojo,
1190 boolean binding, boolean service, String[] sharedLibraries) throws JBIException {
1191 ObjectName result = null;
1192 ComponentNameSpace cns = new ComponentNameSpace(getName(), activationSpec.getComponentName());
1193 if (LOG.isDebugEnabled()) {
1194 LOG.info("Activating component for: " + cns + " with service: " + activationSpec.getService() + " component: " + component);
1195 }
1196 ComponentMBeanImpl lcc = registry.registerComponent(cns, description, component, binding, service, sharedLibraries);
1197 if (lcc != null) {
1198 lcc.setPojo(pojo);
1199 ComponentEnvironment env = environmentContext.registerComponent(context.getEnvironment(), lcc);
1200 if (env.getInstallRoot() == null) {
1201 env.setInstallRoot(installationDir);
1202 }
1203 context.activate(component, env, activationSpec);
1204 lcc.setContext(context);
1205 lcc.setActivationSpec(activationSpec);
1206
1207 if (lcc.isPojo()) {
1208 //non-pojo's are either started by the auto deployer
1209 //or manually
1210 lcc.init();
1211 } else {
1212 lcc.doShutDown();
1213 }
1214 result = lcc.registerMBeans(managementContext);
1215 // Start the component after mbeans have been registered
1216 // This can be usefull if listeners use them
1217 if (lcc.isPojo() && started.get()) {
1218 lcc.start();
1219 }
1220 }
1221 return result;
1222 }
1223
1224 /**
1225 * Allow the service and endpoint name to be configured from the registration, to reduce the amount of XML which is
1226 * required to configure a ServiceMix component
1227 *
1228 * @param component
1229 * @param activationSpec
1230 */
1231 protected void defaultComponentServiceAndEndpoint(PojoSupport component, ActivationSpec activationSpec) {
1232 if (activationSpec.getService() != null) {
1233 component.setService(activationSpec.getService());
1234 }
1235 if (activationSpec.getEndpoint() != null) {
1236 component.setEndpoint(activationSpec.getEndpoint());
1237 }
1238 }
1239
1240 protected ExecutorFactory createExecutorFactory() throws JBIException {
1241 return new ExecutorFactoryImpl();
1242 }
1243
1244 /**
1245 * Factory method to create a new component adaptor from the given lifecycle
1246 *
1247 * @param lifeCycle
1248 * @param activationSpec
1249 * @return Component
1250 */
1251 protected Component createComponentAdaptor(ComponentLifeCycle lifeCycle, ActivationSpec activationSpec) {
1252 ComponentAdaptor answer = null;
1253 if (lifeCycle instanceof MessageExchangeListener) {
1254 answer = new ComponentAdaptorMEListener(lifeCycle, activationSpec.getService(), activationSpec.getEndpoint(),
1255 (MessageExchangeListener) lifeCycle);
1256 } else {
1257 answer = new ComponentAdaptor(lifeCycle, activationSpec.getService(), activationSpec.getEndpoint());
1258 }
1259 answer.setServiceManager(serviceManager);
1260 return answer;
1261 }
1262
1263 protected Component createComponentAdaptor(MessageExchangeListener listener, ActivationSpec activationSpec) {
1264 ComponentLifeCycle lifecCycle = new PojoLifecycleAdaptor(listener, activationSpec.getService(), activationSpec.getEndpoint());
1265 return new ComponentAdaptorMEListener(lifecCycle, listener);
1266 }
1267
1268 /**
1269 * Factory method to create a new component ID if none is specified
1270 *
1271 * @return uniqueId
1272 */
1273 protected String createComponentID() {
1274 return idGenerator.generateId();
1275 }
1276
1277 protected void checkInitialized() throws JBIException {
1278 if (!containerInitialized.get()) {
1279 throw new JBIException("The Container is not initialized - please call init(...)");
1280 }
1281 }
1282
1283 /**
1284 * Retrieve the value for automatic transaction enlistment.
1285 * @return
1286 */
1287 public boolean isAutoEnlistInTransaction() {
1288 return autoEnlistInTransaction;
1289 }
1290
1291 /**
1292 * Set the new value for automatic transaction enlistment.
1293 * When this parameter is set to <code>true</code> and a transaction
1294 * is running when sending / receiving an exchange, this operation will
1295 * automatically be done in the current transaction.
1296 *
1297 * @param autoEnlistInTransaction
1298 */
1299 public void setAutoEnlistInTransaction(boolean autoEnlistInTransaction) {
1300 this.autoEnlistInTransaction = autoEnlistInTransaction;
1301 }
1302
1303 public boolean isPersistent() {
1304 return persistent;
1305 }
1306
1307 /**
1308 * Set the new default value for exchange persistence.
1309 * This value will be the default if none is configured on
1310 * the activation spec of the component or on the message.
1311 *
1312 * @param persistent
1313 */
1314 public void setPersistent(boolean persistent) {
1315 this.persistent = persistent;
1316 }
1317
1318 public void addListener(EventListener listener) {
1319 LOG.debug("Adding listener: " + listener.getClass());
1320 if (listener instanceof ContainerAware) {
1321 ContainerAware containerAware = (ContainerAware) listener;
1322 containerAware.setContainer(this);
1323 }
1324 if (listener instanceof ExchangeListener) {
1325 listeners.add(ExchangeListener.class, (ExchangeListener) listener);
1326 }
1327 if (listener instanceof ComponentListener) {
1328 listeners.add(ComponentListener.class, (ComponentListener) listener);
1329 }
1330 if (listener instanceof ServiceAssemblyListener) {
1331 listeners.add(ServiceAssemblyListener.class, (ServiceAssemblyListener) listener);
1332 }
1333 if (listener instanceof ServiceUnitListener) {
1334 listeners.add(ServiceUnitListener.class, (ServiceUnitListener) listener);
1335 }
1336 if (listener instanceof EndpointListener) {
1337 listeners.add(EndpointListener.class, (EndpointListener) listener);
1338 }
1339 if (listener instanceof DeploymentListener) {
1340 listeners.add(DeploymentListener.class, (DeploymentListener) listener);
1341 }
1342 }
1343
1344 public void removeListener(EventListener listener) {
1345 LOG.debug("Removing listener: " + listener.getClass());
1346 if (listener instanceof ExchangeListener) {
1347 listeners.remove(ExchangeListener.class, (ExchangeListener) listener);
1348 }
1349 if (listener instanceof ComponentListener) {
1350 listeners.remove(ComponentListener.class, (ComponentListener) listener);
1351 }
1352 if (listener instanceof ServiceAssemblyListener) {
1353 listeners.remove(ServiceAssemblyListener.class, (ServiceAssemblyListener) listener);
1354 }
1355 if (listener instanceof ServiceUnitListener) {
1356 listeners.remove(ServiceUnitListener.class, (ServiceUnitListener) listener);
1357 }
1358 if (listener instanceof EndpointListener) {
1359 listeners.remove(EndpointListener.class, (EndpointListener) listener);
1360 }
1361 if (listener instanceof DeploymentListener) {
1362 listeners.remove(DeploymentListener.class, (DeploymentListener) listener);
1363 }
1364 }
1365
1366 public Object[] getListeners(Class lc) {
1367 return listeners.getListeners(lc);
1368 }
1369
1370 public void setListeners(EventListener[] listeners) {
1371 configuredListeners = listeners;
1372 }
1373
1374 public void resendExchange(MessageExchange exchange) throws JBIException {
1375 if (!(exchange instanceof MessageExchangeImpl)) {
1376 throw new IllegalArgumentException("exchange should be a MessageExchangeImpl");
1377 }
1378 MessageExchangeImpl me = (MessageExchangeImpl) exchange;
1379 me.getPacket().setExchangeId(new IdGenerator().generateId());
1380 me.getPacket().setOut(null);
1381 me.getPacket().setFault(null);
1382 me.getPacket().setError(null);
1383 me.getPacket().setStatus(ExchangeStatus.ACTIVE);
1384 me.getPacket().setProperty(JbiConstants.DATESTAMP_PROPERTY_NAME, Calendar.getInstance());
1385 ExchangeListener[] l = (ExchangeListener[]) listeners.getListeners(ExchangeListener.class);
1386 ExchangeEvent event = new ExchangeEvent(me, ExchangeEvent.EXCHANGE_SENT);
1387 for (int i = 0; i < l.length; i++) {
1388 try {
1389 l[i].exchangeSent(event);
1390 } catch (Exception e) {
1391 LOG.warn("Error calling listener: " + e.getMessage(), e);
1392 }
1393 }
1394 me.handleSend(false);
1395 sendExchange(me.getMirror());
1396 }
1397
1398 public boolean isEmbedded() {
1399 return embedded;
1400 }
1401
1402 public void setEmbedded(boolean embedded) {
1403 this.embedded = embedded;
1404 }
1405
1406 public void setRmiPort(int portNum) {
1407 getManagementContext().setNamingPort(portNum);
1408 }
1409
1410 public int getRmiPort() {
1411 return getManagementContext().getNamingPort();
1412 }
1413
1414 /**
1415 * @return Returns the notifyStatistics.
1416 */
1417 public boolean isNotifyStatistics() {
1418 return notifyStatistics;
1419 }
1420
1421 /**
1422 * @param notifyStatistics The notifyStatistics to set.
1423 */
1424 public void setNotifyStatistics(boolean notifyStatistics) {
1425 this.notifyStatistics = notifyStatistics;
1426 }
1427
1428 /**
1429 * @return the executorFactory
1430 */
1431 public ExecutorFactory getExecutorFactory() {
1432 return executorFactory;
1433 }
1434
1435 /**
1436 * @param executorFactory the executorFactory to set
1437 */
1438 public void setExecutorFactory(ExecutorFactory executorFactory) {
1439 this.executorFactory = executorFactory;
1440 }
1441
1442
1443 /**
1444 * Creates a new rootDir
1445 */
1446 protected String createRootDir() {
1447 String prefix = getGeneratedRootDirPrefix();
1448 for (int i = 1; true; i++) {
1449 File file = new File(prefix + i);
1450 if (!file.exists()) {
1451 file.mkdirs();
1452 return file.getAbsolutePath();
1453 }
1454 }
1455 }
1456 }