root/trunk/src/java/org/jcoderz/commons/connector/http/HttpConnectionImpl.java

Revision 1011, 14.2 kB (checked in by amandel, 4 years ago)

Aligned svn keyword settings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.commons.connector.http;
34
35import java.util.logging.Level;
36import java.util.logging.Logger;
37
38import javax.resource.ResourceException;
39
40import org.jcoderz.commons.connector.ConnectionRequestFailedException;
41import org.jcoderz.commons.connector.ConnectionResponseFailedException;
42import org.jcoderz.commons.connector.ConnectionTimeoutErrorException;
43import org.jcoderz.commons.connector.ConnectorConfiguration;
44import org.jcoderz.commons.connector.ConnectorException;
45import org.jcoderz.commons.connector.http.transport.ConnectorContext;
46import org.jcoderz.commons.connector.http.transport
47        .HttpClientConnectionException;
48import org.jcoderz.commons.connector.http.transport
49        .HttpConnectConnectionException;
50import org.jcoderz.commons.connector.http.transport.HttpConnectionException;
51import org.jcoderz.commons.connector.http.transport.HttpConnectorEventListener;
52import org.jcoderz.commons.connector.http.transport.HttpEmptyResponseException;
53import org.jcoderz.commons.connector.http.transport
54        .HttpInvalidResponseHeaderException;
55import org.jcoderz.commons.connector.http.transport.HttpRequestResponseHeader;
56import org.jcoderz.commons.connector.http.transport
57        .HttpServerConnectionException;
58import org.jcoderz.commons.connector.http.transport
59        .HttpTimeoutConnectionException;
60import org.jcoderz.commons.types.Url;
61import org.jcoderz.commons.util.Assert;
62
63
64
65
66/**
67 * Implementation of the HttpConnectionExtended interface.
68 * The implemented methods call the respective methods on
69 * the ManagedHttpConnection class.
70 *
71 */
72public final class HttpConnectionImpl
73      implements HttpConnectionExtended
74{
75   /** Class name used for logging. */
76   private static final String CLASSNAME
77         = HttpConnectionImpl.class.getName();
78   /** Logger in use. */
79   private static final Logger logger
80         = Logger.getLogger(CLASSNAME);
81   /** Handle to the physical connection. Null means connection is invalid. */
82   private HttpManagedConnectionImpl mManagedConnection;
83   /** Flag indicating if the physical connection is closed by the managed
84       connection - if true the connection is disassociated by the application
85       server. */
86   private boolean mClosedByManagedConnection = false;
87   /** Delay for retries in milli seconds. */
88   private int mRequiredDelay;
89   /** Flag indicating that a delay for retries is necessary. */
90   private boolean mIsRetryRequired = false;
91   private final ConnectorConfiguration mConfig;
92
93
94   /**
95    * Constructor.
96    * Sets the calling ManagedPaymentProtocolConnection object.
97    *
98    * @param mc the managed connection creating this object
99    */
100   public HttpConnectionImpl (HttpManagedConnectionImpl mc)
101   {
102      mManagedConnection = mc;
103      mConfig = ConfigurationFactory.getConfiguration();
104   }
105
106   /** {@inheritDoc} */
107   public byte[] sendAndReceive (byte[] message)
108         throws ResourceException, ConnectorException
109   {
110      final String methodName = "sendAndReceive";
111      if (logger.isLoggable(Level.FINER))
112      {
113         logger.entering(CLASSNAME, methodName);
114      }
115      Assert.notNull(message, "message");
116
117      mIsRetryRequired = false;
118      byte[] result = null;
119      try
120      {
121         result = getManagedConnection().sendAndReceive(message);
122      }
123      catch (HttpClientConnectionException hce)
124      {
125         handleClientConnectionException(hce);
126      }
127      catch (HttpServerConnectionException hse)
128      {
129         handleServerConnectionException(hse);
130      }
131      catch (HttpConnectConnectionException hce)
132      {
133         handleConnectConnectionException(hce);
134      }
135      catch (HttpTimeoutConnectionException hte)
136      {
137         handleTimeoutConnectionException(hte);
138      }
139      catch (HttpInvalidResponseHeaderException hie)
140      {
141         handleInvalidResponseHeaderException(hie);
142      }
143      catch (HttpEmptyResponseException ere)
144      {
145         handleEmptyResponseException(ere);
146      }
147      catch (HttpConnectionException he)
148      {
149         handleConnectionException(he);
150      }
151
152      if (logger.isLoggable(Level.FINER))
153      {
154         logger.exiting(CLASSNAME, methodName, result);
155      }
156      return result;
157   }
158
159   /** {@inheritDoc} */
160   public void setRequestResponseHeader (HttpRequestResponseHeader header)
161         throws ResourceException
162   {
163      getManagedConnection().setRequestResponseHeader(header);
164   }
165
166   /** {@inheritDoc} */
167   public void setEventListener (HttpConnectorEventListener listener,
168         ConnectorContext context)
169   {
170      getManagedConnection().setEventListener(listener, context);
171   }
172
173   private void handleClientConnectionException (HttpConnectionException ex)
174         throws ConnectionResponseFailedException
175   {
176      logger.finer("Handling 'ClientConnectionException' " + ex.getMessage());
177      if (mConfig.getHttpClientErrorResendFlag())
178      {
179         mIsRetryRequired = true;
180         mRequiredDelay = mConfig.getHttpClientErrorResendDelayInMilliSeconds();
181      }
182      final ConnectionResponseFailedException cre
183            = new ConnectionResponseFailedException(getUrl(), ex);
184      invalidateManagedConnection(cre);
185      throw cre;
186   }
187
188   private void handleServerConnectionException (HttpConnectionException ex)
189         throws ConnectionResponseFailedException
190   {
191      logger.finer("Handling 'ServerConnectionException' " + ex.getMessage());
192      if (mConfig.getHttpServerErrorResendFlag())
193      {
194         mIsRetryRequired = true;
195         mRequiredDelay
196               = mConfig.getHttpServerErrorResendDelayInMilliSeconds();
197      }
198      final ConnectionResponseFailedException cre
199            = new ConnectionResponseFailedException(getUrl(), ex);
200      invalidateManagedConnection(cre);
201      throw cre;
202   }
203
204   private void handleConnectConnectionException (HttpConnectionException ex)
205         throws ConnectionRequestFailedException
206   {
207      logger.finer("Handling 'ConnectConnectionException' " + ex.getMessage());
208      final ConnectionRequestFailedException cre
209            = new ConnectionRequestFailedException(getUrl(), ex);
210      invalidateManagedConnection(cre);
211      throw cre;
212   }
213
214   private void handleTimeoutConnectionException (HttpConnectionException ex)
215         throws ConnectionTimeoutErrorException
216   {
217      logger.finer("Handling 'TimeoutConnectionException' " + ex.getMessage());
218      if (mConfig.getHttpReadTimeoutErrorResendFlag())
219      {
220         mIsRetryRequired = true;
221         mRequiredDelay
222               = mConfig.getHttpReadTimeoutErrorResendDelayInMilliSeconds();
223      }
224      mIsRetryRequired = true;
225      final StringBuffer previousFailure = new StringBuffer();
226      previousFailure.append(ex.toString());
227      final Throwable cause = ex.getCause();
228      if (cause != null)
229      {
230         previousFailure.append(" caused by ");
231         previousFailure.append(cause.toString());
232      }
233      final ConnectionTimeoutErrorException cte
234            = new ConnectionTimeoutErrorException(
235                  getUrl(), previousFailure.toString(), ex);
236      invalidateManagedConnection(cte);
237      throw cte;
238   }
239
240   private void handleInvalidResponseHeaderException (
241         HttpConnectionException ex)
242         throws ConnectionResponseFailedException
243   {
244      logger.finer("Handling 'InvalidResponseHeaderException' "
245            + ex.getMessage());
246      mIsRetryRequired = false;
247      final ConnectionResponseFailedException cre
248            = new ConnectionResponseFailedException(getUrl(), ex);
249      invalidateManagedConnection(cre);
250      throw cre;
251   }
252
253   private void handleEmptyResponseException (
254         HttpConnectionException ex)
255         throws ConnectionResponseFailedException
256   {
257      logger.finer("Handling 'HttpEmptyResponseException' "
258            + ex.getMessage());
259      mIsRetryRequired = false;
260      final ConnectionResponseFailedException cre
261            = new ConnectionResponseFailedException(getUrl(), ex);
262      invalidateManagedConnection(cre);
263      throw cre;
264   }
265
266   private void handleConnectionException (HttpConnectionException ex)
267         throws ConnectionRequestFailedException
268   {
269      // TODO: retry policy for the "other" errors
270      //    like a server closing whilst sending the request..
271      logger.finer("Handling 'ConnectionException' " + ex.getMessage());
272      mIsRetryRequired = false;
273      final ConnectionRequestFailedException cre
274            = new ConnectionRequestFailedException(getUrl(), ex);
275      invalidateManagedConnection(cre);
276      throw cre;
277   }
278
279   /** {@inheritDoc} */
280   public void close ()
281   {
282      final String methodName = "close";
283      logger.entering(CLASSNAME, methodName);
284
285      // In case that the Connector detects an error on the
286      // HttpManagedConnection, it has the duty to notify the
287      // application server by calling the
288      // notifyAboutConnectionErrorOccurred() callback. In this case, the
289      // application server will call cleanup() on the HttpManagedConnection to
290      // disassociate its connection handle. We can recognize that, as
291      // mClosedByManagedConnection will be set.
292      if (mManagedConnection == null && mClosedByManagedConnection)
293      {
294         // Connection handle already released by application server;
295         // Doesn't need an explicit close().
296         // trace message
297         logger.finer("connection already closed by application server");
298         //
299      }
300      else if (mManagedConnection == null && !mClosedByManagedConnection)
301      {
302         // trace message
303         logger.finer("connection already closed");
304         //
305      }
306      else
307      {
308         // Notify the HttpManagedConnection that this connection handle no
309         // longer belongs to the HttpManagedConnection.
310         getManagedConnection().disassociateConnection(this);
311          // Notify all registered EventListeners (Application Server) that
312         // this connection handle was closed.
313         getManagedConnection().notifyAboutConnectionClosed(this);
314          // Disassociate this connection handle by forgetting to which
315         // HttpManagedConnection we belong. This connection handle is
316         // now invalid.
317         disassociateManagedConnection(false);
318      }
319      logger.exiting(CLASSNAME, methodName);
320   }
321
322   /**
323    * Gets the associated ManagedConnection.
324    *
325    * @return the HttpManagedConnectionImpl
326    * @throws IllegalStateException - if the managed connection handle
327    *          is not set
328    */
329   protected HttpManagedConnectionImpl getManagedConnection ()
330         throws IllegalStateException
331   {
332      if (mManagedConnection == null)
333      {
334         final String errorText = "Connection handle is invalid.";
335         final IllegalStateException ise = new IllegalStateException(errorText);
336         throw ise;
337      }
338      return mManagedConnection;
339   }
340
341   /**
342    * <p>Associate a different physical connection to this user-level
343    * connection.</p>
344    * <p>Called by the AbstractManagedConnection if transaction boundaries
345    * are crossed.</p>
346    *
347    * @param mc new physical connection instance
348    * @throws ResourceException - like defined in the interface
349    */
350   protected void associateManagedConnection (HttpManagedConnectionImpl mc)
351   {
352      mManagedConnection = mc;
353   }
354
355   /**
356    * Disassociate this connection handle by forgetting to which
357    * ManagedConnection we belong. This connection handle is
358    * now invalid.
359    *
360    * @param closedByManagedConnection flag indicates if this managed
361    *          connnection is closed by itself
362    */
363   public void disassociateManagedConnection (boolean closedByManagedConnection)
364   {
365      if (closedByManagedConnection)
366      {
367         logger.finest("disassociated by ManagedConnection");
368      }
369      else
370      {
371         logger.finest("disassociated by Connection");
372      }
373
374      mClosedByManagedConnection = closedByManagedConnection;
375      mManagedConnection = null;
376   }
377
378   /**
379    * Disassociates the connection and marks it as broken.
380    */
381   private void invalidateManagedConnection (final Exception cause)
382   {
383      getManagedConnection().disassociateConnection(this);
384      getManagedConnection().notifyAboutConnectionErrorOccurred(
385            cause, this);
386      disassociateManagedConnection(false);
387   }
388
389   private Url getUrl ()
390   {
391      return getManagedConnection().getUrl();
392   }
393
394   /**
395    * Gets the time in milli seconds required if another retry
396    * will be performed.
397    *
398    * @return int
399    *          the delay to use in HttpConnecionImpl
400    */
401   public int getRequiredDelayForRetries ()
402   {
403      return mRequiredDelay;
404   }
405
406   /**
407    * Gets the flag indicating that a retry is required if
408    * max number of retries is not exceeded.
409    * @return boolean
410    *          if true perform retry - else not
411    */
412   public boolean isRetryRequired ()
413   {
414      return mIsRetryRequired;
415   }
416}
Note: See TracBrowser for help on using the browser.