You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2012/09/26 23:40:02 UTC

svn commit: r1390742 - in /cxf/trunk: rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/ rt/frontend/jaxrs/src/main/java/org/apach...

Author: sergeyb
Date: Wed Sep 26 21:40:02 2012
New Revision: 1390742

URL: http://svn.apache.org/viewvc?rev=1390742&view=rev
Log:
[CXF-4455] Prototyping support for DynamicFeature

Modified:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceInfoImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfo.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java
    cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java
    cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java?rev=1390742&r1=1390741&r2=1390742&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/JAXRSServerFactoryBean.java Wed Sep 26 21:40:02 2012
@@ -183,8 +183,11 @@ public class JAXRSServerFactoryBean exte
                                           null,
                                           null);
             
+            factory.applyDynamicFeatures(getServiceFactory().getClassResourceInfo());
             applyFeatures();
             
+            
+            
             if (start) {
                 server.start();
             }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceInfoImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceInfoImpl.java?rev=1390742&r1=1390741&r2=1390742&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceInfoImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResourceInfoImpl.java Wed Sep 26 21:40:02 2012
@@ -32,6 +32,10 @@ public class ResourceInfoImpl implements
     public ResourceInfoImpl(Message m) {
         this.ori = m.getExchange().get(OperationResourceInfo.class);
     }
