001: /*
002: * $Id: AbstractComponent.java 11416 2008-03-18 04:20:51Z dfeist $
003: * --------------------------------------------------------------------------------------
004: * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
005: *
006: * The software in this package is published under the terms of the CPAL v1.0
007: * license, a copy of which has been included with this distribution in the
008: * LICENSE.txt file.
009: */
010:
011: package org.mule.component;
012:
013: import org.mule.api.DefaultMuleException;
014: import org.mule.api.MuleEvent;
015: import org.mule.api.MuleException;
016: import org.mule.api.MuleMessage;
017: import org.mule.api.component.Component;
018: import org.mule.api.endpoint.InboundEndpoint;
019: import org.mule.api.lifecycle.DisposeException;
020: import org.mule.api.lifecycle.InitialisationException;
021: import org.mule.api.lifecycle.LifecycleTransitionResult;
022: import org.mule.api.service.Service;
023: import org.mule.api.service.ServiceException;
024: import org.mule.api.transport.ReplyToHandler;
025: import org.mule.config.i18n.CoreMessages;
026: import org.mule.config.i18n.MessageFactory;
027: import org.mule.management.stats.ComponentStatistics;
028: import org.mule.transport.AbstractConnector;
029:
030: import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
031:
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034:
035: /**
036: * Abstract {@link Component} to be used by all {@link Component} implementations.
037: */
038: public abstract class AbstractComponent implements Component {
039:
040: /** logger used by this class */
041: protected final Log logger = LogFactory.getLog(this .getClass());
042:
043: protected Service service;
044: protected ComponentStatistics statistics = null;
045: protected final AtomicBoolean started = new AtomicBoolean(false);
046: protected final AtomicBoolean stopping = new AtomicBoolean(false);
047: protected final AtomicBoolean initialised = new AtomicBoolean(false);
048: protected final AtomicBoolean disposing = new AtomicBoolean(false);
049: protected final AtomicBoolean disposed = new AtomicBoolean(false);
050:
051: public AbstractComponent() {
052: statistics = new ComponentStatistics();
053: }
054:
055: public MuleMessage onCall(MuleEvent event) throws MuleException {
056: if (logger.isTraceEnabled()) {
057: logger.trace(this .getClass().getName()
058: + ": sync call for Mule Component "
059: + service.getName());
060: }
061: checkDisposed();
062: if (!(event.getEndpoint() instanceof InboundEndpoint)) {
063: throw new IllegalStateException(
064: "Unable to process outbound event, components only process incoming events.");
065: }
066: if (stopping.get() || !started.get()) {
067: throw new DefaultMuleException(CoreMessages
068: .componentIsStopped(service.getName()));
069: }
070: try {
071: return doOnCall(event);
072: } catch (Exception e) {
073: throw new ServiceException(CoreMessages.failedToInvoke(this
074: .toString()), event.getMessage(), service, e);
075: }
076: }
077:
078: public void onEvent(MuleEvent event) {
079: if (logger.isTraceEnabled()) {
080: logger.trace(this .getClass().getName()
081: + ": async call for Mule Component "
082: + service.getName());
083: }
084: try {
085: checkDisposed();
086: if (!(event.getEndpoint() instanceof InboundEndpoint)) {
087: throw new IllegalStateException(
088: "Unable to process outbound event, components only process incoming events.");
089: }
090: if (stopping.get() || !started.get()) {
091: throw new DefaultMuleException(CoreMessages
092: .componentIsStopped(service.getName()));
093: }
094: doOnEvent(event);
095: } catch (Exception e) {
096: logger.error(new ServiceException(CoreMessages
097: .failedToInvoke(this .toString()), event
098: .getMessage(), service, e));
099: }
100: }
101:
102: protected abstract MuleMessage doOnCall(MuleEvent event);
103:
104: protected abstract void doOnEvent(MuleEvent event);
105:
106: /**
107: * When an exception occurs this method can be called to invoke the configured
108: * UMOExceptionStrategy on the UMO
109: *
110: * @param exception If the UMOExceptionStrategy implementation fails
111: */
112: public void handleException(Exception exception) {
113: service.getExceptionListener().exceptionThrown(exception);
114: }
115:
116: public String toString() {
117: return "proxy for: " + service.toString();
118: }
119:
120: protected ReplyToHandler getReplyToHandler(MuleMessage message,
121: InboundEndpoint endpoint) {
122: Object replyTo = message.getReplyTo();
123: ReplyToHandler replyToHandler = null;
124: if (replyTo != null) {
125: replyToHandler = ((AbstractConnector) endpoint
126: .getConnector()).getReplyToHandler();
127: // Use the response transformer for the event if one is set
128: if (endpoint.getResponseTransformers() != null) {
129: replyToHandler.setTransformers(endpoint
130: .getResponseTransformers());
131: }
132: }
133: return replyToHandler;
134: }
135:
136: public void release() {
137: // nothing to do
138: }
139:
140: public ComponentStatistics getStatistics() {
141: return statistics;
142: }
143:
144: public void setService(Service service) {
145: this .service = service;
146: }
147:
148: public Service getService() {
149: return service;
150: }
151:
152: public LifecycleTransitionResult initialise()
153: throws InitialisationException {
154: if (!initialised.get()) {
155: if (logger.isInfoEnabled()) {
156: logger.info("Initialising: " + this );
157: }
158: if (service == null) {
159: throw new InitialisationException(
160: MessageFactory
161: .createStaticMessage("Component has not been initialized properly, no service."),
162: this );
163: }
164: doInitialise();
165: initialised.set(true);
166: }
167: return LifecycleTransitionResult.OK;
168: }
169:
170: protected abstract void doInitialise()
171: throws InitialisationException;
172:
173: public void dispose() {
174: disposing.set(true);
175: try {
176: if (started.get()) {
177: stop();
178: }
179: } catch (MuleException e) {
180: logger.error(CoreMessages.failedToStop(toString()));
181: }
182: try {
183: doDispose();
184: } catch (Exception e) {
185: logger.warn(CoreMessages.failedToDispose(toString()), e);
186: } finally {
187: disposed.set(true);
188: disposing.set(false);
189: initialised.set(false);
190: }
191: }
192:
193: protected abstract void doDispose();
194:
195: public LifecycleTransitionResult stop() throws MuleException {
196: // If component is already disposed then ignore, don't fails, as stop() might
197: // get called by service after spring has called disposed etc.
198: if (!disposed.get() && started.get() && !stopping.get()) {
199: stopping.set(true);
200: if (logger.isInfoEnabled()) {
201: logger.info("Stopping: " + this );
202: }
203: doStop();
204: started.set(false);
205: stopping.set(false);
206: }
207: return LifecycleTransitionResult.OK;
208: }
209:
210: protected abstract void doStart() throws MuleException;
211:
212: public LifecycleTransitionResult start() throws MuleException {
213: checkDisposed();
214: if (!started.get()) {
215: if (logger.isInfoEnabled()) {
216: logger.info("Starting: " + this );
217: }
218: doStart();
219: started.set(true);
220: }
221: return LifecycleTransitionResult.OK;
222: }
223:
224: protected abstract void doStop() throws MuleException;
225:
226: protected void checkDisposed() throws DisposeException {
227: if (disposed.get()) {
228: throw new DisposeException(
229: CoreMessages
230: .createStaticMessage("Cannot use a disposed component"),
231: this);
232: }
233: }
234:
235: }
|