You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by sc...@apache.org on 2009/12/07 18:52:29 UTC

svn commit: r888050 - in /webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws: binding/BindingImpl.java handler/HandlerChainProcessor.java

Author: scheu
Date: Mon Dec  7 17:52:29 2009
New Revision: 888050

URL: http://svn.apache.org/viewvc?rev=888050&view=rev
Log:
AXIS2-4576
Contributor: Rich Scheuerle
Avoid ConcurrentModificationExcetion during Handler Chain Processing
Plus additional debug trace.

Modified:
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/binding/BindingImpl.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/binding/BindingImpl.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/binding/BindingImpl.java?rev=888050&r1=888049&r2=888050&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/binding/BindingImpl.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/binding/BindingImpl.java Mon Dec  7 17:52:29 2009
@@ -29,18 +29,24 @@
 import org.apache.axis2.jaxws.registry.ClientConfiguratorRegistry;
 import org.apache.axis2.jaxws.spi.Binding;
 import org.apache.axis2.jaxws.spi.BindingProvider;
+import org.apache.axis2.jaxws.utility.JavaUtils;
 
 import javax.xml.ws.WebServiceFeature;
 import javax.xml.ws.handler.Handler;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
 /**
  * Classes that would normally "implement javax.xml.ws.Binding"
  * should extend this class instead.
  */
 public abstract class BindingImpl implements Binding {
+    
+    private static final Log log = LogFactory.getLog(BindingImpl.class);
+    
     // an unsorted list of handlers
     private List<Handler> handlers;
 
@@ -79,7 +85,12 @@
         if (handlers == null) {
             // non-null so client apps can manipulate
             handlers =
-                    new HandlerResolverImpl(endpointDesc.getServiceDescription()).getHandlerChain(endpointDesc.getPortInfo());
+                    new HandlerResolverImpl(endpointDesc.getServiceDescription()).
+                        getHandlerChain(endpointDesc.getPortInfo());
+            if (log.isDebugEnabled()) {
+                log.debug("handers list constructed from HandlerResolverImpl.  The list is:" + 
+                        JavaUtils.getObjectIdentity(handlers));
+            }
         }
         return handlers;
     }
@@ -89,7 +100,19 @@
         if (list == null) {
             handlers = new ArrayList<Handler>(); // non-null, but rather
                                                     // empty
+            if (log.isDebugEnabled()) {
+                log.debug("setHandlerChain called with a null list.  " +
+                        "A empty list is created:" + JavaUtils.getObjectIdentity(handlers));
+            }
         } else {
+            // Use the handler list provided by the caller.
+            // The JAX-WS runtime nor user should ever modify this list or a ConcurrentModificationException 
+            // may occur.
+            // @see org.apache.axis2.jaxws.handler.HandlerChainProcessor which makes a copy of
+            // the handler chain to avoid potential CMEs.
+            if (log.isDebugEnabled()) {
+                log.debug("setHandlerChain called with a list:" + JavaUtils.getObjectIdentity(list));
+            }
             this.handlers = list;
         }
     }

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java?rev=888050&r1=888049&r2=888050&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java Mon Dec  7 17:52:29 2009
@@ -70,7 +70,9 @@
 
     private MEPContext mepCtx;
 
+    // Copy of the handler chain used by HandlerChainProcessor
     private List<Handler> handlers = null;
+    private static final List<Handler> EMPTY_CHAIN = new ArrayList<Handler>(); 
     
     // for tracking purposes -- see trackInternalCall
     private static Handler currentHandler = null;
@@ -103,28 +105,43 @@
     private static boolean saaj_called = false;
 
     /*
-      * HandlerChainProcess expects null, empty list, or an already-sorted
-      * list.  If the chain passed into here came from our HandlerChainResolver,
-      * it is sorted already.  If a client app created or manipulated the list,
-      * it may not be sorted.  The processChain and processFault methods check
-      * for this by calling verifyChain.
+     * The HandlerChainProcessor is constructed with the handler chain.
+     * The handler chain may be null, empty or already sorted.
+     * It also may be shared.  For this reason a copy of chain is made
+     * so that the sort and other manipulation does not affect the original
+     * chain.
+     * @param chain Handler chain
+     * @param proto Protocol
       */
 	public HandlerChainProcessor(List<Handler> chain, Protocol proto) {
-        if (chain == null) {
-            handlers = new ArrayList<Handler>();
-		}
-		else
-            handlers = chain;
+	    if (chain != null) {
+            synchronized (chain) {
+                if (chain.size() == 0) {
+                    // Use empty chain to avoid excessive garbage collection
+                    this.handlers = EMPTY_CHAIN;
+                } else {
+                    this.handlers = new ArrayList<Handler>(); 
+                    this.handlers.addAll(chain);
+                }
+            }
+        } else {
+            handlers = EMPTY_CHAIN;
+        }
         this.proto = proto;
     }
 
-    /*
-      * sortChain will properly sort the chain, logical then protocol, since it may be
-      * a chain built or modified by a client application.  Also keep track of
-      * start/end for each type of handler.
-      */
+	/*
+	 * sortChain sorts the local copy of the handlers chain.
+	 * The logical handlers are first followed by the protocol handlers.
+	 * sortChain also keeps track of the start/end of each type of handler.
+	 */
 	private void sortChain() throws WebServiceException {
         
+        if (handlers.size() == 0) {
+            logicalLength = 0;
+            return;
+        }
+        
         ArrayList<Handler> logicalHandlers = new ArrayList<Handler>();
         ArrayList<Handler> protocolHandlers = new ArrayList<Handler>();