View Javadoc

1   /*
2    * $Id: AbstractConnectable.java 11966 2008-06-05 20:27:51Z aguenther $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport;
12  
13  import org.mule.api.MuleException;
14  import org.mule.api.MuleRuntimeException;
15  import org.mule.api.context.WorkManager;
16  import org.mule.api.endpoint.ImmutableEndpoint;
17  import org.mule.api.transport.Connectable;
18  import org.mule.api.transport.ConnectionStrategy;
19  import org.mule.api.transport.Connector;
20  import org.mule.config.i18n.CoreMessages;
21  import org.mule.context.notification.ConnectionNotification;
22  import org.mule.util.ClassUtils;
23  
24  import java.beans.ExceptionListener;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  /**
30   * Provide a default dispatch (client) support for handling threads lifecycle and validation.
31   */
32  public abstract class AbstractConnectable implements Connectable, ExceptionListener
33  {
34  
35      /**
36       * logger used by this class
37       */
38      protected transient Log logger = LogFactory.getLog(getClass());
39  
40      protected final ImmutableEndpoint endpoint;
41      protected final AbstractConnector connector;
42  
43      protected boolean disposed = false;
44  
45      protected ConnectionStrategy connectionStrategy;
46  
47      protected volatile boolean connecting = false;
48      protected volatile boolean connected = false;
49  
50      public AbstractConnectable(ImmutableEndpoint endpoint)
51      {
52          this.endpoint = endpoint;
53          this.connector = (AbstractConnector) endpoint.getConnector();
54  
55          connectionStrategy = endpoint.getConnectionStrategy();
56          if (connectionStrategy instanceof AbstractConnectionStrategy)
57          {
58              // We don't want to do threading in the dispatcher because we're either
59              // already running in a worker thread (asynchronous) or we need to
60              // complete the operation in a single thread
61              final AbstractConnectionStrategy connStrategy = (AbstractConnectionStrategy) connectionStrategy;
62              if (connStrategy.isDoThreading())
63              {
64                  if (logger.isDebugEnabled())
65                  {
66                      logger.debug("Overriding doThreading to false on " + connStrategy);
67                  }
68                  connStrategy.setDoThreading(false);
69              }
70          }
71  
72          if (isDoThreading())
73          {
74              try
75              {
76                  connector.getDispatcherWorkManager();
77              }
78              catch (MuleException e)
79              {
80                  disposeAndLogException();
81                  throw new MuleRuntimeException(CoreMessages.failedToStart("WorkManager"), e);
82              }
83          }
84      }
85  
86      protected void disposeAndLogException()
87      {
88          try
89          {
90              dispose();
91          }
92          catch (Throwable t)
93          {
94              logger.error("Could not dispose of the message dispatcher!", t);
95          }
96      }
97  
98      /*
99       * (non-Javadoc)
100      *
101      * @see org.mule.util.ExceptionListener#onException(java.lang.Throwable)
102      */
103     public void exceptionThrown(Exception e)
104     {
105         try
106         {
107             getConnector().handleException(e);
108         }
109         finally
110         {
111             dispose();
112         }
113     }
114 
115     public boolean validate()
116     {
117         // by default a dispatcher/requester can be used unless disposed
118         return !disposed;
119     }
120 
121     public void activate()
122     {
123         // nothing to do by default
124     }
125 
126     public void passivate()
127     {
128         // nothing to do by default
129     }
130 
131     /**
132      * Template method to destroy any resources held by the Message Dispatcher
133      */
134     public final synchronized void dispose()
135     {
136         if (!disposed)
137         {
138             try
139             {
140                 try
141                 {
142                     this.disconnect();
143                 }
144                 catch (Exception e)
145                 {
146                     // TODO MULE-863: What should we really do?
147                     logger.warn(e.getMessage(), e);
148                 }
149 
150                 this.doDispose();
151             }
152             finally
153             {
154                 disposed = true;
155             }
156         }
157     }
158 
159     public Connector getConnector()
160     {
161         return connector;
162     }
163 
164     public ImmutableEndpoint getEndpoint()
165     {
166         return endpoint;
167     }
168 
169     public synchronized void connect() throws Exception
170     {
171         if (disposed)
172         {
173             throw new IllegalStateException("Requester/dispatcher has been disposed; cannot connect to resource");
174         }
175 
176         if (connected)
177         {
178             return;
179         }
180 
181         if (!connecting)
182         {
183             connecting = true;
184 
185             if (logger.isDebugEnabled())
186             {
187                 logger.debug("Connecting: " + this);
188             }
189 
190             connectionStrategy.connect(this);
191 
192             logger.info("Connected: " + this);
193             return;
194         }
195 
196         try
197         {
198             //Make sure the connector has connected. If it is connected, this method does nothing
199             connectionStrategy.connect(connector);
200 
201             this.doConnect();
202             connected = true;
203             connecting = false;
204 
205             connector.fireNotification(new ConnectionNotification(this, getConnectEventId(endpoint),
206                 ConnectionNotification.CONNECTION_CONNECTED));
207         }
208         catch (Exception e)
209         {
210             connected = false;
211             connecting = false;
212 
213             connector.fireNotification(new ConnectionNotification(this, getConnectEventId(endpoint),
214                 ConnectionNotification.CONNECTION_FAILED));
215 
216             if (e instanceof ConnectException)
217             {
218                 throw (ConnectException) e;
219             }
220             else
221             {
222                 throw new ConnectException(e, this);
223             }
224         }
225     }
226 
227     public synchronized void disconnect() throws Exception
228     {
229         if (!connected)
230         {
231             return;
232         }
233 
234         if (logger.isDebugEnabled())
235         {
236             logger.debug("Disconnecting: " + this);
237         }
238 
239         this.doDisconnect();
240         connected = false;
241 
242         logger.info("Disconnected: " + this);
243 
244         connector.fireNotification(new ConnectionNotification(this, getConnectEventId(endpoint),
245             ConnectionNotification.CONNECTION_DISCONNECTED));
246     }
247 
248     protected String getConnectEventId(ImmutableEndpoint endpoint)
249     {
250         return connector.getName() + ".dispatcher(" + endpoint.getEndpointURI().getUri() + ")";
251     }
252 
253     public final boolean isConnected()
254     {
255         return connected;
256     }
257 
258     protected boolean isDoThreading ()
259     {
260         return connector.getDispatcherThreadingProfile().isDoThreading();
261     }
262 
263     /**
264      * Returns a string identifying the underlying resource
265      *
266      * @return
267      */
268     public String getConnectionDescription()
269     {
270         return endpoint.getEndpointURI().toString();
271     }
272 
273     public synchronized void reconnect() throws Exception
274     {
275         disconnect();
276         connect();
277     }
278 
279     protected abstract void doDispose();
280 
281     protected abstract void doConnect() throws Exception;
282 
283     protected abstract void doDisconnect() throws Exception;
284 
285     //  @Override
286     public String toString()
287     {
288         final StringBuffer sb = new StringBuffer(80);
289         sb.append(ClassUtils.getSimpleName(this.getClass()));
290         sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
291         sb.append(", endpoint=").append(endpoint.getEndpointURI().getUri());
292         sb.append(", disposed=").append(disposed);
293         sb.append('}');
294         return sb.toString();
295     }
296 }