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.framework;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.util.Properties;
022
023 import javax.jbi.JBIException;
024 import javax.jbi.component.Component;
025 import javax.jbi.component.ComponentLifeCycle;
026 import javax.jbi.component.ServiceUnitManager;
027 import javax.jbi.management.DeploymentException;
028 import javax.jbi.management.LifeCycleMBean;
029 import javax.management.JMException;
030 import javax.management.MBeanAttributeInfo;
031 import javax.management.MBeanOperationInfo;
032 import javax.management.ObjectName;
033
034 import org.apache.commons.logging.Log;
035 import org.apache.commons.logging.LogFactory;
036 import org.apache.servicemix.jbi.container.ActivationSpec;
037 import org.apache.servicemix.jbi.container.JBIContainer;
038 import org.apache.servicemix.jbi.event.ComponentEvent;
039 import org.apache.servicemix.jbi.event.ComponentListener;
040 import org.apache.servicemix.jbi.management.AttributeInfoHelper;
041 import org.apache.servicemix.jbi.management.BaseLifeCycle;
042 import org.apache.servicemix.jbi.management.ManagementContext;
043 import org.apache.servicemix.jbi.management.OperationInfoHelper;
044 import org.apache.servicemix.jbi.messaging.DeliveryChannelImpl;
045 import org.apache.servicemix.jbi.util.XmlPersistenceSupport;
046 import org.apache.xbean.classloader.DestroyableClassLoader;
047
048 /**
049 * Defines basic statistics on the Component
050 */
051 public class ComponentMBeanImpl extends BaseLifeCycle implements ComponentMBean {
052
053 private static final Log LOG = LogFactory.getLog(ComponentMBeanImpl.class);
054
055 private boolean exchangeThrottling;
056 private long throttlingTimeout = 100;
057 private int throttlingInterval = 1;
058 private Component component;
059 private ComponentLifeCycle lifeCycle;
060 private ServiceUnitManager suManager;
061 private ComponentContextImpl context;
062 private ActivationSpec activationSpec;
063 private ObjectName mBeanName;
064 private JBIContainer container;
065 private ComponentNameSpace componentName;
066 private String description = "POJO Component";
067 private int queueCapacity = 1024;
068 private boolean pojo;
069 private boolean binding;
070 private boolean service;
071 private File stateFile;
072 private String[] sharedLibraries;
073
074 /**
075 * Construct with it's id and delivery channel Id
076 *
077 * @param name
078 * @param description
079 * @param component
080 * @param binding
081 * @param service
082 * @param sharedLibraries
083 */
084 public ComponentMBeanImpl(JBIContainer container,
085 ComponentNameSpace name,
086 String description,
087 Component component,
088 boolean binding,
089 boolean service,
090 String[] sharedLibraries) {
091 this.componentName = name;
092 this.container = container;
093 this.component = component;
094 this.description = description;
095 this.binding = binding;
096 this.service = service;
097 this.sharedLibraries = sharedLibraries;
098 }
099
100 public void dispose() {
101 ClassLoader cl = component.getClass().getClassLoader();
102 lifeCycle = null;
103 suManager = null;
104 component = null;
105 if (cl instanceof DestroyableClassLoader) {
106 ((DestroyableClassLoader) cl).destroy();
107 }
108 fireEvent(ComponentEvent.COMPONENT_UNINSTALLED);
109 }
110
111 /**
112 * Register the MBeans for this Component
113 * @param ctx
114 * @return ObjectName
115 * @throws JBIException
116 */
117 public ObjectName registerMBeans(ManagementContext ctx) throws JBIException {
118 try {
119 mBeanName = ctx.createObjectName(this);
120 ctx.registerMBean(mBeanName, this, ComponentMBean.class);
121 return mBeanName;
122 } catch (Exception e) {
123 String errorStr = "Failed to register MBeans";
124 LOG.error(errorStr, e);
125 throw new JBIException(errorStr, e);
126 }
127 }
128
129 /**
130 * Unregister Component MBeans
131 * @param ctx
132 * @throws JBIException
133 */
134 public void unregisterMbeans(ManagementContext ctx) throws JBIException {
135 ctx.unregisterMBean(mBeanName);
136 }
137
138 /**
139 * Set the Context
140 *
141 * @param ctx
142 */
143 public void setContext(ComponentContextImpl ctx) {
144 this.context = ctx;
145 this.stateFile = ctx.getEnvironment().getStateFile();
146 }
147
148 /**
149 * Get the JMX ObjectName for any additional MBean for this component. If there is none, return null.
150 *
151 * @return ObjectName the JMX object name of the additional MBean or null if there is no additional MBean.
152 */
153 public ObjectName getExtensionMBeanName() {
154 if (isInitialized() || isStarted() || isStopped()) {
155 return lifeCycle.getExtensionMBeanName();
156 } else {
157 return null;
158 }
159 }
160
161 /**
162 * Get the name of the item
163 * @return the name
164 */
165 public String getName() {
166 return componentName.getName();
167 }
168
169 /**
170 * Get the type of the item
171 * @return the type
172 */
173 public String getType() {
174 return "Component";
175 }
176
177 public String getSubType() {
178 return "LifeCycle";
179 }
180
181 /**
182 * Get the Description of the item
183 * @return the description
184 */
185 public String getDescription() {
186 return description;
187 }
188
189
190 public void init() throws JBIException {
191 LOG.info("Initializing component: " + getName());
192 if (context != null && component != null) {
193 DeliveryChannelImpl channel = new DeliveryChannelImpl(this);
194 channel.setContext(context);
195 context.setDeliveryChannel(channel);
196 super.init();
197 fireEvent(ComponentEvent.COMPONENT_INITIALIZED);
198 ClassLoader loader = Thread.currentThread().getContextClassLoader();
199 try {
200 Thread.currentThread().setContextClassLoader(component.getClass().getClassLoader());
201 getLifeCycle().init(context);
202 } finally {
203 Thread.currentThread().setContextClassLoader(loader);
204 }
205 }
206 }
207
208 /**
209 * Start the item.
210 *
211 * @exception javax.jbi.JBIException if the item fails to start.
212 */
213 public void start() throws javax.jbi.JBIException {
214 LOG.info("Starting component: " + getName());
215 try {
216 doStart();
217 persistRunningState();
218 getContainer().getRegistry().checkPendingAssemblies();
219 } catch (JBIException e) {
220 LOG.error("Could not start component", e);
221 throw e;
222 } catch (RuntimeException e) {
223 LOG.error("Could not start component", e);
224 throw e;
225 } catch (Error e) {
226 LOG.error("Could not start component", e);
227 throw e;
228 }
229 }
230
231 /**
232 * Stop the item. This suspends current messaging activities.
233 *
234 * @exception javax.jbi.JBIException if the item fails to stop.
235 */
236 public void stop() throws javax.jbi.JBIException {
237 LOG.info("Stopping component: " + getName());
238 try {
239 doStop();
240 persistRunningState();
241 } catch (JBIException e) {
242 LOG.error("Could not stop component", e);
243 throw e;
244 } catch (RuntimeException e) {
245 LOG.error("Could not start component", e);
246 throw e;
247 } catch (Error e) {
248 LOG.error("Could not start component", e);
249 throw e;
250 }
251 }
252
253 /**
254 * Shut down the item. The releases resources, preparatory to uninstallation.
255 *
256 * @exception javax.jbi.JBIException if the item fails to shut down.
257 */
258 public void shutDown() throws javax.jbi.JBIException {
259 LOG.info("Shutting down component: " + getName());
260 try {
261 doShutDown();
262 persistRunningState();
263 } catch (JBIException e) {
264 LOG.error("Could not shutDown component", e);
265 throw e;
266 } catch (RuntimeException e) {
267 LOG.error("Could not start component", e);
268 throw e;
269 } catch (Error e) {
270 LOG.error("Could not start component", e);
271 throw e;
272 }
273 }
274
275 public void setShutdownStateAfterInstall() {
276 setCurrentState(SHUTDOWN);
277 }
278
279 /**
280 * Start the item - doesn't persist the state
281 *
282 * @exception javax.jbi.JBIException if the item fails to start.
283 */
284 public void doStart() throws javax.jbi.JBIException {
285 if (isShutDown()) {
286 // need to re-initialze before starting
287 init();
288 }
289 if (!isStarted()) {
290 ClassLoader loader = Thread.currentThread().getContextClassLoader();
291 try {
292 Thread.currentThread().setContextClassLoader(component.getClass().getClassLoader());
293 getLifeCycle().start();
294 } finally {
295 Thread.currentThread().setContextClassLoader(loader);
296 }
297 super.start();
298 initServiceAssemblies();
299 startServiceAssemblies();
300 }
301 fireEvent(ComponentEvent.COMPONENT_STARTED);
302 }
303
304 /**
305 * Stop the item - doesn't persist the state
306 *
307 * @exception javax.jbi.JBIException
308 * if the item fails to stop.
309 */
310 public void doStop() throws javax.jbi.JBIException {
311 if (isUnknown() || isStarted()) {
312 stopServiceAssemblies();
313 ClassLoader loader = Thread.currentThread().getContextClassLoader();
314 try {
315 Thread.currentThread().setContextClassLoader(component.getClass().getClassLoader());
316 getLifeCycle().stop();
317 } finally {
318 Thread.currentThread().setContextClassLoader(loader);
319 }
320 super.stop();
321 }
322 fireEvent(ComponentEvent.COMPONENT_STOPPED);
323 }
324
325 /**
326 * Shut down the item - doesn't persist the state
327 *
328 * @exception javax.jbi.JBIException if the item fails to shut down.
329 */
330 public void doShutDown() throws javax.jbi.JBIException {
331 // Transition from UNKNOWN to SHUTDOWN is done at installation time
332 // In this case or if the component is already shut down, do nothing
333 if (!isUnknown() && !isShutDown()) {
334 doStop();
335 shutDownServiceAssemblies();
336 ClassLoader loader = Thread.currentThread().getContextClassLoader();
337 try {
338 Thread.currentThread().setContextClassLoader(component.getClass().getClassLoader());
339 getLifeCycle().shutDown();
340 } finally {
341 Thread.currentThread().setContextClassLoader(loader);
342 }
343 if (getDeliveryChannel() != null) {
344 getDeliveryChannel().close();
345 setDeliveryChannel(null);
346 }
347 lifeCycle = null;
348 suManager = null;
349 }
350 super.shutDown();
351 fireEvent(ComponentEvent.COMPONENT_SHUTDOWN);
352 }
353
354
355 /**
356 * Set the initial running state of the Component
357 * @throws JBIException
358 */
359 public void setInitialRunningState() throws JBIException {
360 if (!isPojo()) {
361 String name = getName();
362 String runningState = getRunningStateFromStore();
363 LOG.info("Setting running state for Component: " + name + " to " + runningState);
364 if (runningState != null) {
365 if (runningState.equals(LifeCycleMBean.STARTED)) {
366 doStart();
367 } else if (runningState.equals(LifeCycleMBean.STOPPED)) {
368 doStart();
369 doStop();
370 } else if (runningState.equals(LifeCycleMBean.SHUTDOWN)) {
371 doShutDown();
372 }
373 }
374 }
375 }
376
377 /**
378 * Persist the running state
379 */
380 public void persistRunningState() {
381 if (!isPojo()) {
382 String name = getName();
383 try {
384 String currentState = getCurrentState();
385 Properties props = new Properties();
386 props.setProperty("state", currentState);
387 XmlPersistenceSupport.write(stateFile, props);
388 } catch (IOException e) {
389 LOG.error("Failed to write current running state for Component: " + name, e);
390 }
391 }
392 }
393
394 /**
395 * @return the current running state from disk
396 */
397 public String getRunningStateFromStore() {
398 String result = LifeCycleMBean.UNKNOWN;
399 String name = getName();
400 try {
401 Properties props = (Properties) XmlPersistenceSupport.read(stateFile);
402 result = props.getProperty("state", result);
403 } catch (Exception e) {
404 LOG.error("Failed to read running state for Component: " + name, e);
405 }
406 return result;
407 }
408
409 /**
410 * @return the capacity of the inbound queue
411 */
412 public int getInboundQueueCapacity() {
413 return queueCapacity;
414 }
415
416 /**
417 * Set the inbound queue capacity
418 * @param value
419 */
420 public void setInboundQueueCapacity(int value) {
421 if (getDeliveryChannel() != null) {
422 throw new IllegalStateException("The component must be shut down before changing queue capacity");
423 }
424 this.queueCapacity = value;
425 }
426
427 /**
428 * @return Returns the deliveryChannel.
429 */
430 public DeliveryChannelImpl getDeliveryChannel() {
431 return (DeliveryChannelImpl) context.getDeliveryChannel();
432 }
433
434 /**
435 * @param deliveryChannel
436 * The deliveryChannel to set.
437 */
438 public void setDeliveryChannel(DeliveryChannelImpl deliveryChannel) {
439 context.setDeliveryChannel(deliveryChannel);
440 }
441
442 /**
443 * @return the ActivateionSpec
444 */
445 public ActivationSpec getActivationSpec() {
446 return activationSpec;
447 }
448
449 /**
450 * @return Returns the pojo.
451 */
452 public boolean isPojo() {
453 return pojo;
454 }
455
456 /**
457 * Set the ActivationSpec
458 *
459 * @param activationSpec
460 */
461 public void setActivationSpec(ActivationSpec activationSpec) {
462 this.activationSpec = activationSpec;
463 }
464
465 /**
466 * Is MessageExchange sender throttling enabled ?
467 *
468 * @return true if throttling enabled
469 */
470 public boolean isExchangeThrottling() {
471 return exchangeThrottling;
472 }
473
474 /**
475 * Set message throttling
476 *
477 * @param value
478 */
479 public void setExchangeThrottling(boolean value) {
480 this.exchangeThrottling = value;
481 }
482
483 /**
484 * Get the throttling timeout
485 *
486 * @return throttling tomeout (ms)
487 */
488 public long getThrottlingTimeout() {
489 return throttlingTimeout;
490 }
491
492 /**
493 * Set the throttling timout
494 *
495 * @param value (ms)
496 */
497 public void setThrottlingTimeout(long value) {
498 throttlingTimeout = value;
499 }
500
501 /**
502 * Get the interval for throttling - number of Exchanges set before the throttling timeout is applied
503 *
504 * @return interval for throttling
505 */
506 public int getThrottlingInterval() {
507 return throttlingInterval;
508 }
509
510 /**
511 * Set the throttling interval number of Exchanges set before the throttling timeout is applied
512 *
513 * @param value
514 */
515 public void setThrottlingInterval(int value) {
516 throttlingInterval = value;
517 }
518
519 /**
520 * Get an array of MBeanAttributeInfo
521 *
522 * @return array of AttributeInfos
523 * @throws JMException
524 */
525 public MBeanAttributeInfo[] getAttributeInfos() throws JMException {
526 AttributeInfoHelper helper = new AttributeInfoHelper();
527 helper.addAttribute(getObjectToManage(), "componentType", "the type of this component (BC, SE, POJO)");
528 helper.addAttribute(getObjectToManage(), "inboundQueueCapacity", "capacity of the inbound queue");
529 helper.addAttribute(getObjectToManage(), "exchangeThrottling", "apply throttling");
530 helper.addAttribute(getObjectToManage(), "throttlingTimeout", "timeout for throttling");
531 helper.addAttribute(getObjectToManage(), "throttlingInterval", "exchange intervals before throttling");
532 helper.addAttribute(getObjectToManage(), "extensionMBeanName", "extension mbean name");
533 return AttributeInfoHelper.join(super.getAttributeInfos(), helper.getAttributeInfos());
534 }
535
536 /**
537 * Get an array of MBeanOperationInfo
538 *
539 * @return array of OperationInfos
540 * @throws JMException
541 */
542 public MBeanOperationInfo[] getOperationInfos() throws JMException {
543 OperationInfoHelper helper = new OperationInfoHelper();
544 return OperationInfoHelper.join(super.getOperationInfos(), helper.getOperationInfos());
545 }
546
547 public void firePropertyChanged(String name, Object oldValue, Object newValue) {
548 super.firePropertyChanged(name, oldValue, newValue);
549 }
550
551 protected void initServiceAssemblies() throws DeploymentException {
552 }
553
554 protected void startServiceAssemblies() throws DeploymentException {
555 }
556
557 protected void stopServiceAssemblies() throws DeploymentException {
558 Registry registry = getContainer().getRegistry();
559 String[] sas = registry.getDeployedServiceAssembliesForComponent(getName());
560 for (int i = 0; i < sas.length; i++) {
561 ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(sas[i]);
562 if (sa.isStarted()) {
563 try {
564 sa.stop(false, false);
565 registry.addPendingAssembly(sa);
566 } catch (Exception e) {
567 LOG.error("Error stopping service assembly " + sas[i]);
568 }
569 }
570 }
571 }
572
573 protected void shutDownServiceAssemblies() throws DeploymentException {
574 Registry registry = getContainer().getRegistry();
575 String[] sas = registry.getDeployedServiceAssembliesForComponent(getName());
576 for (int i = 0; i < sas.length; i++) {
577 ServiceAssemblyLifeCycle sa = registry.getServiceAssembly(sas[i]);
578 if (sa.isStopped()) {
579 try {
580 sa.shutDown(false);
581 registry.addPendingAssembly(sa);
582 } catch (Exception e) {
583 LOG.error("Error shutting down service assembly " + sas[i]);
584 }
585 }
586 }
587 }
588
589 protected void fireEvent(int type) {
590 ComponentEvent event = new ComponentEvent(this, type);
591 ComponentListener[] listeners = (ComponentListener[]) getContainer().getListeners(ComponentListener.class);
592 for (int i = 0; i < listeners.length; i++) {
593 switch (type) {
594 case ComponentEvent.COMPONENT_INITIALIZED:
595 listeners[i].componentInitialized(event);
596 break;
597 case ComponentEvent.COMPONENT_STARTED:
598 listeners[i].componentStarted(event);
599 break;
600 case ComponentEvent.COMPONENT_STOPPED:
601 listeners[i].componentStopped(event);
602 break;
603 case ComponentEvent.COMPONENT_SHUTDOWN:
604 listeners[i].componentShutDown(event);
605 break;
606 case ComponentEvent.COMPONENT_UNINSTALLED:
607 listeners[i].componentUninstalled(event);
608 break;
609 default:
610 break;
611 }
612 }
613
614 }
615
616 public ComponentLifeCycle getLifeCycle() {
617 if (lifeCycle == null) {
618 lifeCycle = component.getLifeCycle();
619 }
620 return lifeCycle;
621 }
622
623 public ServiceUnitManager getServiceUnitManager() {
624 if (suManager == null) {
625 suManager = component.getServiceUnitManager();
626 }
627 return suManager;
628 }
629
630 public JBIContainer getContainer() {
631 return container;
632 }
633
634 public Component getComponent() {
635 return component;
636 }
637
638 public ComponentNameSpace getComponentNameSpace() {
639 return componentName;
640 }
641
642 public ComponentContextImpl getContext() {
643 return context;
644 }
645 public ObjectName getMBeanName() {
646 return mBeanName;
647 }
648 public boolean isBinding() {
649 return binding;
650 }
651 public boolean isService() {
652 return service;
653 }
654
655 public void setPojo(boolean pojo) {
656 this.pojo = pojo;
657 }
658
659 public boolean isEngine() {
660 return service;
661 }
662
663 /**
664 * @return the sharedLibraries
665 */
666 public String[] getSharedLibraries() {
667 return sharedLibraries;
668 }
669
670 /**
671 * @return the component type
672 */
673 public String getComponentType() {
674 return isBinding() ? "binding-component" : isEngine() ? "service-engine" : "pojo";
675 }
676
677 }