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 ro...@apache.org on 2007/06/25 21:39:23 UTC

svn commit: r550586 - in /webservices/axis2/trunk/java/modules/jaxws: src/org/apache/axis2/jaxws/ src/org/apache/axis2/jaxws/client/ src/org/apache/axis2/jaxws/client/proxy/ src/org/apache/axis2/jaxws/core/ src/org/apache/axis2/jaxws/core/controller/ s...

Author: rott
Date: Mon Jun 25 12:39:19 2007
New Revision: 550586

URL: http://svn.apache.org/viewvc?view=rev&rev=550586
Log:
Properties were being defaulted to HANDLER scope, which hides them from endpoints and client apps.  Now when properties are copied through a property migrator, they have APPLICATION scope, which allows access by client apps and endpoints

Modified:
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/BindingProvider.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/PropertyMigrator.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MEPContext.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MessageContext.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/InvocationController.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/handler/HandlerChainProcessor.java
    webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/spi/migrator/ApplicationContextMigratorUtil.java
    webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/BindingProvider.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/BindingProvider.java?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/BindingProvider.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/BindingProvider.java Mon Jun 25 12:39:19 2007
@@ -199,6 +199,9 @@
 
         @Override
         public synchronized Object put(String key, Object value) {
+            // super.put rightly throws a NullPointerException if key or value is null, so don't continue if that's the case
+            if (value == null)
+                return null;
             if (PropertyValidator.validate(key, value)) {
                 return super.put(key, value);
             } else {

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/PropertyMigrator.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/PropertyMigrator.java?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/PropertyMigrator.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/PropertyMigrator.java Mon Jun 25 12:39:19 2007
@@ -18,17 +18,10 @@
  */
 package org.apache.axis2.jaxws.client;
 
-import org.apache.axis2.jaxws.ExceptionFactory;
-import org.apache.axis2.jaxws.core.MEPContext;
 import org.apache.axis2.jaxws.core.MessageContext;
 import org.apache.axis2.jaxws.spi.migrator.ApplicationContextMigrator;
 
-import javax.xml.ws.handler.MessageContext.Scope;
-
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.Map.Entry;
 
 /**
  * The PropertyMigrator implements the ApplicationContextMigrator in order to perform the necessary
@@ -38,57 +31,12 @@
 
     public void migratePropertiesFromMessageContext(Map<String, Object> userContext,
                                                     MessageContext messageContext) {
-
-        // TODO: we don't want to copy all of the properties to the userContext, just the APPLICATION scoped ones
-        MessageContext requestMC = messageContext.getMEPContext().getRequestMessageContext();
-        MessageContext responseMC = messageContext.getMEPContext().getResponseMessageContext();
-        // sanity check
-        if ((requestMC != messageContext) && (responseMC != messageContext))  // object check, not .equals()
-            // an exception that should never happen nor be exposed to a user, but it certainly helps us debug
-            throw ExceptionFactory.makeWebServiceException("The MessageContext from which we are copying properties does not match the MessageContext in the MEP");
-        else if (requestMC == null)
-            // TODO also not an exception to expose to a user
-            throw ExceptionFactory.makeWebServiceException("The MessageContext from which we are copying properties is null.");
-
-        HashMap<String, Object> mergedProperties = new HashMap<String, Object>();
-        // responseMC properties take priority since they are used later in the MEP
-        mergedProperties.putAll(requestMC.getProperties());
-        if (responseMC != null)
-            mergedProperties.putAll(responseMC.getProperties());
-        
-        for(Iterator it = mergedProperties.entrySet().iterator();it.hasNext();) {
-            Entry<String, Object> entry = (Entry<String, Object>)it.next();
-            /*
-             * Call getScope on the MEPContext so it will check both MCs on the MEPMC.
-             * Client apps are permitted to see APPLICATION scoped properties that were
-             * set on or changed to APPLICATION scope on the outbound and inbound flows.
-             */
-            Scope scope = (Scope)messageContext.getMEPContext().getScope(entry.getKey());
-            if ((scope != null) && (scope.equals(Scope.APPLICATION))) {
-                userContext.put(entry.getKey(), entry.getValue());
-            }
-        }
-
+        userContext.putAll(messageContext.getProperties());
     }
 
     public void migratePropertiesToMessageContext(Map<String, Object> userContext,
                                                   MessageContext messageContext) {
-
-        /*
-         * TODO JAXWS 4.2.1 Request section:  should I be setting all props to HANDLER scope?
-         * The CTS has a test where a prop is set on the request ctx by a client app, then
-         * later that prop is retrieved.  This indicates to me that props set by a client app
-         * would be APPLICATION scoped, and the CTS seems to confirm this, in spite of the spec.
-         * I'm choosing to conform to the CTS rather than the spec on this one.
-         */
-        messageContext.getProperties().putAll(userContext);
-        if (messageContext.getMEPContext() == null) {
-            messageContext.setMEPContext(new MEPContext(messageContext));
-        }
-        for(Iterator it = userContext.keySet().iterator();it.hasNext();) {
-            messageContext.getMEPContext().setScope((String)it.next(), Scope.APPLICATION);
-        }
-
+        messageContext.setProperties(userContext);
     }
 
 }

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java Mon Jun 25 12:39:19 2007
@@ -183,11 +183,6 @@
         // be sure to use whatever handlerresolver is registered on the Service
         requestIC.setHandlers(bnd.getHandlerChain());
 