+    public ResourceInfoImpl(OperationResourceInfo ori) {
+        this.ori = ori;
+    }
+    
     @Override
     public Method getResourceMethod() {
         return ori == null ? null : ori.getMethodToInvoke();

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfo.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfo.java?rev=1390742&r1=1390741&r2=1390742&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfo.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfo.java Wed Sep 26 21:40:02 2012
@@ -21,7 +21,7 @@ package org.apache.cxf.jaxrs.model;
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 
 import javax.ws.rs.Consumes;
@@ -47,7 +47,7 @@ public class OperationResourceInfo {
     private String defaultParamValue;
     private List<Parameter> parameters;
     private boolean oneway; 
-    private List<String> nameBindings = Collections.emptyList();
+    private List<String> nameBindings = new LinkedList<String>();
 
     public OperationResourceInfo(Method mInvoke, ClassResourceInfo cri) {
         this(mInvoke, mInvoke, cri);
@@ -102,6 +102,10 @@ public class OperationResourceInfo {
         this.oneway = oneway;
     }
     
+    public void addNameBindings(List<String> names) {
+        nameBindings.addAll(names);
+    }
+    
     public List<String> getNameBindings() {
         List<String> criNames = classResourceInfo.getNameBindings();
         if (criNames.isEmpty()) {

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java?rev=1390742&r1=1390741&r2=1390742&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java Wed Sep 26 21:40:02 2012
@@ -29,6 +29,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -43,8 +44,11 @@ import javax.ws.rs.client.ClientRequestF
 import javax.ws.rs.client.ClientResponseFilter;
 import javax.ws.rs.container.ContainerRequestFilter;
 import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.container.DynamicFeature;
 import javax.ws.rs.container.PreMatching;
 import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Configurable;
+import javax.ws.rs.core.Feature;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.ext.ContextResolver;
@@ -69,9 +73,11 @@ import org.apache.cxf.jaxrs.ext.Response
 import org.apache.cxf.jaxrs.impl.HttpHeadersImpl;
 import org.apache.cxf.jaxrs.impl.ReaderInterceptorMBR;
 import org.apache.cxf.jaxrs.impl.RequestPreprocessor;
+import org.apache.cxf.jaxrs.impl.ResourceInfoImpl;
 import org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper;
 import org.apache.cxf.jaxrs.impl.WriterInterceptorMBW;
 import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
 import org.apache.cxf.jaxrs.model.ProviderInfo;
 import org.apache.cxf.jaxrs.model.wadl.WadlGenerator;
 import org.apache.cxf.jaxrs.utils.AnnotationUtils;
@@ -81,6 +87,11 @@ import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 
 public final class ProviderFactory {
+    private static final Class<?>[] FILTER_INTERCEPTOR_CLASSES = 
+        new Class<?>[] {ContainerRequestFilter.class,
+                        ContainerResponseFilter.class,
+                        ReaderInterceptor.class,
+                        WriterInterceptor.class};
     private static final String ACTIVE_JAXRS_PROVIDER_KEY = "active.jaxrs.provider";
     private static final Logger LOG = LogUtils.getL7dLogger(ProviderFactory.class);
     private static final ProviderFactory SHARED_FACTORY = getInstance();
@@ -138,12 +149,14 @@ public final class ProviderFactory {
     // ContainerRequestFilter & ContainerResponseFilter are introduced in JAX-RS 2.0
     private List<ProviderInfo<ContainerRequestFilter>> preMatchContainerRequestFilters = 
         new ArrayList<ProviderInfo<ContainerRequestFilter>>(1);
+    //TODO: consider using List as a value type for postmatching filters
     private Map<NameKey, ProviderInfo<ContainerRequestFilter>> postMatchContainerRequestFilters = 
         new LinkedHashMap<NameKey, ProviderInfo<ContainerRequestFilter>>();
     private Map<NameKey, ProviderInfo<ContainerResponseFilter>> postMatchContainerResponseFilters = 
         new LinkedHashMap<NameKey, ProviderInfo<ContainerResponseFilter>>();
     private RequestPreprocessor requestPreprocessor;
     private ProviderInfo<Application> application;
+    private List<DynamicFeature> dynamicFeatures = new LinkedList<DynamicFeature>();
     
     // Client-only providers, consider introducing ClientProviderFactory
     private List<ProviderInfo<ClientRequestFilter>> clientRequestFilters = 
@@ -716,6 +729,10 @@ public final class ProviderFactory {
                    new ProviderInfo<WriterInterceptor>((WriterInterceptor)o, bus));
             }
             
+            if (DynamicFeature.class.isAssignableFrom(oClass)) {
+                dynamicFeatures.add((DynamicFeature)o);
+            }
+            
             if (ClientRequestFilter.class.isAssignableFrom(oClass)) {
                 clientRequestFilters.add(
                    new ProviderInfo<ClientRequestFilter>((ClientRequestFilter)o, bus));
@@ -769,9 +786,9 @@ public final class ProviderFactory {
             List<String> names = AnnotationUtils.getNameBindings(
                 p.getProvider().getClass().getAnnotations());
             names = names.isEmpty() ? Collections.singletonList(DEFAULT_FILTER_NAME_BINDING) : names;
-            //TODO:  Would it be faster to have a single NameKey to keep all the names ?
             for (String name : names) {
-                map.put(new NameKey(name), p);
+                map.put(new NameKey(name, AnnotationUtils.getBindingPriority(p.getProvider().getClass())), 
+                        p);
             }
         }
         
@@ -781,9 +798,7 @@ public final class ProviderFactory {
                                                ProviderInfo<T> p,
                                                List<ProviderInfo<T>> preMatchFilters) {
         T filter = p.getProvider();
-        if (preMatchFilters != null
-            && AnnotationUtils.getAnnotation(filter.getClass().getAnnotations(), 
-                                             PreMatching.class) != null) {
+        if (preMatchFilters != null && isPrematching(filter.getClass())) {
             preMatchFilters.add(p);
         } else {
             postMatchFilters.add(p);
@@ -791,6 +806,11 @@ public final class ProviderFactory {
         
     }
     
+    private static boolean isPrematching(Class<?> filterCls) {
+        return AnnotationUtils.getAnnotation(filterCls.getAnnotations(), 
+                                      PreMatching.class) != null;
+    }
+    
     static void injectContextValues(ProviderInfo<?> pi, Message m) {
         if (m != null) {
             InjectionUtils.injectContexts(pi.getProvider(), pi, m);
@@ -804,14 +824,18 @@ public final class ProviderFactory {
                 if (ProviderFactory.SHARED_FACTORY == this && isJaxbBasedProvider(pi.getProvider())) {
                     continue;
                 }
-                if (pi.contextsAvailable()) {
-                    InjectionUtils.injectContextProxies(pi, pi.getProvider());
-                    injectedProviders.add(pi);
-                }
+                injectContextProxiesIntoProvider(pi);
             }
         }
     }
     
+    void injectContextProxiesIntoProvider(ProviderInfo<?> pi) {
+        if (pi.contextsAvailable()) {
+            InjectionUtils.injectContextProxies(pi, pi.getProvider());
+            injectedProviders.add(pi);
+        }
+    }
+    
     /*
      * sorts the available providers according to the media types they declare
      * support for. Sorting of media types follows the general rule: x/y < * x < *,
@@ -1095,6 +1119,30 @@ public final class ProviderFactory {
         }
     }
     
+    public void applyDynamicFeatures(List<ClassResourceInfo> list) {
+        if (dynamicFeatures.size() > 0) {
+            for (ClassResourceInfo cri : list) {
+                doApplyDynamicFeatures(cri);
+            }
+        }
+    }
+    
+    private void doApplyDynamicFeatures(ClassResourceInfo cri) {
+        Set<OperationResourceInfo> oris = cri.getMethodDispatcher().getOperationResourceInfos();
+        for (OperationResourceInfo ori : oris) {
+            for (DynamicFeature feature : dynamicFeatures) {
+                Configurable methodConfigurable = new MethodConfigurable(ori);
+                feature.configure(new ResourceInfoImpl(ori), methodConfigurable);
+            }
+        }
+        Collection<ClassResourceInfo> subs = cri.getSubResources();
+        for (ClassResourceInfo sub : subs) {
+            if (sub != cri) {
+                doApplyDynamicFeatures(sub);    
+            }
+        }
+    }
+    
     private boolean injectProviderProperty(Object provider, String mName, Class<?> pClass, 
                                         Object pValue) {
         try {
@@ -1248,8 +1296,7 @@ public final class ProviderFactory {
         }
         
         private int getBindingPriorityValue(ProviderInfo<?> p) {
-            BindingPriority b = p.getProvider().getClass().getAnnotation(BindingPriority.class);
-            return b == null ? BindingPriority.USER : b.value();
+            return AnnotationUtils.getBindingPriority(p.getProvider().getClass());
         }
     }
     
@@ -1275,12 +1322,240 @@ public final class ProviderFactory {
     
     private static class NameKey { 
         private String name;
-        public NameKey(String name) {
+        private int bindingPriority;
+        public NameKey(String name, int priority) {
             this.name = name;
+            this.bindingPriority = priority;
         }
         
         public String getName() {
             return name;
         }
+        
+        public int getPriority() {
+            return bindingPriority;
+        }
+    }
+    
+    private class MethodConfigurable implements Configurable {
+        
+        private OperationResourceInfo ori;
+        private String nameBinding;
+        private boolean bindingSet;
+        
+        public MethodConfigurable(OperationResourceInfo ori) {
+            this.ori = ori;
+            nameBinding = DEFAULT_FILTER_NAME_BINDING 
+                + ori.getClassResourceInfo().getServiceClass().getName()
+                + "."
+                + ori.getMethodToInvoke().getName();
+        }
+        
+        @Override
+        public Configurable register(Object provider) {
+            return register(provider, AnnotationUtils.getBindingPriority(provider.getClass()));
+        }
+
+        @Override
+        public Configurable register(Object provider, int bindingPriority) {
+            return doRegister(provider, bindingPriority, FILTER_INTERCEPTOR_CLASSES);
+        }
+        
+        @Override
+        public <T> Configurable register(Object provider, Class<? super T>... contracts) {
+            return register(provider, BindingPriority.USER, contracts);
+        }
+        
+        @Override
+        public <T> Configurable register(Object provider, int bindingPriority, Class<? super T>... contracts) {
+            return doRegister(provider, bindingPriority, contracts);
+        }
+        
+        @Override
+        public Configurable register(Class<?> providerClass) {
+            return register(providerClass, AnnotationUtils.getBindingPriority(providerClass));
+        }
+
+        @Override
+        public Configurable register(Class<?> providerClass, int bindingPriority) {
+            return doRegister(createProvider(providerClass), bindingPriority, 
+                              FILTER_INTERCEPTOR_CLASSES);
+        }
+
+        @Override
+        public <T> Configurable register(Class<T> providerClass, Class<? super T>... contracts) {
+            return register(providerClass, BindingPriority.USER, contracts);
+        }
+
+        @Override
+        public <T> Configurable register(Class<T> providerClass, int bindingPriority,
+                                         Class<? super T>... contracts) {
+            return doRegister(createProvider(providerClass), bindingPriority, contracts);
+        }
+        
+        private Configurable doRegister(Object provider, int bindingPriority, Class<?>... contracts) {
+        
+            if (provider instanceof Feature) {
+                ((Feature)provider).configure(this);
+                return this;
+            }
+            
+            boolean setIsNeeded = false;
+            for (Class<?> contract : contracts) {
+                if (contract == ContainerRequestFilter.class && provider instanceof ContainerRequestFilter) {
+                    if (isPrematching(provider.getClass())) {
+                        addToInterceptors(preMatchContainerRequestFilters, provider, bindingPriority, true);
+                    } else {
+                        postMatchContainerRequestFilters = 
+                            addToPostMatching(postMatchContainerRequestFilters, provider, bindingPriority, true);
+                        setIsNeeded = true;
+                    }
+                }
+                if (contract == ContainerResponseFilter.class && provider instanceof ContainerResponseFilter) {
+                    postMatchContainerResponseFilters = 
+                        addToPostMatching(postMatchContainerResponseFilters, provider, bindingPriority, false);
+                    setIsNeeded = true;    
+                }
+                if (contract == ReaderInterceptor.class && provider instanceof ReaderInterceptor) {
+                    addToInterceptors(readerInterceptors, provider, bindingPriority, true);
+                }
+                if (contract == WriterInterceptor.class && provider instanceof WriterInterceptor) {
+                    addToInterceptors(writerInterceptors, provider, bindingPriority, false);
+                }
+            }
+            
+            if (setIsNeeded && !bindingSet) {
+                ori.addNameBindings(Collections.singletonList(nameBinding));
+                bindingSet = true;
+            }
+
+            return this;
+        }
+        
+        @SuppressWarnings("unchecked")
+        private <T> void addToInterceptors(List<ProviderInfo<T>> providers, Object provider, 
+                                           int priority, boolean asc) {
+            int size = providers.size();
+            if (size > 0) {
+                for (int i = 0; i < size; i++) {
+                    int providerPriority = AnnotationUtils.getBindingPriority(
+                        providers.get(i).getProvider().getClass());
+                    if (asc) {
+                        if (priority < providerPriority || i + 1 == size) {
+                            int index = priority < providerPriority ? i : i + 1;
+                            providers.add(index, (ProviderInfo<T>)newProvider(provider));
+                            break;
+                        }
+                    } else if (priority > providerPriority || i + 1 == size) {
+                        int index = priority > providerPriority ? i : i + 1; 
+                        providers.add(index, (ProviderInfo<T>)newProvider(provider));
+                        break;
+                    }
+                }
+            } else {
+                providers.add((ProviderInfo<T>)newProvider(provider));
+            }
+        }
+        
+        private <T> ProviderInfo<T> newProvider(T provider) {
+            ProviderInfo<T> newProvider = new ProviderInfo<T>(provider, bus);
+            injectContextProxiesIntoProvider(newProvider);
+            return newProvider;
+        }
+        
+        @SuppressWarnings("unchecked")
+        private <T> Map<NameKey, ProviderInfo<T>> addToPostMatching(
+            Map<NameKey, ProviderInfo<T>> map, Object provider, int priority, boolean asc) {
+            Map<NameKey, ProviderInfo<T>> newMap = new LinkedHashMap<NameKey, ProviderInfo<T>>();
+            
+            Iterator<Map.Entry<NameKey, ProviderInfo<T>>> it = map.entrySet().iterator();
+            if (it.hasNext()) {
+                boolean added = false;
+                while (it.hasNext()) {
+                    Map.Entry<NameKey, ProviderInfo<T>> entry = it.next();
+                    int providerPriority = entry.getKey().getPriority();
+                    // this surely can be collapsed further
+                    if (!added && asc && (priority < providerPriority || !it.hasNext())) {
+                        addNewProvider(newMap, entry, provider, priority, providerPriority >= priority);
+                        added = true;
+                    } else if (!added && !asc && (priority > providerPriority || !it.hasNext())) {
+                        addNewProvider(newMap, entry, provider, priority, priority > providerPriority);
+                        added = true;
+                    } else {
+                        newMap.put(entry.getKey(), entry.getValue());
+                    }   
+                }
+            } else {
+                newMap.put(new NameKey(nameBinding, priority), (ProviderInfo<T>)newProvider(provider));
+            }
+            return newMap;
+            
+                
+        }
+        
+        @SuppressWarnings("unchecked")
+        private <T> void addNewProvider(Map<NameKey, ProviderInfo<T>> newMap, 
+                                        Map.Entry<NameKey, ProviderInfo<T>> entry,
+                                        Object provider, 
+                                        int priority,
+                                        boolean first) {
+            if (first) {
+                newMap.put(new NameKey(nameBinding, priority), (ProviderInfo<T>)newProvider(provider));
+                newMap.put(entry.getKey(), entry.getValue());
+            } else {
+                newMap.put(entry.getKey(), entry.getValue());
+                newMap.put(new NameKey(nameBinding, priority), (ProviderInfo<T>)newProvider(provider));
+            }
+        }
+        
+        @Override
+        public Collection<Feature> getFeatures() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Set<Class<?>> getProviderClasses() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Set<Object> getProviderInstances() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Map<String, Object> getProperties() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Object getProperty(String name) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Configurable setProperties(Map<String, ?> properties) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public Configurable setProperty(String name, Object value) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+        
+        private Object createProvider(Class<?> cls) {
+            try {
+                return cls.newInstance();
+            } catch (Throwable ex) {
+                throw new RuntimeException(ex); 
+            }
+        }
     }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java?rev=1390742&r1=1390741&r2=1390742&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/AnnotationUtils.java Wed Sep 26 21:40:02 2012
@@ -33,6 +33,7 @@ import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.BindingPriority;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.CookieParam;
 import javax.ws.rs.DefaultValue;
@@ -124,6 +125,10 @@ public final class AnnotationUtils {
         return classes;
     }
 
+    public static int getBindingPriority(Class<?> providerCls) {
+        BindingPriority b = providerCls.getAnnotation(BindingPriority.class);
+        return b == null ? BindingPriority.USER : b.value();
+    }
     public static List<String> getNameBindings(Annotation[] targetAnns) {
         if (targetAnns.length == 0) {
             return Collections.emptyList();

Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java?rev=1390742&r1=1390741&r2=1390742&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookServer20.java Wed Sep 26 21:40:02 2012
@@ -28,14 +28,17 @@ import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.ws.rs.BindingPriority;
 import javax.ws.rs.NameBinding;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.container.ContainerRequestFilter;
 import javax.ws.rs.container.ContainerResponseContext;
 import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.container.DynamicFeature;
 import javax.ws.rs.container.PreMatching;
 import javax.ws.rs.container.ResourceInfo;
+import javax.ws.rs.core.Configurable;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.ext.ReaderInterceptor;
@@ -63,11 +66,14 @@ public class BookServer20 extends Abstra
         
         List<Object> providers = new ArrayList<Object>();
         
+        providers.add(new PreMatchContainerRequestFilter2());
         providers.add(new PreMatchContainerRequestFilter());
         providers.add(new PostMatchContainerResponseFilter());
+        providers.add(new PostMatchContainerResponseFilter3());
         providers.add(new PostMatchContainerResponseFilter2());
         providers.add(new CustomReaderInterceptor());
         providers.add(new CustomWriterInterceptor());
+        providers.add(new CustomDynamicFeature());
         sf.setProviders(providers);
         sf.setResourceProvider(BookStore.class,
                                new SingletonResourceProvider(new BookStore(), true));
@@ -96,11 +102,12 @@ public class BookServer20 extends Abstra
     }
     
     @PreMatching
+    @BindingPriority(1)
     private static class PreMatchContainerRequestFilter implements ContainerRequestFilter {
 
         @Override
         public void filter(ContainerRequestContext context) throws IOException {
-            context.getHeaders().add("BOOK", "123");
+            context.setProperty("FirstPrematchingFilter", "true");
             
             UriInfo ui = context.getUriInfo();
             String path = ui.getPath(false);
@@ -111,6 +118,36 @@ public class BookServer20 extends Abstra
         
     }
     
+    @PreMatching
+    @BindingPriority(3)
+    private static class PreMatchContainerRequestFilter2 implements ContainerRequestFilter {
+
+        @Override
+        public void filter(ContainerRequestContext context) throws IOException {
+            if (!"true".equals(context.getProperty("FirstPrematchingFilter"))
+                || !"true".equals(context.getProperty("DynamicPrematchingFilter"))) {
+                throw new RuntimeException();
+            }
+            context.getHeaders().add("BOOK", "123");
+        }
+        
+    }
+    
+    @PreMatching
+    @BindingPriority(2)
+    private static class PreMatchDynamicContainerRequestFilter implements ContainerRequestFilter {
+
+        @Override
+        public void filter(ContainerRequestContext context) throws IOException {
+            if (!"true".equals(context.getProperty("FirstPrematchingFilter"))) {
+                throw new RuntimeException();
+            }
+            context.setProperty("DynamicPrematchingFilter", "true");
+        }
+        
+    }
+    
+    @BindingPriority(3)
     public static class PostMatchContainerResponseFilter implements ContainerResponseFilter {
 
         @Override
@@ -121,12 +158,28 @@ public class BookServer20 extends Abstra
         
     }
     
-    @CustomHeaderAdded
+    @BindingPriority(1)
     public static class PostMatchContainerResponseFilter2 implements ContainerResponseFilter {
 
         @Override
         public void filter(ContainerRequestContext requestContext,
                            ContainerResponseContext responseContext) throws IOException {
+            if (!responseContext.getHeaders().containsKey("Response")
+                || !responseContext.getHeaders().containsKey("DynamicResponse")) {
+                throw new RuntimeException();
+            }
+            responseContext.getHeaders().add("Response2", "OK2");
+            
+        }
+        
+    }
+    @BindingPriority(4)
+    @CustomHeaderAdded
+    public static class PostMatchContainerResponseFilter3 implements ContainerResponseFilter {
+
+        @Override
+        public void filter(ContainerRequestContext requestContext,
+                           ContainerResponseContext responseContext) throws IOException {
             responseContext.getHeaders().add("Custom", "custom");
             Book book = (Book)responseContext.getEntity();
             responseContext.setEntity(new Book(book.getName(), 1 + book.getId()), null, null);
@@ -134,6 +187,21 @@ public class BookServer20 extends Abstra
         
     }
     
+    @BindingPriority(2)
+    public static class PostMatchDynamicContainerResponseFilter implements ContainerResponseFilter {
+
+        @Override
+        public void filter(ContainerRequestContext requestContext,
+                           ContainerResponseContext responseContext) throws IOException {
+            if (!responseContext.getHeaders().containsKey("Response")) {
+                throw new RuntimeException();
+            }
+            responseContext.getHeaders().add("DynamicResponse", "Dynamic");
+            
+        }
+        
+    }
+    
     @Target({ ElementType.TYPE, ElementType.METHOD })
     @Retention(value = RetentionPolicy.RUNTIME)
     @NameBinding
@@ -165,4 +233,15 @@ public class BookServer20 extends Abstra
         }
         
     }
+    
+    public static class CustomDynamicFeature implements DynamicFeature {
+
+        @Override
+        public void configure(ResourceInfo resourceInfo, Configurable configurable) {
+            
+            configurable.register(new PreMatchDynamicContainerRequestFilter());
+            configurable.register(new PostMatchDynamicContainerResponseFilter());
+        }
+        
+    }
 }

Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java?rev=1390742&r1=1390741&r2=1390742&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRS20ClientServerBookTest.java Wed Sep 26 21:40:02 2012
@@ -195,6 +195,8 @@ public class JAXRS20ClientServerBookTest
     private void validateResponse(WebClient wc) {
         Response response = wc.getResponse();
         assertEquals("OK", response.getHeaderString("Response"));
+        assertEquals("OK2", response.getHeaderString("Response2"));
+        assertEquals("Dynamic", response.getHeaderString("DynamicResponse"));
         assertEquals("custom", response.getHeaderString("Custom"));
         assertEquals("simple", response.getHeaderString("Simple"));
         assertEquals("serverWrite", response.getHeaderString("ServerWriterInterceptor"));