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);
}