-        // Before we invoke, copy all of the properties from the client request
-        // context to the MessageContext
-        // TODO: Add the plug point for property migration
-        request.getProperties().putAll(getRequestContext());
-
         requestIC.setRequestMessageContext(request);
         requestIC.setServiceClient(serviceDelegate.getServiceClient(endpointDesc.getPortQName()));
 
@@ -334,7 +329,7 @@
         request.setMessage(message);
 
         // TODO: What happens here might be affected by the property migration plugpoint.  
-        request.getProperties().putAll(getRequestContext());
+        request.setProperties(getRequestContext());
 
         if (log.isDebugEnabled()) {
             log.debug("Request MessageContext created successfully.");

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MEPContext.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MEPContext.java?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MEPContext.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MEPContext.java Mon Jun 25 12:39:19 2007
@@ -16,7 +16,6 @@
  */
 package org.apache.axis2.jaxws.core;
 
-import org.apache.axis2.jaxws.ExceptionFactory;
 import org.apache.axis2.jaxws.description.EndpointDescription;
 import org.apache.axis2.jaxws.message.Message;
 
@@ -108,8 +107,10 @@
     
     public Scope getScope(String s) {
         if (scopes.get(s) == null) {
-            // JAX-WS default 9.4.1
-            return Scope.HANDLER;
+            // JAX-WS default 9.4.1.  However, we try to set the scope for
+            // every incoming property to HANDLER.  If a property is coming from
+            // the axis2 Options bag, we want those to be APPLICATION scoped.
+            return Scope.APPLICATION;
         }
         return scopes.get(s);
     }
@@ -223,24 +224,32 @@
     public Object put(String key, Object value) {
         // TODO careful:  endpoints may overwrite pre-existing key/value pairs.
         // Those key/value pairs may already have a scope attached to them, which
-        // means an endpoint could "put" a property and immediately do a "get" which
-        // would return null.
+        // means an endpoint could "put" a property that is wrongly scoped
+        if (scopes.get(key) == null) {  // check the scopes object directly, not through getScope()!!
+            setScope(key, Scope.HANDLER);
+        }
         if (requestMC.getProperties().containsKey(key)) {
-            return requestMC.getProperties().put(key, value);
+            return requestMC.setProperty(key, value);
         }
         if (responseMC != null) {
-            return responseMC.getProperties().put(key, value);
+            return responseMC.setProperty(key, value);
         }
-        return requestMC.getProperties().put(key, value);
+        return requestMC.setProperty(key, value);
     }
 
     public void putAll(Map t) {
         // TODO similar problem as "put"
+        for(Iterator it = t.entrySet().iterator(); it.hasNext();) {
+            Entry<String, Object> entry = (Entry)it.next();
+            if (getScope(entry.getKey()) == null) {
+                setScope(entry.getKey(), Scope.HANDLER);
+            }
+        }
         if (responseMC != null) {
-            responseMC.getProperties().putAll(t);
+            responseMC.setProperties(t);
         }
         else {
-            requestMC.getProperties().putAll(t);
+            requestMC.setProperties(t);
         }
     }
 
@@ -330,7 +339,7 @@
      * 
      * @return
      */
-    private Map<String, Object> getApplicationScopedProperties() {
+    public Map<String, Object> getApplicationScopedProperties() {
         Map<String, Object> tempMap = new HashMap<String, Object>();
         // better performance:
         if (!scopes.containsValue(Scope.APPLICATION)) {

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MessageContext.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MessageContext.java?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MessageContext.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/MessageContext.java Mon Jun 25 12:39:19 2007
@@ -18,7 +18,6 @@
  */
 package org.apache.axis2.jaxws.core;
 
-import javax.xml.ws.handler.MessageContext.Scope;
 import org.apache.axis2.description.AxisService;
 import org.apache.axis2.jaxws.description.EndpointDescription;
 import org.apache.axis2.jaxws.description.OperationDescription;
@@ -31,6 +30,10 @@
 import javax.xml.ws.WebServiceException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
 
 /**
  * The <code>org.apache.axis2.jaxws.core.MessageContext</code> is an interface that extends the
@@ -54,6 +57,10 @@
     private Message message;
     private Mode mode;
     
+    // TODO:  flag to set whether we delegate property setting up to the
+    // axis2 options objecct or keep it local
+    private boolean DELEGATE_TO_OPTIONS = true;
+    
     /*
      * JAXWS runtime uses a request and response mc, but we need to know the pair.
      * We will use this mepCtx as a wrapper to the request and response message contexts
@@ -68,11 +75,15 @@
 
     public MessageContext() {
         axisMsgCtx = new org.apache.axis2.context.MessageContext();
-        properties = new HashMap<String, Object>();
+        if (!DELEGATE_TO_OPTIONS) {
+            properties = new HashMap<String, Object>();
+        }
+           
     }
-
     public MessageContext(org.apache.axis2.context.MessageContext mc) throws WebServiceException {
-        properties = new HashMap<String, Object>();
+        if (!DELEGATE_TO_OPTIONS) {
+            properties = new HashMap<String, Object>();
+        }
 
         /*
          * Instead of creating a member MEPContext object every time, we will
@@ -100,8 +111,37 @@
     }
 
     public Map<String, Object> getProperties() {
+        if (DELEGATE_TO_OPTIONS) {
+            return new ReadOnlyProperties(axisMsgCtx.getOptions().getProperties());
+        }
         return properties;
     }
+    
+    public void setProperties(Map<String, Object> _properties) {
+        if (DELEGATE_TO_OPTIONS) {
+            axisMsgCtx.getOptions().setProperties(_properties);
+        } else {
+            getProperties().putAll(_properties);
+        }
+    }
+    
+    public Object getProperty(String key) {
+        if (DELEGATE_TO_OPTIONS) {
+            return axisMsgCtx.getOptions().getProperty(key);
+        }
+        return getProperties().get(key);
+    }
+    
+    // acts like Map.put(key, value)
+    public Object setProperty(String key, Object value) {
+        if (DELEGATE_TO_OPTIONS) {
+            Object retval = axisMsgCtx.getOptions().getProperty(key);
+            axisMsgCtx.getOptions().setProperty(key, value);
+            return retval;
+        } else {
+            return getProperties().put(key, value);
+        }
+    }
 
     public EndpointDescription getEndpointDescription() {
         return endpointDesc;
@@ -166,7 +206,7 @@
     public boolean isMaintainSession() {
         boolean maintainSession = false;
 
-        Boolean value = (Boolean)properties.get(BindingProvider.SESSION_MAINTAIN_PROPERTY);
+        Boolean value = (Boolean) getProperties().get(BindingProvider.SESSION_MAINTAIN_PROPERTY);
         if (value != null && value.booleanValue()) {
             maintainSession = true;
         }
@@ -205,12 +245,208 @@
      * @param mepCtx
      */
     public void setMEPContext(MEPContext mepCtx) {
-        this.mepCtx = mepCtx;
-        // and set parent's child pointer
-        this.mepCtx.setResponseMessageContext(this);
+        if (this.mepCtx == null) {
+            this.mepCtx = mepCtx;
+            // and set parent's child pointer
+            this.mepCtx.setResponseMessageContext(this);
+        }
     }
 
     public MEPContext getMEPContext() {
+        if (mepCtx == null) {
+            setMEPContext(new MEPContext(this));
+        }
         return mepCtx;
+    }
+    
+    private class ReadOnlyProperties extends AbstractMap<String, Object> {
+        
+        private Map<String, Object> containedProps;
+        
+        public ReadOnlyProperties(Map containedProps) {
+            this.containedProps = containedProps;
+        }
+
+        @Override
+        public Set<Entry<String, Object>> entrySet() {
+            return new ReadOnlySet(containedProps.entrySet());
+        }
+
+        @Override
+        public Set<String> keySet() {
+            return new ReadOnlySet(containedProps.keySet());
+        }
+
+        @Override
+        public Object put(String key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void putAll(Map<? extends String, ? extends Object> t) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Object remove(Object key) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Collection<Object> values() {
+            return new ReadOnlyCollection(containedProps.values());
+        }
+        
+        /*
+         * nested classes to be used to enforce read-only Collection, Set, and Iterator for MEPContext
+         */
+        
+        class ReadOnlyCollection implements Collection {
+            
+            private Collection containedCollection;
+            
+            private ReadOnlyCollection(Collection containedCollection) {
+                this.containedCollection = containedCollection;
+            }
+            
+            public boolean add(Object o) {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean addAll(Collection c) {
+                throw new UnsupportedOperationException();
+            }
+
+            public void clear() {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean contains(Object o) {
+                return containedCollection.contains(o);
+            }
+
+            public boolean containsAll(Collection c) {
+                return containedCollection.containsAll(c);
+            }
+
+            public boolean isEmpty() {
+                return containedCollection.isEmpty();
+            }
+
+            public Iterator iterator() {
+                return new ReadOnlyIterator(containedCollection.iterator());
+            }
+
+            public boolean remove(Object o) {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean removeAll(Collection c) {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean retainAll(Collection c) {
+                throw new UnsupportedOperationException();
+            }
+
+            public int size() {
+                return containedCollection.size();
+            }
+
+            public Object[] toArray() {
+                return containedCollection.toArray();
+            }
+
+            public Object[] toArray(Object[] a) {
+                return containedCollection.toArray(a);
+            }
+
+        }
+        
+        class ReadOnlyIterator implements Iterator {
+            
+            private Iterator containedIterator;
+            
+            private ReadOnlyIterator(Iterator containedIterator) {
+                this.containedIterator = containedIterator;
+            }
+            
+            // override remove() to make this Iterator class read-only
+            
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean hasNext() {
+                return containedIterator.hasNext();
+            }
+
+            public Object next() {
+                return containedIterator.next();
+            }
+        }
+        
+        class ReadOnlySet implements Set {
+
+            private Set containedSet;
+            
+            private ReadOnlySet(Set containedSet) {
+                this.containedSet = containedSet;
+            }
+            
+            public boolean add(Object o) {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean addAll(Collection c) {
+                throw new UnsupportedOperationException();
+            }
+
+            public void clear() {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean contains(Object o) {
+                return containedSet.contains(o);
+            }
+
+            public boolean containsAll(Collection c) {
+                return containedSet.containsAll(c);
+            }
+
+            public boolean isEmpty() {
+                return containedSet.isEmpty();
+            }
+
+            public Iterator iterator() {
+                return new ReadOnlyIterator(containedSet.iterator());
+            }
+
+            public boolean remove(Object o) {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean removeAll(Collection c) {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean retainAll(Collection c) {
+                throw new UnsupportedOperationException();
+            }
+
+            public int size() {
+                return containedSet.size();
+            }
+
+            public Object[] toArray() {
+                return containedSet.toArray();
+            }
+
+            public Object[] toArray(Object[] a) {
+                return containedSet.toArray(a);
+            }
+            
+        }
+        
     }
 }

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/InvocationController.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/InvocationController.java?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/InvocationController.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/core/controller/InvocationController.java Mon Jun 25 12:39:19 2007
@@ -16,17 +16,13 @@
  */
 package org.apache.axis2.jaxws.core.controller;
 
-import javax.xml.ws.WebServiceException;
-import org.apache.axis2.AxisFault;
 import org.apache.axis2.jaxws.ExceptionFactory;
 import org.apache.axis2.jaxws.core.InvocationContext;
 import org.apache.axis2.jaxws.core.MessageContext;
 import org.apache.axis2.jaxws.core.util.MessageContextUtils;
 import org.apache.axis2.jaxws.handler.HandlerChainProcessor;
 import org.apache.axis2.jaxws.handler.HandlerInvokerUtils;
-import org.apache.axis2.jaxws.handler.HandlerResolverImpl;
 import org.apache.axis2.jaxws.i18n.Messages;
-import org.apache.axis2.jaxws.message.util.XMLFaultUtils;
 import org.apache.axis2.jaxws.util.Constants;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -91,7 +87,7 @@
         MessageContext request = ic.getRequestMessageContext();
         MessageContext response = null;
 
-        request.getProperties().put(Constants.INVOCATION_PATTERN, InvocationPattern.SYNC);
+        request.setProperty(Constants.INVOCATION_PATTERN, InvocationPattern.SYNC);
 
         // Invoke outbound handlers.
         boolean success =
@@ -134,7 +130,8 @@
                     // we've reversed directions
             response = MessageContextUtils.createMinimalResponseMessageContext(request);
             // since we've reversed directions, the message has "become a
-            // response message" (section 9.3.2.1, footnote superscript 2)
+            // make sure request and response contexts share a single parent
+            response.setMEPContext(request.getMEPContext());
             response.setMessage(request.getMessage());
         }
         ic.setResponseMessageContext(response);
@@ -166,7 +163,7 @@
         }
 
         MessageContext request = ic.getRequestMessageContext();
-        request.getProperties().put(Constants.INVOCATION_PATTERN, InvocationPattern.ONEWAY);
+        request.setProperty(Constants.INVOCATION_PATTERN, InvocationPattern.ONEWAY);
 
         // Invoke outbound handlers.
         boolean success =
@@ -208,7 +205,7 @@
         }
 
         MessageContext request = ic.getRequestMessageContext();
-        request.getProperties().put(Constants.INVOCATION_PATTERN, InvocationPattern.ASYNC_POLLING);
+        request.setProperty(Constants.INVOCATION_PATTERN, InvocationPattern.ASYNC_POLLING);
 
         Response resp = null;
 
@@ -270,7 +267,7 @@
         }
 
         MessageContext request = ic.getRequestMessageContext();
-        request.getProperties().put(Constants.INVOCATION_PATTERN, InvocationPattern.ASYNC_CALLBACK);
+        request.setProperty(Constants.INVOCATION_PATTERN, InvocationPattern.ASYNC_CALLBACK);
 
         Future<?> future = null;
 

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?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- 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 Jun 25 12:39:19 2007
@@ -269,10 +269,11 @@
                 // it's a response, so we can safely assume that 
                 // ALL the handlers were invoked on the request,
                 // so we need to close ALL of them
-                if (direction.equals(Direction.IN))
+                if (direction.equals(Direction.IN)) {
                     callCloseHandlers(handlers.size() - 1, 0, direction);
-                else
+                } else {
                     callCloseHandlers(0, handlers.size() - 1, direction);
+                }
                 if (savedException != null) {
                     // we have a saved exception, throw it (JAX-WS 9.3.2.1 "Throw any
                     // other runtime exception --> No response" case.
@@ -488,8 +489,8 @@
             throw ExceptionFactory.makeWebServiceException(ex);
         }
 
-	}
-    
+    }
+
 
     private void initContext(Direction direction) {
         soapMC = MessageContextFactory.createSoapMessageContext(mepCtx.getMessageContext());

Modified: webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/spi/migrator/ApplicationContextMigratorUtil.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/spi/migrator/ApplicationContextMigratorUtil.java?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/spi/migrator/ApplicationContextMigratorUtil.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/src/org/apache/axis2/jaxws/spi/migrator/ApplicationContextMigratorUtil.java Mon Jun 25 12:39:19 2007
@@ -20,7 +20,9 @@
 
 import org.apache.axis2.context.ConfigurationContext;
 import org.apache.axis2.jaxws.ExceptionFactory;
+import org.apache.axis2.jaxws.core.MEPContext;
 import org.apache.axis2.jaxws.core.MessageContext;
+import org.apache.axis2.jaxws.core.util.MessageContextUtils;
 import org.apache.axis2.jaxws.description.ServiceDescription;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -29,6 +31,13 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Map.Entry;
+import javax.xml.ws.handler.MessageContext.Scope;
 
 public class ApplicationContextMigratorUtil {
 
@@ -127,9 +136,263 @@
                         log.debug("migrator: " + cpm.getClass().getName() +
                                 ".migratePropertiesFromMessageContext");
                     }
-                    cpm.migratePropertiesFromMessageContext(responseContext, messageContext);
+                    cpm.migratePropertiesFromMessageContext(new ApplicationPropertyMapWriter(responseContext, messageContext.getMEPContext()), messageContext);
                 }
             }
         }
     }
+    
+
+    /**
+     *
+     * ApplicationPropertyMapReader is a wrapper for the SOURCE property map passed to individual
+     * property migrators.  When a property migrator copies properties from a request context map
+     * to a JAXWS MessageContext object, all of those properties should be marked APPLICATION
+     * scope so they can later be retrieved from the request context or response context
+     * in the client application.
+     *
+     * We override the EntrySet and Iterator to make sure the scope is properly set in the
+     * "request context to JAXWS message context" case where the property migrator uses
+     * get(String key) or putAll(Map source).  This is not guaranteed to be correct, however,
+     * because a property migrator could simply be doing a get(String key) to observe properties
+     * rather than copy them.  This just means we might be setting scope for a property that
+     * never actually makes its way into the JAXWS message context.  If someone (a hander,
+     * perhaps) later sets a property with the same key, its scope may be "pre-set" and
+     * therefore incorrect.
+     * 
+     * TODO:  find solution to above problem.  The MEPContext.put sets an explicit scope whenever
+     * a property is and a scope is not already present for that property.  An example
+     * of where this idea would produce unexpected results is where a scope was set to APPLICATION
+     * in the property migrator for key/value pair "myKey/someValue", but myKey never actually made
+     * it into the messagecontext.  Later a handler might put a "myKey/theHandlerValue".  In this
+     * case the scope was already set to APPLICATION and would therefore not be set by the
+     * MEPContext.put and therefore be incorrect.
+     *
+     * ApplicationPropertyMapReader only sets the scope if a migrator calls "get" on this map or
+     * iterates over the entrySet, which may occur explicitly in the migrator, or implicitly when
+     * this map is the source for a call such as otherMap.putAll(Map source).
+     *
+     * @author rott
+     *
+     */
+    private static class ApplicationPropertyMapReader extends HashMap<String, Object> {
+
+        private Map<String, Object> userMap;
+        private MEPContext mepCtx;
+        
+        public ApplicationPropertyMapReader(Map<String, Object> userMap, MEPContext mepCtx) {
+            this.userMap = userMap;
+            this.mepCtx = mepCtx;
+        }
+        
+        @Override
+        public Object put(String key, Object value) {
+            //mepCtx.setScope(key, Scope.APPLICATION);
+            return userMap.put(key, value);
+        }
+
+        @Override
+        public void putAll(Map<? extends String, ? extends Object> m) {
+            // we need to take advantage of the smarter put(String, Object)
+            for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
+                Entry entry = (Entry)it.next();
+                put((String)entry.getKey(), entry.getValue());
+            }
+        }
+        
+        @Override
+        public boolean containsKey(Object key) {
+            return userMap.containsKey(key);
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            return userMap.containsValue(value);
+        }
+
+        @Override
+        public Set entrySet() {
+            return new ApplicationPropertyMapEntrySet(userMap.entrySet(), mepCtx);
+        }
+
+        @Override
+        public Object get(Object key) {
+            // WARNING:  there's no real guarantee that the reason a migrator is getting
+            // a property is due to it being put on the MessageContext.
+            // We would therefore be setting scope for a property that never actually makes
+            // its way into the messageContext.
+            Object obj = userMap.get(key);
+            if (obj != null) {
+                mepCtx.setScope((String)key, Scope.APPLICATION);
+            }
+            return obj;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return userMap.isEmpty();
+        }
+
+        @Override
+        public Set keySet() {
+            return userMap.keySet();
+        }
+
+        @Override
+        public Object remove(Object key) {
+            return userMap.remove(key);
+        }
+
+        @Override
+        public int size() {
+            return userMap.size();
+        }
+
+        @Override
+        public Collection values() {
+            return userMap.values();
+        }
+        
+        private class ApplicationPropertyMapEntrySet extends AbstractSet {
+
+            Set containedSet;
+            MEPContext mepCtx;
+            
+            public ApplicationPropertyMapEntrySet(Set set, MEPContext mepCtx) {
+                containedSet = set;
+                this.mepCtx = mepCtx;
+            }
+            
+            @Override
+            public EntrySetIterator iterator() {
+                return new EntrySetIterator(containedSet.iterator(), mepCtx);
+            }
+
+            @Override
+            public int size() {
+                return containedSet.size();
+            }
+            
+        }
+        
+        private class EntrySetIterator implements Iterator {
+            
+            private Iterator containedIterator;
+            private MEPContext mepCtx;
+            
+            private EntrySetIterator(Iterator containedIterator, MEPContext mepCtx) {
+                this.containedIterator = containedIterator;
+                this.mepCtx = mepCtx;
+            }
+            
+            // override remove() to make this Iterator class read-only
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean hasNext() {
+                return containedIterator.hasNext();
+            }
+
+            public Object next() {
+                // WARNING:  there's no real guarantee that the reason a migrator is iterating
+                // over the properties is due to this being the source object for a putAll(source)
+                // We would therefore be setting scope for a property that never actually makes
+                // its way into the messageContext
+                Entry entry = (Entry)containedIterator.next();
+                mepCtx.setScope((String)entry.getKey(), Scope.APPLICATION);
+                return entry;
+            }
+        }
+     }
+    
+    /**
+     * ApplicationPropertyMapWriter is similar to the ApplicationPropertyMapReader in that it
+     * observes scope to determine what can be returned to a property migrator.  Individual
+     * property migrators should only be allowed to retrieve APPLICATION-scoped properties.
+     * 
+     * TODO:  There's quite a bit of expensive logic that would need to go into this to be
+     * fully correct.  For example, if a migrator calls size, we cannot simply return
+     * userMap.size().  Rather, we would have to count only the APPLICATION scoped properties
+     * and return those.
+     * 
+     * @author rott
+     *
+     */
+    private static class ApplicationPropertyMapWriter extends HashMap<String, Object> {
+
+        private Map<String, Object> userMap;
+        private MEPContext mepCtx;
+        
+        public ApplicationPropertyMapWriter(Map<String, Object> userMap, MEPContext mepCtx) {
+            this.userMap = userMap;
+            this.mepCtx = mepCtx;
+        }
+        
+        @Override
+        public Object put(String key, Object value) {
+            // notice the logic here!  We won't put a property on the userMap that is not APPLICATION scoped
+            if (mepCtx.getScope(key) == Scope.APPLICATION) {
+                return userMap.put(key, value);
+            }
+            return null;
+        }
+
+        @Override
+        public void putAll(Map<? extends String, ? extends Object> m) {
+            // we need to take advantage of the smarter put(String, Object)
+            for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
+                Entry entry = (Entry)it.next();
+                put((String)entry.getKey(), entry.getValue());
+            }
+        }
+        
+        @Override
+        public boolean containsKey(Object key) {
+            if (mepCtx.getScope((String)key) == Scope.APPLICATION) {
+                return userMap.containsKey(key);
+            }
+            return false;
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            return userMap.containsValue(value);
+        }
+
+        @Override
+        public Set entrySet() {
+            return userMap.entrySet();
+        }
+
+        @Override
+        public Object get(Object key) {
+            return userMap.get(key);
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return userMap.isEmpty();
+        }
+
+        @Override
+        public Set keySet() {
+            return userMap.keySet();
+        }
+
+        @Override
+        public Object remove(Object key) {
+            return userMap.remove(key);
+        }
+
+        @Override
+        public int size() {
+            return userMap.size();
+        }
+
+        @Override
+        public Collection values() {
+            return userMap.values();
+        }
+     }
 }

