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 2016/04/14 14:31:37 UTC

cxf git commit: [CXF-6837] Prototyping MBR/MBW cache code, a patch from Neal Hu with modifications applied

Repository: cxf
Updated Branches:
  refs/heads/master 26edcd457 -> 0abb19515


[CXF-6837] Prototyping MBR/MBW cache code, a patch from Neal Hu with modifications applied


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/0abb1951
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/0abb1951
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/0abb1951

Branch: refs/heads/master
Commit: 0abb1951545fe2e271daac373669a75e501a8434
Parents: 26edcd4
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Thu Apr 14 13:31:21 2016 +0100
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Thu Apr 14 13:31:21 2016 +0100

----------------------------------------------------------------------
 .../cxf/jaxrs/provider/ProviderCache.java       | 106 ++++++++++++++
 .../cxf/jaxrs/provider/ProviderFactory.java     | 139 +++++++++++++++----
 2 files changed, 219 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/0abb1951/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderCache.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderCache.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderCache.java
new file mode 100644
index 0000000..37aeb7b
--- /dev/null
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderCache.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.jaxrs.provider;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.apache.cxf.jaxrs.model.ProviderInfo;
+
+public class ProviderCache {
+    private static final int MAX_PROVIDER_CACHE_SIZE = 
+        Integer.getInteger("org.apache.cxf.jaxrs.max_provider_cache_size", 100);
+    private final Map<String, List<ProviderInfo<MessageBodyReader<?>>>>
+        readerProviderCache = new ConcurrentHashMap<String, List<ProviderInfo<MessageBodyReader<?>>>>();
+
+    private final Map<String, List<ProviderInfo<MessageBodyWriter<?>>>>
+        writerProviderCache = new ConcurrentHashMap<String, List<ProviderInfo<MessageBodyWriter<?>>>>();
+    
+    private boolean checkAllCandidates;
+    public ProviderCache(boolean checkAllCandidates) {
+        this.checkAllCandidates = checkAllCandidates;
+    }
+    
+    public List<ProviderInfo<MessageBodyReader<?>>> getReaders(Class<?> type, MediaType mt) {
+        if (readerProviderCache.isEmpty()) {
+            return Collections.emptyList();
+        }
+        String key = getKey(type, mt);
+
+        List<ProviderInfo<MessageBodyReader<?>>> list = readerProviderCache.get(key);
+        return list != null ? list : Collections.emptyList();
+    }
+    public List<ProviderInfo<MessageBodyWriter<?>>> getWriters(Class<?> type, MediaType mt) {
+        if (writerProviderCache.isEmpty()) {
+            return Collections.emptyList();
+        }
+        
+        String key = getKey(type, mt);
+
+        List<ProviderInfo<MessageBodyWriter<?>>> list = writerProviderCache.get(key);
+        return list != null ? list : Collections.emptyList();
+    }
+
+    public void putReaders(Class<?> type, MediaType mt, List<ProviderInfo<MessageBodyReader<?>>> candidates) {
+        if (candidates == null || candidates.isEmpty()) {
+            return;
+        }
+        checkCacheSize(readerProviderCache);
+        
+        String key = getKey(type, mt);
+        readerProviderCache.put(key, candidates);       
+    }
+
+    public void putWriters(Class<?> type, MediaType mt, List<ProviderInfo<MessageBodyWriter<?>>> candidates) {
+        if (candidates == null || candidates.isEmpty()) {
+            return;
+        }
+        checkCacheSize(writerProviderCache);
+        
+        String key = getKey(type, mt);
+        writerProviderCache.put(key, candidates);       
+    }
+
+    public void destroy() {
+        this.readerProviderCache.clear();
+        this.writerProviderCache.clear();
+    }
+
+    private String getKey(Class<?> type, MediaType mt) {
+        return type.getName() + "-" + mt.toString();
+    }
+
+    private static void checkCacheSize(Map<?, ?> map) {
+        final int size = map.size();
+        if (size >= MAX_PROVIDER_CACHE_SIZE) {
+            map.clear();
+        }
+    }
+
+    public boolean isCheckAllCandidates() {
+        return checkAllCandidates;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/0abb1951/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
index 2754c61..41f7346 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
@@ -91,6 +91,8 @@ public abstract class ProviderFactory {
     private static final String JAXB_PROVIDER_NAME = "org.apache.cxf.jaxrs.provider.JAXBElementProvider";
     private static final String JSON_PROVIDER_NAME = "org.apache.cxf.jaxrs.provider.json.JSONProvider";
     private static final String BUS_PROVIDERS_ALL = "org.apache.cxf.jaxrs.bus.providers";
+    private static final String PROVIDER_CACHE_ALLOWED = "org.apache.cxf.jaxrs.provider.cache.allowed";
+    private static final String PROVIDER_CACHE_CHECK_ALL = "org.apache.cxf.jaxrs.provider.cache.checkAllCandidates";
     
     protected Map<NameKey, ProviderInfo<ReaderInterceptor>> readerInterceptors = 
         new NameKeyMap<ProviderInfo<ReaderInterceptor>>(true);
@@ -117,14 +119,25 @@ public abstract class ProviderFactory {
     
     private Comparator<?> providerComparator;
     
+    private ProviderCache providerCache;
+    
     protected ProviderFactory(Bus bus) {
         this.bus = bus;
+        providerCache = initCache(bus);
     }
     
     public Bus getBus() {
         return bus;
     }
-    
+    protected static ProviderCache initCache(Bus theBus) {
+        Object allowProp = theBus.getProperty(PROVIDER_CACHE_ALLOWED);
+        boolean allowed = allowProp == null || PropertyUtils.isTrue(allowProp);
+        if (!allowed) {
+            return null;
+        }
+        boolean checkAll = PropertyUtils.isTrue(theBus.getProperty(PROVIDER_CACHE_CHECK_ALL));
+        return new ProviderCache(checkAll);
+    }
     protected static void initFactory(ProviderFactory factory) {
         factory.setProviders(false,
                              false,
@@ -413,13 +426,45 @@ public abstract class ProviderFactory {
                                                             Annotation[] annotations,
                                                             MediaType mediaType,
                                                             Message m) {
+        // Step1: check the cache 
+        
+        if (providerCache != null) {
+            for (ProviderInfo<MessageBodyReader<?>> ep : providerCache.getReaders(type, mediaType)) {
+                if (isReadable(ep, type, genericType, annotations, mediaType, m)) {
+                    return (MessageBodyReader<T>)ep.getProvider();
+                }
+            }           
+        }
+        
+        boolean checkAll = providerCache != null && providerCache.isCheckAllCandidates();
+        List<ProviderInfo<MessageBodyReader<?>>> allCandidates = 
+            checkAll ? new LinkedList<ProviderInfo<MessageBodyReader<?>>>() : null;
+            
+        MessageBodyReader<T> selectedReader = null;    
         for (ProviderInfo<MessageBodyReader<?>> ep : messageReaders) {
-            if (matchesReaderCriterias(ep, type, genericType, annotations, mediaType, m)
+            if (matchesReaderMediaTypes(ep, mediaType)
                 && handleMapper(ep, type, m, MessageBodyReader.class, false)) {
-                return (MessageBodyReader<T>)ep.getProvider();
+                // This writer matches Media Type and Class
+                if (checkAll) {
+                    allCandidates.add(ep);
+                } else if (providerCache != null && providerCache.getReaders(type, mediaType).isEmpty()) {
+                    providerCache.putReaders(type, mediaType, Collections.singletonList(ep));
+                }
+                if (selectedReader == null
+                    && isReadable(ep, type, genericType, annotations, mediaType, m)) {
+                    // This writer is a selected candidate
+                    selectedReader = (MessageBodyReader<T>)ep.getProvider();
+                    if (!checkAll) {
+                        return selectedReader;
+                    }
+                }
+                
             }
         }     
-        return null;
+        if (checkAll) {
+            providerCache.putReaders(type, mediaType, allCandidates);
+        } 
+        return selectedReader;
     }
     
     @SuppressWarnings("unchecked")
@@ -428,13 +473,49 @@ public abstract class ProviderFactory {
                                                             Annotation[] annotations,
                                                             MediaType mediaType,
                                                             Message m) {
+        
+        // Step1: check the cache. 
+        if (providerCache != null) {
+            for (ProviderInfo<MessageBodyWriter<?>> ep : providerCache.getWriters(type, mediaType)) {
+                if (isWriteable(ep, type, genericType, annotations, mediaType, m)) {
+                    return (MessageBodyWriter<T>)ep.getProvider();
+                }
+            }           
+        }
+        
+        // Step2: check all the registered writers
+        
+        // The cache, if enabled, may have been configured to keep the top candidate only
+        boolean checkAll = providerCache != null && providerCache.isCheckAllCandidates();
+        List<ProviderInfo<MessageBodyWriter<?>>> allCandidates = 
+            checkAll ? new LinkedList<ProviderInfo<MessageBodyWriter<?>>>() : null;
+            
+        MessageBodyWriter<T> selectedWriter = null;    
         for (ProviderInfo<MessageBodyWriter<?>> ep : messageWriters) {
-            if (matchesWriterCriterias(ep, type, genericType, annotations, mediaType, m)
+            if (matchesWriterMediaTypes(ep, mediaType)
                 && handleMapper(ep, type, m, MessageBodyWriter.class, false)) {
-                return (MessageBodyWriter<T>)ep.getProvider();
+                // This writer matches Media Type and Class
+                if (checkAll) {
+                    allCandidates.add(ep);
+                } else if (providerCache != null && providerCache.getWriters(type, mediaType).isEmpty()) {
+                    providerCache.putWriters(type, mediaType, Collections.singletonList(ep));
+                }
+                if (selectedWriter == null
+                    && isWriteable(ep, type, genericType, annotations, mediaType, m)) {
+                    // This writer is a selected candidate
+                    selectedWriter = (MessageBodyWriter<T>)ep.getProvider();
+                    if (!checkAll) {
+                        return selectedWriter;
+                    }
+                }
+                
             }
-        }
-        return null;
+        }     
+        if (checkAll) {
+            providerCache.putWriters(type, mediaType, allCandidates);
+        } 
+        return selectedWriter;
+        
     }
     
     protected void setBusProviders() {
@@ -635,33 +716,32 @@ public abstract class ProviderFactory {
     
     
     
-    private <T> boolean matchesReaderCriterias(ProviderInfo<MessageBodyReader<?>> pi,
-                                               Class<T> type,
-                                               Type genericType,
-                                               Annotation[] annotations,
-                                               MediaType mediaType,
-                                               Message m) {
+    private <T> boolean matchesReaderMediaTypes(ProviderInfo<MessageBodyReader<?>> pi,
+                                                MediaType mediaType) {
         MessageBodyReader<?> ep = pi.getProvider();
         List<MediaType> supportedMediaTypes = JAXRSUtils.getProviderConsumeTypes(ep);
         
         List<MediaType> availableMimeTypes = 
             JAXRSUtils.intersectMimeTypes(Collections.singletonList(mediaType), supportedMediaTypes, false);
 
-        if (availableMimeTypes.size() == 0) {
-            return false;
-        }
+        return availableMimeTypes.size() != 0;
+    }
+    
+    private boolean isReadable(ProviderInfo<MessageBodyReader<?>> pi,
+                               Class<?> type,
+                               Type genericType,
+                               Annotation[] annotations,
+                               MediaType mediaType,
+                               Message m) {
+        MessageBodyReader<?> ep = pi.getProvider();
         if (m.get(ACTIVE_JAXRS_PROVIDER_KEY) != ep) {
             injectContextValues(pi, m);
         }
         return ep.isReadable(type, genericType, annotations, mediaType);
     }
         
-    private <T> boolean matchesWriterCriterias(ProviderInfo<MessageBodyWriter<?>> pi,
-                                               Class<T> type,
-                                               Type genericType,
-                                               Annotation[] annotations,
-                                               MediaType mediaType,
-                                               Message m) {
+    private <T> boolean matchesWriterMediaTypes(ProviderInfo<MessageBodyWriter<?>> pi,
+                                                MediaType mediaType) {
         MessageBodyWriter<?> ep = pi.getProvider();
         List<MediaType> supportedMediaTypes = JAXRSUtils.getProviderProduceTypes(ep);
         
@@ -669,9 +749,16 @@ public abstract class ProviderFactory {
             JAXRSUtils.intersectMimeTypes(Collections.singletonList(mediaType),
                                           supportedMediaTypes, false);
 
-        if (availableMimeTypes.size() == 0) {
-            return false;
-        }
+        return availableMimeTypes.size() != 0;
+    }
+    
+    private boolean isWriteable(ProviderInfo<MessageBodyWriter<?>> pi,
+                               Class<?> type,
+                               Type genericType,
+                               Annotation[] annotations,
+                               MediaType mediaType,
+                               Message m) {
+        MessageBodyWriter<?> ep = pi.getProvider();
         if (m.get(ACTIVE_JAXRS_PROVIDER_KEY) != ep) {
             injectContextValues(pi, m);
         }