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.MessageExchangeListener;
055 import org.apache.servicemix.components.util.ComponentAdaptor;
056 import org.apache.servicemix.components.util.ComponentAdaptorMEListener;
057 import org.apache.servicemix.components.util.ComponentSupport;
058 import org.apache.servicemix.components.util.PojoLifecycleAdaptor;
059 import org.apache.servicemix.components.util.PojoSupport;
060 import org.apache.servicemix.executors.ExecutorFactory;
061 import org.apache.servicemix.executors.impl.ExecutorFactoryImpl;
062 import org.apache.servicemix.id.IdGenerator;
063 import org.apache.servicemix.jbi.api.Container;
064 import org.apache.servicemix.jbi.event.ComponentListener;
065 import org.apache.servicemix.jbi.event.ContainerAware;
066 import org.apache.servicemix.jbi.event.DeploymentListener;
067 import org.apache.servicemix.jbi.event.EndpointListener;
068 import org.apache.servicemix.jbi.event.ExchangeEvent;
069 import org.apache.servicemix.jbi.event.ExchangeListener;
070 import org.apache.servicemix.jbi.event.ServiceAssemblyListener;
071 import org.apache.servicemix.jbi.event.ServiceUnitListener;
072 import org.apache.servicemix.jbi.framework.AdminCommandsService;
073 import org.apache.servicemix.jbi.framework.AutoDeploymentService;
074 import org.apache.servicemix.jbi.framework.ClientFactory;
075 import org.apache.servicemix.jbi.framework.ComponentContextImpl;
076 import org.apache.servicemix.jbi.framework.ComponentMBeanImpl;
077 import org.apache.servicemix.jbi.framework.ComponentNameSpace;
078 import org.apache.servicemix.jbi.framework.DeploymentService;
079 import org.apache.servicemix.jbi.framework.InstallationService;
080 import org.apache.servicemix.jbi.framework.Registry;
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: 707528 $
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 LOG.warn("Unable to shutdown components and service assemblies normally: " + e, e);
764 LOG.warn("Forcing shutdown by cancelling all pending exchanges");
765 registry.cancelPendingExchanges();
766 }
767 }
768
769 protected void addShutdownHook() {
770 if (useShutdownHook) {
771 shutdownHook = new Thread("ServiceMix ShutdownHook") {
772 public void run() {
773 containerShutdown();
774 }
775 };
776 Runtime.getRuntime().addShutdownHook(shutdownHook);
777 }
778 }
779
780 protected void removeShutdownHook() {
781 if (shutdownHook != null) {
782 try {
783 Runtime.getRuntime().removeShutdownHook(shutdownHook);
784 } catch (Exception e) {
785 LOG.debug("Caught exception, must be shutting down: " + e);
786 }
787 }
788 }
789
790 /**
791 * Causes a clean shutdown of the container when the VM is being shut down
792 */
793 protected void containerShutdown() {
794 try {
795 shutDown();
796 } catch (Throwable e) {
797 System.err.println("Failed to shut down: " + e);
798 }
799 }
800
801 /**
802 * @return theMBean server assocated with the JBI
803 */
804 public synchronized MBeanServer getMBeanServer() {
805 return mbeanServer;
806 }
807
808 /**
809 * Set the MBeanServer
810 *
811 * @param mbs
812 */
813 public synchronized void setMBeanServer(MBeanServer mbs) {
814 this.mbeanServer = mbs;
815 }
816
817 /**
818 * @return the naming context
819 */
820 public synchronized InitialContext getNamingContext() {
821 return namingContext;
822 }
823
824 /**
825 * Set the naming context
826 *
827 * @param ic
828 */
829 public synchronized void setNamingContext(InitialContext ic) {
830 this.namingContext = ic;
831 }
832
833 /**
834 * @return the TransactionManager for this implementation
835 */
836 public synchronized Object getTransactionManager() {
837 if (transactionManager == null && namingContext != null) {
838 try {
839 transactionManager = (TransactionManager) namingContext.lookup("java:appserver/TransactionManager");
840 } catch (NamingException e) {
841 LOG.debug("No transaction manager found from naming context: " + e.getMessage());
842 try {
843 transactionManager = (TransactionManager) namingContext.lookup("javax.transaction.TransactionManager");
844 } catch (NamingException e1) {
845 LOG.debug("No transaction manager found from naming context: " + e1.getMessage());
846 }
847 }
848 }
849 return transactionManager;
850 }
851
852 /**
853 * Set the transaction manager
854 *
855 * @param tm
856 */
857 public synchronized void setTransactionManager(Object tm) {
858 this.transactionManager = (TransactionManager) tm;
859 }
860
861 /**
862 * @return the root directory path
863 */
864 public synchronized String getRootDir() {
865 if (rootDir == null) {
866 if (isGenerateRootDir()) {
867 rootDir = createRootDir();
868 } else {
869 rootDir = "." + File.separator + "rootDir";
870 }
871 LOG.debug("Defaulting to rootDir: " + rootDir);
872 }
873 return this.rootDir;
874 }
875
876
877 /**
878 * Set the workspace root
879 *
880 * @param root
881 */
882 public synchronized void setRootDir(String root) {
883 this.rootDir = root;
884 }
885
886 /**
887 * Route an ExchangePacket to a destination
888 *
889 * @param exchange
890 * @throws MessagingException
891 */
892 public void sendExchange(MessageExchangeImpl exchange) throws MessagingException {
893 try {
894 broker.sendExchangePacket(exchange);
895 } catch (MessagingException e) {
896 throw e;
897 } catch (JBIException e) {
898 throw new MessagingException(e);
899 }
900 }
901
902 /**
903 * @param context
904 * @param externalEndpoint
905 * @throws JBIException
906 */
907 public void registerExternalEndpoint(ComponentNameSpace cns, ServiceEndpoint externalEndpoint) throws JBIException {
908 registry.registerExternalEndpoint(cns, externalEndpoint);
909 }
910
911 /**
912 * @param context
913 * @param externalEndpoint
914 * @throws JBIException
915 */
916 public void deregisterExternalEndpoint(ComponentNameSpace cns, ServiceEndpoint externalEndpoint) throws JBIException {
917 registry.deregisterExternalEndpoint(cns, externalEndpoint);
918 }
919
920 /**
921 * @param context
922 * @param epr
923 * @return matching endpoint or null
924 */
925 public ServiceEndpoint resolveEndpointReference(ComponentContextImpl context, DocumentFragment epr) {
926 return registry.resolveEndpointReference(epr);
927 }
928
929 /**
930 * @param context
931 * @param service
932 * @param endpointName
933 * @return the matching endpoint
934 */
935 public ServiceEndpoint getEndpoint(ComponentContextImpl context, QName service, String endpointName) {
936 return registry.getEndpoint(service, endpointName);
937 }
938
939 /**
940 * @param context
941 * @param interfaceName
942 * @return endpoints that match the interface name
943 */
944 public ServiceEndpoint[] getEndpoints(ComponentContextImpl context, QName interfaceName) {
945 return registry.getEndpointsForInterface(interfaceName);
946 }
947
948 /**
949 * @param context
950 * @param serviceName
951 * @return endpoints for a given service
952 */
953 public ServiceEndpoint[] getEndpointsForService(ComponentContextImpl context, QName serviceName) {
954 return registry.getEndpointsForService(serviceName);
955 }
956
957 /**
958 * @param context
959 * @param interfaceName
960 * @return endpoints matching the interface name
961 */
962 public ServiceEndpoint[] getExternalEndpoints(ComponentContextImpl context, QName interfaceName) {
963 return registry.getExternalEndpoints(interfaceName);
964 }
965
966 /**
967 * @param context
968 * @param serviceName
969 * @return external endpoints
970 */
971 public ServiceEndpoint[] getExternalEndpointsForService(ComponentContextImpl context, QName serviceName) {
972 return registry.getExternalEndpointsForService(serviceName);
973 }
974
975 /**
976 * @param suffix
977 * @param resourceBundleName
978 * @return the Logger
979 * @throws MissingResourceException
980 * @throws JBIException
981 */
982 public Logger getLogger(String suffix, String resourceBundleName) throws MissingResourceException, JBIException {
983 try {
984 return Logger.getLogger(suffix, resourceBundleName);
985 } catch (IllegalArgumentException e) {
986 throw new JBIException("A logger can not be created using resource bundle " + resourceBundleName);
987 }
988 }
989
990 /**
991 * Used for Simple POJO's
992 *
993 * @param componentName - the unique component ID
994 * @throws JBIException
995 */
996 public void deactivateComponent(String componentName) throws JBIException {
997 ComponentMBeanImpl component = registry.getComponent(componentName);
998 if (component != null) {
999 component.doShutDown();
1000 component.unregisterMbeans(managementContext);
1001 registry.deregisterComponent(component);
1002 environmentContext.unreregister(component);
1003 component.dispose();
1004 LOG.info("Deactivating component " + componentName);
1005 } else {
1006 throw new JBIException("Could not find component " + componentName);
1007 }
1008 }
1009
1010 /**
1011 * Delete a Component
1012 *
1013 * @param id
1014 * @throws JBIException
1015 */
1016 public void deleteComponent(String id) throws JBIException {
1017 deactivateComponent(id);
1018 environmentContext.removeComponentRootDirectory(id);
1019 }
1020
1021 /**
1022 * Get the component associated with the given component ID
1023 *
1024 * @param componentName
1025 * @return the component
1026 */
1027 public ComponentMBeanImpl getComponent(String componentName) {
1028 return registry.getComponent(componentName);
1029 }
1030
1031 /**
1032 * @return all local ComponentConnectors
1033 */
1034 public Collection getLocalComponentConnectors() {
1035 return registry.getComponents();
1036 }
1037
1038 /**
1039 * Activates a new component
1040 *
1041 * @param activationSpec
1042 * @return Component
1043 * @throws JBIException
1044 */
1045 public Component activateComponent(ActivationSpec activationSpec) throws JBIException {
1046 if (activationSpec.getId() == null) {
1047 if (activationSpec.getComponentName() == null) {
1048 // lets generate one
1049 activationSpec.setId(createComponentID());
1050 } else {
1051 activationSpec.setId(activationSpec.getComponentName());
1052 }
1053 }
1054 String id = activationSpec.getId();
1055 if (id == null) {
1056 throw new IllegalArgumentException("A Registration must have an ID");
1057 }
1058 if (activationSpec.getEndpoint() == null && activationSpec.getService() != null) {
1059 // lets default to the ID
1060 activationSpec.setEndpoint(id);
1061 }
1062 if (activationSpec.getComponentName() == null) {
1063 activationSpec.setComponentName(id);
1064 }
1065 Object bean = activationSpec.getComponent();
1066 if (bean == null) {
1067 throw new IllegalArgumentException("A Registration must have a component associated with it");
1068 }
1069 if (bean instanceof Component) {
1070 Component component = (Component) bean;
1071 if (component instanceof ComponentSupport) {
1072 defaultComponentServiceAndEndpoint((ComponentSupport) component, activationSpec);
1073 }
1074 activateComponent(component, activationSpec);
1075 return component;
1076 } else if (bean instanceof ComponentLifeCycle) {
1077 // lets support just plain lifecycle pojos
1078 ComponentLifeCycle lifeCycle = (ComponentLifeCycle) bean;
1079 if (bean instanceof PojoSupport) {
1080 defaultComponentServiceAndEndpoint((PojoSupport) bean, activationSpec);
1081 }
1082 Component adaptor = createComponentAdaptor(lifeCycle, activationSpec);
1083 activateComponent(adaptor, activationSpec);
1084 return adaptor;
1085 } else if (bean instanceof MessageExchangeListener) {
1086 // lets support just plain listener pojos
1087 MessageExchangeListener listener = (MessageExchangeListener) bean;
1088 Component adaptor = createComponentAdaptor(listener, activationSpec);
1089 activateComponent(adaptor, activationSpec);
1090 return adaptor;
1091 } else {
1092 throw new IllegalArgumentException("Component name: " + id
1093 + " is bound to an object which is not a JBI component, it is of type: " + bean.getClass().getName());
1094 }
1095 }
1096
1097 /**
1098 * Activate a POJO Component
1099 *
1100 * @param component
1101 * @param componentName
1102 * @return the ObjectName of the MBean for the Component
1103 * @throws JBIException
1104 */
1105 public ObjectName activateComponent(Component component, String componentName) throws JBIException {
1106 ActivationSpec activationSpec = new ActivationSpec();
1107 ComponentNameSpace cns = new ComponentNameSpace(getName(), componentName);
1108 activationSpec.setComponent(component);
1109 activationSpec.setComponentName(cns.getName());
1110 return activateComponent(component, activationSpec);
1111 }
1112
1113 /**
1114 * Activate A POJO Component
1115 *
1116 * @param component
1117 * @param activationSpec
1118 * @return the ObjectName of the MBean for the Component
1119 * @throws JBIException
1120 */
1121 public ObjectName activateComponent(Component component, ActivationSpec activationSpec) throws JBIException {
1122 return activateComponent(component, "POJO Component", activationSpec, true, false, false, null);
1123 }
1124
1125 /**
1126 * Called by the Installer MBean
1127 *
1128 * @param installDir
1129 * @param component
1130 * @param description
1131 * @param context
1132 * @param binding
1133 * @param service
1134 * @return the ObjectName of the Component's MBean
1135 * @throws JBIException
1136 */
1137 public ObjectName activateComponent(File installDir, Component component, String description, ComponentContextImpl context,
1138 boolean binding, boolean service, String[] sharedLibraries) throws JBIException {
1139 ComponentNameSpace cns = context.getComponentNameSpace();
1140 ActivationSpec activationSpec = new ActivationSpec();
1141 activationSpec.setComponent(component);
1142 activationSpec.setComponentName(cns.getName());
1143 return activateComponent(installDir, component, description, context, activationSpec, false, binding, service, sharedLibraries);
1144 }
1145
1146 /**
1147 * @param component
1148 * @param description
1149 * @param activationSpec
1150 * @param pojo
1151 * @param binding
1152 * @param service
1153 * @return the ObjectName of the Component's MBean
1154 * @throws JBIException
1155 */
1156 public ObjectName activateComponent(Component component, String description, ActivationSpec activationSpec, boolean pojo,
1157 boolean binding, boolean service, String[] sharedLibraries) throws JBIException {
1158 ComponentNameSpace cns = new ComponentNameSpace(getName(), activationSpec.getComponentName());
1159 if (registry.getComponent(cns) != null) {
1160 throw new JBIException("A component is already registered for " + cns);
1161 }
1162 ComponentContextImpl context = new ComponentContextImpl(this, cns);
1163 return activateComponent(new File("."), component, description, context, activationSpec, pojo, binding, service, sharedLibraries);
1164 }
1165
1166 /**
1167 * @param installationDir
1168 * @param component
1169 * @param description
1170 * @param context
1171 * @param activationSpec
1172 * @param pojo
1173 * @param binding
1174 * @param service
1175 * @return the ObjectName of the Component's MBean
1176 * @throws JBIException
1177 */
1178 public ObjectName activateComponent(File installationDir, Component component,
1179 String description, ComponentContextImpl context,
1180 ActivationSpec activationSpec, boolean pojo,
1181 boolean binding, boolean service, String[] sharedLibraries) throws JBIException {
1182 ObjectName result = null;
1183 ComponentNameSpace cns = new ComponentNameSpace(getName(), activationSpec.getComponentName());
1184 if (LOG.isDebugEnabled()) {
1185 LOG.info("Activating component for: " + cns + " with service: " + activationSpec.getService() + " component: " + component);
1186 }
1187 ComponentMBeanImpl lcc = registry.registerComponent(cns, description, component, binding, service, sharedLibraries);
1188 if (lcc != null) {
1189 lcc.setPojo(pojo);
1190 ComponentEnvironment env = environmentContext.registerComponent(context.getEnvironment(), lcc);
1191 if (env.getInstallRoot() == null) {
1192 env.setInstallRoot(installationDir);
1193 }
1194 context.activate(component, env, activationSpec);
1195 lcc.setContext(context);
1196 lcc.setActivationSpec(activationSpec);
1197
1198 if (lcc.isPojo()) {
1199 //non-pojo's are either started by the auto deployer
1200 //or manually
1201 lcc.init();
1202 } else {
1203 lcc.doShutDown();
1204 }
1205 result = lcc.registerMBeans(managementContext);
1206 // Start the component after mbeans have been registered
1207 // This can be usefull if listeners use them
1208 if (lcc.isPojo() && started.get()) {
1209 lcc.start();
1210 }
1211 }
1212 return result;
1213 }
1214
1215 /**
1216 * Allow the service and endpoint name to be configured from the registration, to reduce the amount of XML which is
1217 * required to configure a ServiceMix component
1218 *
1219 * @param component
1220 * @param activationSpec
1221 */
1222 protected void defaultComponentServiceAndEndpoint(PojoSupport component, ActivationSpec activationSpec) {
1223 if (activationSpec.getService() != null) {
1224 component.setService(activationSpec.getService());
1225 }
1226 if (activationSpec.getEndpoint() != null) {
1227 component.setEndpoint(activationSpec.getEndpoint());
1228 }
1229 }
1230
1231 protected ExecutorFactory createExecutorFactory() throws JBIException {
1232 return new ExecutorFactoryImpl();
1233 }
1234
1235 /**
1236 * Factory method to create a new component adaptor from the given lifecycle
1237 *
1238 * @param lifeCycle
1239 * @param activationSpec
1240 * @return Component
1241 */
1242 protected Component createComponentAdaptor(ComponentLifeCycle lifeCycle, ActivationSpec activationSpec) {
1243 ComponentAdaptor answer = null;
1244 if (lifeCycle instanceof MessageExchangeListener) {
1245 answer = new ComponentAdaptorMEListener(lifeCycle, activationSpec.getService(), activationSpec.getEndpoint(),
1246 (MessageExchangeListener) lifeCycle);
1247 } else {
1248 answer = new ComponentAdaptor(lifeCycle, activationSpec.getService(), activationSpec.getEndpoint());
1249 }
1250 answer.setServiceManager(serviceManager);
1251 return answer;
1252 }
1253
1254 protected Component createComponentAdaptor(MessageExchangeListener listener, ActivationSpec activationSpec) {
1255 ComponentLifeCycle lifecCycle = new PojoLifecycleAdaptor(listener, activationSpec.getService(), activationSpec.getEndpoint());
1256 return new ComponentAdaptorMEListener(lifecCycle, listener);
1257 }
1258
1259 /**
1260 * Factory method to create a new component ID if none is specified
1261 *
1262 * @return uniqueId
1263 */
1264 protected String createComponentID() {
1265 return idGenerator.generateId();
1266 }
1267
1268 protected void checkInitialized() throws JBIException {
1269 if (!containerInitialized.get()) {
1270 throw new JBIException("The Container is not initialized - please call init(...)");
1271 }
1272 }
1273
1274 /**
1275 * Retrieve the value for automatic transaction enlistment.
1276 * @return
1277 */
1278 public boolean isAutoEnlistInTransaction() {
1279 return autoEnlistInTransaction;
1280 }
1281
1282 /**
1283 * Set the new value for automatic transaction enlistment.
1284 * When this parameter is set to <code>true</code> and a transaction
1285 * is running when sending / receiving an exchange, this operation will
1286 * automatically be done in the current transaction.
1287 *
1288 * @param autoEnlistInTransaction
1289 */
1290 public void setAutoEnlistInTransaction(boolean autoEnlistInTransaction) {
1291 this.autoEnlistInTransaction = autoEnlistInTransaction;
1292 }
1293
1294 public boolean isPersistent() {
1295 return persistent;
1296 }
1297
1298 /**
1299 * Set the new default value for exchange persistence.
1300 * This value will be the default if none is configured on
1301 * the activation spec of the component or on the message.
1302 *
1303 * @param persistent
1304 */
1305 public void setPersistent(boolean persistent) {
1306 this.persistent = persistent;
1307 }
1308
1309 public void addListener(EventListener listener) {
1310 LOG.debug("Adding listener: " + listener.getClass());
1311 if (listener instanceof ContainerAware) {
1312 ContainerAware containerAware = (ContainerAware) listener;
1313 containerAware.setContainer(this);
1314 }
1315 if (listener instanceof ExchangeListener) {
1316 listeners.add(ExchangeListener.class, (ExchangeListener) listener);
1317 }
1318 if (listener instanceof ComponentListener) {
1319 listeners.add(ComponentListener.class, (ComponentListener) listener);
1320 }
1321 if (listener instanceof ServiceAssemblyListener) {
1322 listeners.add(ServiceAssemblyListener.class, (ServiceAssemblyListener) listener);
1323 }
1324 if (listener instanceof ServiceUnitListener) {
1325 listeners.add(ServiceUnitListener.class, (ServiceUnitListener) listener);
1326 }
1327 if (listener instanceof EndpointListener) {
1328 listeners.add(EndpointListener.class, (EndpointListener) listener);
1329 }
1330 if (listener instanceof DeploymentListener) {
1331 listeners.add(DeploymentListener.class, (DeploymentListener) listener);
1332 }
1333 }
1334
1335 public void removeListener(EventListener listener) {
1336 LOG.debug("Removing listener: " + listener.getClass());
1337 if (listener instanceof ExchangeListener) {
1338 listeners.remove(ExchangeListener.class, (ExchangeListener) listener);
1339 }
1340 if (listener instanceof ComponentListener) {
1341 listeners.remove(ComponentListener.class, (ComponentListener) listener);
1342 }
1343 if (listener instanceof ServiceAssemblyListener) {
1344 listeners.remove(ServiceAssemblyListener.class, (ServiceAssemblyListener) listener);
1345 }
1346 if (listener instanceof ServiceUnitListener) {
1347 listeners.remove(ServiceUnitListener.class, (ServiceUnitListener) listener);
1348 }
1349 if (listener instanceof EndpointListener) {
1350 listeners.remove(EndpointListener.class, (EndpointListener) listener);
1351 }
1352 if (listener instanceof DeploymentListener) {
1353 listeners.remove(DeploymentListener.class, (DeploymentListener) listener);
1354 }
1355 }
1356
1357 public Object[] getListeners(Class lc) {
1358 return listeners.getListeners(lc);
1359 }
1360
1361 public void setListeners(EventListener[] listeners) {
1362 configuredListeners = listeners;
1363 }
1364
1365 public void resendExchange(MessageExchange exchange) throws JBIException {
1366 if (!(exchange instanceof MessageExchangeImpl)) {
1367 throw new IllegalArgumentException("exchange should be a MessageExchangeImpl");
1368 }
1369 MessageExchangeImpl me = (MessageExchangeImpl) exchange;
1370 me.getPacket().setExchangeId(new IdGenerator().generateId());
1371 me.getPacket().setOut(null);
1372 me.getPacket().setFault(null);
1373 me.getPacket().setError(null);
1374 me.getPacket().setStatus(ExchangeStatus.ACTIVE);
1375 me.getPacket().setProperty(JbiConstants.DATESTAMP_PROPERTY_NAME, Calendar.getInstance());
1376 ExchangeListener[] l = (ExchangeListener[]) listeners.getListeners(ExchangeListener.class);
1377 ExchangeEvent event = new ExchangeEvent(me, ExchangeEvent.EXCHANGE_SENT);
1378 for (int i = 0; i < l.length; i++) {
1379 try {
1380 l[i].exchangeSent(event);
1381 } catch (Exception e) {
1382 LOG.warn("Error calling listener: " + e.getMessage(), e);
1383 }
1384 }
1385 me.handleSend(false);
1386 sendExchange(me.getMirror());
1387 }
1388
1389 public boolean isEmbedded() {
1390 return embedded;
1391 }
1392
1393 public void setEmbedded(boolean embedded) {
1394 this.embedded = embedded;
1395 }
1396
1397 public void setRmiPort(int portNum) {
1398 getManagementContext().setNamingPort(portNum);
1399 }
1400
1401 public int getRmiPort() {
1402 return getManagementContext().getNamingPort();
1403 }
1404
1405 /**
1406 * @return Returns the notifyStatistics.
1407 */
1408 public boolean isNotifyStatistics() {
1409 return notifyStatistics;
1410 }
1411
1412 /**
1413 * @param notifyStatistics The notifyStatistics to set.
1414 */
1415 public void setNotifyStatistics(boolean notifyStatistics) {
1416 this.notifyStatistics = notifyStatistics;
1417 }
1418
1419 /**
1420 * @return the executorFactory
1421 */
1422 public ExecutorFactory getExecutorFactory() {
1423 return executorFactory;
1424 }
1425
1426 /**
1427 * @param executorFactory the executorFactory to set
1428 */
1429 public void setExecutorFactory(ExecutorFactory executorFactory) {
1430 this.executorFactory = executorFactory;
1431 }
1432
1433
1434 /**
1435 * Creates a new rootDir
1436 */
1437 protected String createRootDir() {
1438 String prefix = getGeneratedRootDirPrefix();
1439 for (int i = 1; true; i++) {
1440 File file = new File(prefix + i);
1441 if (!file.exists()) {
1442 file.mkdirs();
1443 return file.getAbsolutePath();
1444 }
1445 }
1446 }
1447 }