Modified: webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java
URL: http://svn.apache.org/viewvc/webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java?view=diff&rev=550586&r1=550585&r2=550586
==============================================================================
--- webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java (original)
+++ webservices/axis2/trunk/java/modules/jaxws/test/org/apache/axis2/jaxws/sample/AddNumbersHandlerTests.java Mon Jun 25 12:39:19 2007
@@ -20,6 +20,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.Future;
 
 import javax.xml.ws.AsyncHandler;
@@ -170,7 +171,11 @@
             int total = proxy.addNumbersHandler(10,10);
             
             // see if I can get an APPLICATION scoped property set during outbound flow.  I should be able to do this according to 4.2.1
-            assertNotNull("Should be able to retrieve APPLICATION scoped property, but could not.", ((String)p.getResponseContext().get("AddNumbersClientProtocolHandlerOutboundAppScopedProperty")));
+            
+            // TODO:  assert is now commented out.  This property is set by a client outbound handler, and I don't think it
+            // should be available on the request or response contexts.
+            //assertNotNull("Should be able to retrieve APPLICATION scoped property, but could not.", ((String)p.getRequestContext().get("AddNumbersClientProtocolHandlerOutboundAppScopedProperty")));
+
             // should NOT be able to get this HANDLER scoped property though
             assertNull("Should not be able to retrieve HANDLER scoped property, but was able.", (String)p.getResponseContext().get("AddNumbersClientProtocolHandlerOutboundHandlerScopedProperty"));
             // should be able to get this APPLICATION scoped property set during inbound flow
@@ -178,7 +183,7 @@
             // should NOT be able to get this HANDLER scoped property though
             assertNull("Should not be able to retrieve HANDLER scoped property, but was able.", (String)p.getResponseContext().get("AddNumbersClientProtocolHandlerInboundHandlerScopedProperty"));
             // should be able to get this APPLICATION scoped property set by this client
-            assertNotNull("Should be able to retrieve APPLICATION scoped property, but could not.", (String)p.getResponseContext().get("myClientKey"));
+            assertNotNull("Should be able to retrieve APPLICATION scoped property, but could not.", (String)p.getRequestContext().get("myClientKey"));
 
             assertEquals("With handler manipulation, total should be 4 less than a proper sumation.", 16, total);
             TestLogger.logger.debug("Total (after handler manipulation) = " + total);



---------------------------------------------------------------------
To unsubscribe, e-mail: axis-cvs-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-cvs-help@ws.apache.org