PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib-fort/rules4jbi/src/main/org/openesb/components/rules4jbi/engine/component/Rules4JBIComponent.java

https://bitbucket.org/ssteinmetz/openesb-components
Java | 365 lines | 198 code | 102 blank | 65 comment | 21 complexity | 9607a9a1aa4415eadb596d9e24d953bb MD5 | raw file
  1. /*
  2. * @(#)Rules4JBIComponent.java $Revision: 1.2 $ $Date: 2008/07/14 16:30:26 $
  3. *
  4. * Copyright (c) 2008 Milan Fort (http://www.milanfort.com/). All rights reserved.
  5. *
  6. * The contents of this file are subject to the terms of the Common Development
  7. * and Distribution License (the "License"). You may not use this file except
  8. * in compliance with the License.
  9. *
  10. * You can obtain a copy of the license at http://www.sun.com/cddl/cddl.html.
  11. * See the License for the specific language governing permissions and limitations
  12. * under the License.
  13. */
  14. package org.openesb.components.rules4jbi.engine.component;
  15. import java.io.File;
  16. import java.util.concurrent.Callable;
  17. import java.util.concurrent.CompletionService;
  18. import java.util.concurrent.ExecutionException;
  19. import java.util.concurrent.ExecutorService;
  20. import java.util.concurrent.Executors;
  21. import java.util.concurrent.Future;
  22. import java.util.concurrent.TimeUnit;
  23. import javax.jbi.JBIException;
  24. import javax.jbi.component.Component;
  25. import javax.jbi.component.ComponentContext;
  26. import javax.jbi.component.ComponentLifeCycle;
  27. import javax.jbi.component.ServiceUnitManager;
  28. import javax.jbi.messaging.ExchangeStatus;
  29. import javax.jbi.messaging.InOut;
  30. import javax.jbi.messaging.MessageExchange;
  31. import javax.jbi.servicedesc.ServiceEndpoint;
  32. import javax.management.ObjectName;
  33. import org.w3c.dom.Document;
  34. import org.w3c.dom.DocumentFragment;
  35. import com.google.inject.Guice;
  36. import com.google.inject.Inject;
  37. import com.google.inject.Injector;
  38. import com.google.inject.Stage;
  39. import net.jcip.annotations.NotThreadSafe;
  40. import org.openesb.components.rules4jbi.shared.logging.Logger;
  41. import org.openesb.components.rules4jbi.engine.guice.annotations.Main;
  42. import org.openesb.components.rules4jbi.engine.guice.annotations.MessageExchangeProcessor;
  43. import org.openesb.components.rules4jbi.engine.guice.modules.ConstantModule;
  44. import org.openesb.components.rules4jbi.engine.guice.modules.ExecutorModule;
  45. import org.openesb.components.rules4jbi.engine.guice.modules.JBIModule;
  46. import org.openesb.components.rules4jbi.engine.guice.modules.LoggerModule;
  47. import org.openesb.components.rules4jbi.engine.util.DOMUtils;
  48. import static org.openesb.components.rules4jbi.engine.util.ConcurrencyUtils.shutdownExecutorService;
  49. /**
  50. * This class is the entry point of the Rules service engine to the JBI runtime.
  51. * It implements both the <code>javax.jbi.component.Component</code> and
  52. * <code>javax.jbi.component.ComponentLifeCycle</code> interfaces.
  53. *
  54. * @author Milan Fort (http://www.milanfort.com/)
  55. * @version $Revision: 1.2 $ $Date: 2008/07/14 16:30:26 $
  56. *
  57. * @see javax.jbi.component.Component
  58. * @see javax.jbi.component.ComponentLifeCycle
  59. * @since 0.1
  60. */
  61. @NotThreadSafe
  62. public class Rules4JBIComponent implements Component, ComponentLifeCycle {
  63. /** Time to wait for tasks to complete after component was stopped; in seconds. */
  64. private static final long TASK_COMPLETION_WAIT_TIME = 2;
  65. @Inject @Main
  66. private Logger logger;
  67. @Inject
  68. private Injector injector;
  69. @Inject
  70. private Rules4JBIServiceUnitManager manager;
  71. @Inject
  72. private DeliveryChannelService deliveryChannelService;
  73. @Inject
  74. private ComponentContext componentContext;
  75. @Inject @Main
  76. private ExecutorService mainExecutorService;
  77. /**
  78. * This completition service uses mainExecutorService as its internal executor.
  79. *
  80. * @see #mainExecutorService
  81. */
  82. @Inject @MessageExchangeProcessor
  83. private CompletionService<InOut> messageExchangeProcessor;
  84. private ExecutorService dispatcher;
  85. private ExecutorService collector;
  86. /* ComponentLifeCycle Methods */
  87. public ObjectName getExtensionMBeanName() {
  88. logger.entering(this.getClass(), "getExtensionMBeanName");
  89. return null;
  90. }
  91. public void init(ComponentContext componentContext) throws JBIException {
  92. if (componentContext == null) {
  93. throw new JBIException("Null component context received during bootstrap");
  94. }
  95. /*
  96. * The JBI spec doesn't guarantee that the same instance will be provided
  97. * during the lifecycle of the component. Therefore, we need to re-inject
  98. * the dependencie upon every init() method call.
  99. */
  100. // if (this.componentContext != null && this.componentContext != componentContext) {
  101. // throw new JBIException("Different instance of component context during lifecycle is not supported");
  102. // }
  103. boolean configurationValuesLoaded = true;
  104. InstallationConfiguration configuration = null;
  105. try {
  106. configuration = InstallationConfiguration.load(
  107. new File(componentContext.getWorkspaceRoot(), InstallationConfiguration.CONFIG_FILE_NAME));
  108. } catch (InvalidInstallationConfigurationException e) {
  109. configurationValuesLoaded = false;
  110. configuration = new InstallationConfiguration();
  111. }
  112. injector = Guice.createInjector(Stage.PRODUCTION,
  113. new JBIModule(componentContext),
  114. new LoggerModule(componentContext),
  115. new ConstantModule(configuration.getMaxServiceUnits()),
  116. new ExecutorModule(configuration.getPoolSize()));
  117. injector.injectMembers(this);
  118. manager.injectDependenciesIntoServiceUnits();
  119. if (logger == null) {
  120. throw new JBIException("Unable to properly inject depencencies");
  121. }
  122. logger.entering(this.getClass(), "init");
  123. logger.info("Initializing component '%s'", componentContext.getComponentName());
  124. if (!configurationValuesLoaded) {
  125. logger.warning("Failed to load configuration file; using default values");
  126. }
  127. logger.config("Thread pool size: %d", configuration.getPoolSize());
  128. logger.config("Maximum allowed service units: %d", configuration.getMaxServiceUnits());
  129. deliveryChannelService.init();
  130. dispatcher = Executors.newSingleThreadExecutor();
  131. collector = Executors.newSingleThreadExecutor();
  132. logger.exiting(this.getClass(), "init");
  133. }
  134. public void start() throws JBIException {
  135. logger.entering(this.getClass(), "start");
  136. deliveryChannelService.start();
  137. collector.execute(new CollectorTask());
  138. dispatcher.execute(new DispatcherTask());
  139. /*
  140. * JBI runtime will start the service units automatically, if appropriate
  141. */
  142. }
  143. public void stop() throws JBIException {
  144. logger.entering(this.getClass(), "stop");
  145. deliveryChannelService.stop();
  146. /*
  147. * JBI runtime will stop the service units automatically, if appropriate
  148. */
  149. }
  150. public void shutDown() throws JBIException {
  151. logger.entering(this.getClass(), "shutDown");
  152. shutdownExecutorService(logger, "Dispatcher", dispatcher);
  153. shutdownExecutorService(logger, "Collector", collector);
  154. shutdownExecutorService(logger, "Main Executor", mainExecutorService);
  155. deliveryChannelService.shutDown();
  156. }
  157. /* Component Methods */
  158. public ComponentLifeCycle getLifeCycle() {
  159. return this;
  160. }
  161. public Document getServiceDescription(ServiceEndpoint endpoint) {
  162. logger.entering(this.getClass(), "getServiceDescription", endpoint);
  163. ServiceUnit serviceUnit = manager.findByServiceEndpoint(endpoint);
  164. return serviceUnit != null ? serviceUnit.getServiceDescription() : null;
  165. }
  166. public ServiceUnitManager getServiceUnitManager() {
  167. logger.entering(this.getClass(), "getServiceUnitManager");
  168. return manager;
  169. }
  170. public boolean isExchangeWithConsumerOkay(ServiceEndpoint endpoint, MessageExchange exchange) {
  171. logger.entering(this.getClass(), "isExchangeWithConsumerOkay");
  172. /*
  173. * TODO: We should check whether we want/are able to handle this exchange
  174. */
  175. return true;
  176. }
  177. public boolean isExchangeWithProviderOkay(ServiceEndpoint endpoint, MessageExchange exchange) {
  178. logger.entering(this.getClass(), "isExchangeWithProviderOkay");
  179. /*
  180. * TODO: We should probably return false here. We do not initiate message exchanges,
  181. * so this method should never be called on us.
  182. */
  183. return true;
  184. }
  185. public ServiceEndpoint resolveEndpointReference(DocumentFragment epr) {
  186. logger.entering(this.getClass(), "resolveEndpointReference", DOMUtils.documentFragmentToString(epr));
  187. /* We do not support dynamic endpoints */
  188. return null;
  189. }
  190. /* Tasks */
  191. /**
  192. * Task responsible for retrieving received <code>MessageExchange</code>s
  193. * and dispatching them to the appropriate service unit for processing.
  194. */
  195. private class DispatcherTask implements Runnable {
  196. public void run() {
  197. logger.fine("Starting message dispatcher");
  198. while (true) {
  199. try {
  200. MessageExchange messageExchange = deliveryChannelService.receive();
  201. if (messageExchange instanceof EmptyMessageExchange) {
  202. logger.fine("Message dispatcher received terminal message");
  203. messageExchangeProcessor.submit(new Callable<InOut>() {
  204. public InOut call() throws Exception {
  205. /* give the other tasks some time to complete */
  206. TimeUnit.SECONDS.sleep(TASK_COMPLETION_WAIT_TIME);
  207. return new EmptyMessageExchange();
  208. }
  209. });
  210. break;
  211. } else if (messageExchange instanceof InOut) {
  212. InOut inOut = (InOut) messageExchange;
  213. if (ExchangeStatus.ACTIVE.equals(inOut.getStatus())) {
  214. logger.fine("Searching for service unit for the endpoint: %s", inOut.getEndpoint());
  215. ServiceUnit serviceUnit = manager.findByServiceEndpoint(inOut.getEndpoint());
  216. if (serviceUnit != null) {
  217. serviceUnit.process(inOut);
  218. } else {
  219. logger.warning("Could not find providing service unit");
  220. }
  221. } else if (ExchangeStatus.DONE.equals(inOut.getStatus())) {
  222. logger.fine("Received message with DONE status");
  223. } else if (ExchangeStatus.ERROR.equals(inOut.getStatus())) {
  224. logger.warning("Received message with ERROR status", inOut.getError());
  225. }
  226. } else {
  227. logger.severe("Received incorrect MEP");
  228. }
  229. } catch (InterruptedException e) {
  230. logger.fine("Message dispatcher interrupted");
  231. break;
  232. }
  233. }
  234. logger.fine("Message dispatcher terminated");
  235. }
  236. }
  237. /**
  238. * Task responsible for retrieving completed <code>MessageExchange</code>s
  239. * and sending them back to the caller via <code>DeliveryChannelService</code>.
  240. */
  241. private class CollectorTask implements Runnable {
  242. public void run() {
  243. logger.fine("Starting results collector");
  244. while (true) {
  245. try {
  246. Future<InOut> processedMessageExchange = messageExchangeProcessor.take();
  247. InOut processedMessage = processedMessageExchange.get();
  248. deliveryChannelService.send(processedMessage);
  249. if (processedMessage instanceof EmptyMessageExchange) {
  250. logger.fine("Results collector received terminal message");
  251. break;
  252. }
  253. } catch (InterruptedException e) {
  254. logger.fine("Results collector interrupted");
  255. break;
  256. } catch (ExecutionException e) {
  257. logger.warning("Error while executing task", e);
  258. }
  259. }
  260. logger.fine("Results collector terminated");
  261. }
  262. }
  263. }