jersey.repackaged.com.google.common.collect.Maps



API Populatity

1 Client projects

Project: jersey

Project jersey/jersey in file ....glassfish.jersey.message.internal.MediaTypes.java (2015-02-05)
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2010-2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010-2015 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -51,29 +51,61 @@ import javax.ws.rs.Consumes;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
+import jersey.repackaged.com.google.common.base.Predicate;
+import jersey.repackaged.com.google.common.collect.Maps;
+
 /**
  * Common media types and functionality.
  *
  * @author Paul Sandoz
  * @author Marek Potociar (marek.potociar at oracle.com)
  */
-public class MediaTypes {
+public final class MediaTypes {
 
     /**
      * WADL Media type.
      */
-    public final static MediaType WADL = MediaType.valueOf("application/vnd.sun.wadl+xml");
+    public static final MediaType WADL_TYPE = MediaType.valueOf("application/vnd.sun.wadl+xml");
+
+
     /**
-     * Fast infoset media type.
+     * A comparator for media types, that implements the "partial order" defined in the resource matching algorithm
+     * section of the JAX-RS specification, except that this comparator is "inverted" so that it allows for natural
+     * sorting in Java collections, where "lower" values are put to the front of a collection.
+     *
+     * IOW, when used to sort a collection, the resulting collection can be iterated in a way that the more specific
+     * media types are preferred over the less specific ones:
+     *
+     * <pre>
+     *   m/n &lt; m/&#42; &lt; &#42;/&#42;</pre>
+     *
+     * The actual media type values are ignored, i.e. the different media types are considered equal if they are
+     * comparably specific:
+     *
+     * <pre>
+     *   compare(m/n, x/y) == 0
+     *   compare(m/&#42;, x/&#42;) == 0</pre>
      */
-    public final static MediaType FAST_INFOSET = MediaType.valueOf("application/fastinfoset");
+    public static final Comparator<MediaType> PARTIAL_ORDER_COMPARATOR = new Comparator<MediaType>() {
+
+        private int rank(final MediaType type) {
+            // "m/n" = 0; "m/*" = 1; "*/*" = 3; ...also "*/n" = 2, but that's just nonsense...
+            return ((type.isWildcardType() ? 1 : 0) << 1) | (type.isWildcardSubtype() ? 1 : 0);
+        }
+
+        @Override
+        public int compare(MediaType typeA, MediaType typeB) {
+            return rank(typeA) - rank(typeB);
+        }
+    };
+
     /**
      * Comparator for lists of media types.
      * <p>
      * The least specific content type of each list is obtained and then compared
-     * using {@link #MEDIA_TYPE_COMPARATOR}.
+     * using {@link #PARTIAL_ORDER_COMPARATOR}.
      * <p>
-     * Assumes each list is already ordered according to {@link #MEDIA_TYPE_COMPARATOR}
+     * Assumes each list is already ordered according to {@link #PARTIAL_ORDER_COMPARATOR}
      * and therefore the least specific media type is at the end of the list.
      */
     public static final Comparator<List<? extends MediaType>> MEDIA_TYPE_LIST_COMPARATOR =
@@ -81,90 +113,37 @@ public class MediaTypes {
 
                 @Override
                 public int compare(List<? extends MediaType> o1, List<? extends MediaType> o2) {
-                    return MEDIA_TYPE_COMPARATOR.compare(getLeastSpecific(o1), getLeastSpecific(o2));
+                    return PARTIAL_ORDER_COMPARATOR.compare(getLeastSpecific(o1), getLeastSpecific(o2));
                 }
 
-                public MediaType getLeastSpecific(List<? extends MediaType> l) {
+                private MediaType getLeastSpecific(List<? extends MediaType> l) {
+                    // FIXME: really comparing just last one?
                     return l.get(l.size() - 1);
                 }
             };
     /**
-     * The general media type corresponding to *\\/*.
-     *
+     * A singleton list containing the wildcard media type.
      */
-    public static final MediaType GENERAL_MEDIA_TYPE = new MediaType("*", "*");
+    public static final List<MediaType> WILDCARD_TYPE_SINGLETON_LIST =
+            Collections.singletonList(MediaType.WILDCARD_TYPE);
     /**
-     * A singleton list containing the general media type.
+     * An acceptable media type corresponding to a wildcard type.
      */
-    public static final List<MediaType> GENERAL_MEDIA_TYPE_LIST = createMediaTypeList();
+    public static final AcceptableMediaType WILDCARD_ACCEPTABLE_TYPE = new AcceptableMediaType("*", "*");
     /**
-     * The general acceptable media type corresponding to *\\/*.
-     *
+     * An acceptable media type corresponding to a wildcard type.
      */
-    static final AcceptableMediaType GENERAL_ACCEPT_MEDIA_TYPE = new AcceptableMediaType("*", "*");
+    public static final QualitySourceMediaType WILDCARD_QS_TYPE = new QualitySourceMediaType("*", "*");
     /**
-     * A singleton list containing the general acceptable media type.
+     * A singleton list containing the wildcard media type.
      */
-    static final List<AcceptableMediaType> GENERAL_ACCEPT_MEDIA_TYPE_LIST = createAcceptMediaTypeList();
-    /**
-     * A singleton list containing the general media type.
-     */
-    public static final List<MediaType> GENERAL_QUALITY_SOURCE_MEDIA_TYPE_LIST = createQualitySourceMediaTypeList();
-    /**
-     * Comparator for lists of quality source media types.
-     */
-    public static final Comparator<QualitySourceMediaType> QUALITY_SOURCE_MEDIA_TYPE_COMPARATOR = new Comparator<QualitySourceMediaType>() {
-
-        @Override
-        public int compare(QualitySourceMediaType o1, QualitySourceMediaType o2) {
-            int i = o2.getQualitySource() - o1.getQualitySource();
-            if (i != 0) {
-                return i;
-            }
-
-            return MediaTypes.MEDIA_TYPE_COMPARATOR.compare(o1, o2);
-        }
-    };
-    /**
-     * Comparator for media types. The more specific media types are preferred over
-     * the less specific ones:
-     * <pre>
-     *   m/n &lt; m/&#42; &lt; &#42;/&#42;</pre>
-     * <p />
-     * The actual media type values are ignored, i.e. the different media types are
-     * considered equal if they are comparably specific:
-     * <pre>
-     *   compare(m/n, x/y) == 0
-     *   compare(m/&#42;, x/&#42;) == 0</pre>
-     */
-    public static final Comparator<MediaType> MEDIA_TYPE_COMPARATOR = new Comparator<MediaType>() {
-
-        @Override
-        public int compare(MediaType o1, MediaType o2) {
-            if (o1.isWildcardType() && !o2.isWildcardType()) {
-                return 1;
-            }
-
-            if (o2.isWildcardType() && !o1.isWildcardType()) {
-                return -1;
-            }
-
-            if (o1.isWildcardSubtype() && !o2.isWildcardSubtype()) {
-                return 1;
-            }
-
-            if (o2.isWildcardSubtype() && !o1.isWildcardSubtype()) {
-                return -1;
-            }
-
-            return 0;
-        }
-    };
+    public static final List<MediaType> WILDCARD_QS_TYPE_SINGLETON_LIST =
+            Collections.<MediaType>singletonList(WILDCARD_QS_TYPE);
 
     /**
      * Cache containing frequently requested media type values with a wildcard subtype.
      */
-    private static Map<String, MediaType> wildcardSubtypeCache = new HashMap<String, MediaType>() {
+    private static final Map<String, MediaType> WILDCARD_SUBTYPE_CACHE = new HashMap<String, MediaType>() {
 
         private static final long serialVersionUID = 3109256773218160485L;
 
@@ -174,11 +153,22 @@ public class MediaTypes {
             put("text", new MediaType("text", MediaType.MEDIA_TYPE_WILDCARD));
         }
     };
+    /**
+     * Predicate for constructing filtering parameter maps that ignore the "q" and "qs" parameters.
+     */
+    private static final Predicate<String> QUALITY_PARAM_FILTERING_PREDICATE = new Predicate<String>() {
+        @Override
+        public boolean apply(String input) {
+            return !Quality.QUALITY_SOURCE_PARAMETER_NAME.equals(input) &&
+                    !Quality.QUALITY_PARAMETER_NAME.equals(input);
+        }
+    };
 
     /**
      * Prevents initialization.
      */
     private MediaTypes() {
+        throw new AssertionError("Instantiation not allowed.");
     }
 
     /**
@@ -195,7 +185,7 @@ public class MediaTypes {
      * @param m1 first media type.
      * @param m2 second media type.
      * @return {@code true} if the two media types are of the same type and subtype,
-     *     {@code false} otherwise.
+     * {@code false} otherwise.
      */
     public static boolean typeEqual(MediaType m1, MediaType m2) {
         if (m1 == null || m2 == null) {
@@ -213,7 +203,7 @@ public class MediaTypes {
      * @param ml1 first media type list.
      * @param ml2 second media type list.
      * @return {@code true} if the two media type lists intersect by sharing a
-     *     common type-equal sub-list, {@code false} otherwise.
+     * common type-equal sub-list, {@code false} otherwise.
      */
     public static boolean intersect(List<? extends MediaType> ml1, List<? extends MediaType> ml2) {
         for (MediaType m1 : ml1) {
@@ -229,95 +219,90 @@ public class MediaTypes {
     /**
      * Get the most specific media type from a pair of media types. The most
      * specific media type is the media type from the pair that has least
-     * wild cards present.
+     * wild cards present, or has more parameters specified.
      *
-     * @param m1 the first media type
-     * @param m2 the second media type
+     * @param m1 the first media type.
+     * @param m2 the second media type.
      * @return the most specific media type. If the media types are equally
-     *         specific then the first media type is returned.
+     * specific then the first media type is returned.
      */
     public static MediaType mostSpecific(MediaType m1, MediaType m2) {
+        if (m1.isWildcardType() && !m2.isWildcardType()) {
+            return m2;
+        }
         if (m1.isWildcardSubtype() && !m2.isWildcardSubtype()) {
             return m2;
         }
-        if (m1.isWildcardType() && !m2.isWildcardType()) {
+        if (m2.getParameters().size() > m1.getParameters().size()) {
             return m2;
         }
-        return m1;
-    }
 
-    private static List<MediaType> createMediaTypeList() {
-        return Collections.singletonList(GENERAL_MEDIA_TYPE);
-    }
-
-    private static List<AcceptableMediaType> createAcceptMediaTypeList() {
-        return Collections.singletonList(GENERAL_ACCEPT_MEDIA_TYPE);
+        return m1;
     }
 
     /**
-     * Create the list of media types from the values declared in the {@link Consumes}
+     * Create an unmodifiable list of media types from the values declared in the {@link Consumes}
      * annotation.
      *
      * @param annotation the Consumes annotation.
-     * @return the list of {@link MediaType}, ordered according to {@link #MEDIA_TYPE_COMPARATOR}.
+     * @return the list of {@link MediaType}, ordered according to {@link #PARTIAL_ORDER_COMPARATOR}.
      */
     public static List<MediaType> createFrom(Consumes annotation) {
         if (annotation == null) {
-            return GENERAL_MEDIA_TYPE_LIST;
+            return WILDCARD_TYPE_SINGLETON_LIST;
         }
 
         return createFrom(annotation.value());
     }
 
     /**
-     * Create the list of media types from the values declared in the {@link Produces}
+     * Create an unmodifiable list of media types from the values declared in the {@link Produces}
      * annotation.
      *
      * @param annotation the Produces annotation.
-     * @return the list of {@link MediaType}, ordered according to {@link #MEDIA_TYPE_COMPARATOR}.
+     * @return the list of {@link MediaType}, ordered according to {@link #PARTIAL_ORDER_COMPARATOR}.
      */
     public static List<MediaType> createFrom(Produces annotation) {
         if (annotation == null) {
-            return GENERAL_MEDIA_TYPE_LIST;
+            return WILDCARD_TYPE_SINGLETON_LIST;
         }
 
         return createFrom(annotation.value());
     }
 
     /**
-     * Create a list of media type from a string array of media types.
-     * <p>
+     * Create an unmodifiable list of media type from a string array of media types.
+     *
      * @param mediaTypes the string array of media types.
-     * @return the list of {@link MediaType}, ordered according to {@link #MEDIA_TYPE_COMPARATOR}.
+     * @return the list of {@link MediaType}, ordered according to {@link #PARTIAL_ORDER_COMPARATOR}.
      */
     public static List<MediaType> createFrom(String[] mediaTypes) {
-        List<MediaType> l = new ArrayList<MediaType>();
+        List<MediaType> result = new ArrayList<MediaType>();
+
         try {
             for (String mediaType : mediaTypes) {
-                HttpHeaderReader.readMediaTypes(l, mediaType);
+                HttpHeaderReader.readMediaTypes(result, mediaType);
             }
-
-            Collections.sort(l, MEDIA_TYPE_COMPARATOR);
-            return l;
         } catch (ParseException ex) {
             throw new IllegalArgumentException(ex);
         }
-    }
 
-    private static List<MediaType> createQualitySourceMediaTypeList() {
-        return Collections.<MediaType>singletonList(new QualitySourceMediaType("*", "*"));
+        Collections.sort(result, PARTIAL_ORDER_COMPARATOR);
+
+        return Collections.unmodifiableList(result);
     }
 
     /**
      * Create a list of quality source media type from the Produces annotation.
      * <p>
+     *
      * @param mime the Produces annotation.
      * @return the list of {@link QualitySourceMediaType}, ordered according to
-     *         {@link #QUALITY_SOURCE_MEDIA_TYPE_COMPARATOR}.
+     * {@link org.glassfish.jersey.message.internal.QualitySourceMediaType#COMPARATOR}.
      */
     public static List<MediaType> createQualitySourceMediaTypes(Produces mime) {
         if (mime == null || mime.value().length == 0) {
-            return GENERAL_QUALITY_SOURCE_MEDIA_TYPE_LIST;
+            return WILDCARD_QS_TYPE_SINGLETON_LIST;
         }
 
         return new ArrayList<MediaType>(createQualitySourceMediaTypes(mime.value()));
@@ -326,9 +311,10 @@ public class MediaTypes {
     /**
      * Create a list of quality source media type from an array of media types.
      * <p>
+     *
      * @param mediaTypes the array of media types.
      * @return the list of {@link QualitySourceMediaType}, ordered according to
-     * the quality source as the primary key and {@link #MEDIA_TYPE_COMPARATOR}
+     * the quality source as the primary key and {@link #PARTIAL_ORDER_COMPARATOR}
      * as the secondary key.
      */
     public static List<QualitySourceMediaType> createQualitySourceMediaTypes(String[] mediaTypes) {
@@ -341,18 +327,19 @@ public class MediaTypes {
 
     /**
      * Reads quality factor from given media type.
+     *
      * @param mt media type to read quality parameter from
      * @return quality factor of input media type
      */
     public static int getQuality(MediaType mt) {
 
-        final String qParam = mt.getParameters().get(Qualified.QUALITY_PARAMETER_NAME);
+        final String qParam = mt.getParameters().get(Quality.QUALITY_PARAMETER_NAME);
         return readQualityFactor(qParam);
     }
 
     private static int readQualityFactor(final String qParam) throws IllegalArgumentException {
         if (qParam == null) {
-            return Quality.DEFAULT_QUALITY;
+            return Quality.DEFAULT;
         } else {
             try {
                 return HttpHeaderReader.readQualityFactor(qParam);
@@ -367,22 +354,18 @@ public class MediaTypes {
      *
      * @param mediaType type to strip quality parameters from
      * @return media type instance corresponding to the given one with quality parameters stripped off
-     *          or the original instance if no such parameters are present
+     * or the original instance if no such parameters are present
      */
     public static MediaType stripQualityParams(MediaType mediaType) {
         final Map<String, String> oldParameters = mediaType.getParameters();
-        if (oldParameters.isEmpty()) {
+        if (oldParameters.isEmpty() ||
+                (!oldParameters.containsKey(Quality.QUALITY_SOURCE_PARAMETER_NAME) &&
+                        !oldParameters.containsKey(Quality.QUALITY_PARAMETER_NAME))) {
             return mediaType;
         }
-        Map<String, String> newParameters = new HashMap<String, String>();
-        for (Map.Entry<String, String> e : oldParameters.entrySet()) {
-            final boolean isQs = e.getKey().equals(QualitySourceMediaType.QUALITY_SOURCE_PARAMETER_NAME);
-            final boolean isQ = e.getKey().equals(Qualified.QUALITY_PARAMETER_NAME);
-            if (!isQ && !isQs) {
-                newParameters.put(e.getKey(), e.getValue());
-            }
-        }
-        return new MediaType(mediaType.getType(), mediaType.getSubtype(), newParameters);
+
+        return new MediaType(mediaType.getType(), mediaType.getSubtype(),
+                Maps.filterKeys(oldParameters, QUALITY_PARAM_FILTERING_PREDICATE));
     }
 
 
@@ -393,7 +376,7 @@ public class MediaTypes {
      * @return MediaType with wildcard in subtype.
      */
     public static MediaType getTypeWildCart(MediaType mediaType) {
-        MediaType mt = wildcardSubtypeCache.get(mediaType.getType());
+        MediaType mt = WILDCARD_SUBTYPE_CACHE.get(mediaType.getType());
 
         if (mt == null) {
             mt = new MediaType(mediaType.getType(), MediaType.MEDIA_TYPE_WILDCARD);
@@ -427,4 +410,16 @@ public class MediaTypes {
         return sb.toString();
 
     }
+
+    /**
+     * Check if the given media type is a wildcard type.
+     *
+     * A media type is considered to be a wildcard if either the media type's type or subtype is a wildcard type.
+     *
+     * @param mediaType media type.
+     * @return {@code true} if the media type is a wildcard type, {@code false} otherwise.
+     */
+    public static boolean isWildcard(final MediaType mediaType) {
+        return mediaType.isWildcardType() || mediaType.isWildcardSubtype();
+    }
 }
Project jersey/jersey in file ...ernal.monitoring.ResourceMethodStatisticsImpl.java (2014-06-12)
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013-2014 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -40,44 +40,82 @@
 
 package org.glassfish.jersey.server.internal.monitoring;
 
+import java.util.Map;
+
 import org.glassfish.jersey.server.model.ResourceMethod;
 import org.glassfish.jersey.server.monitoring.ExecutionStatistics;
 import org.glassfish.jersey.server.monitoring.ResourceMethodStatistics;
 
+import jersey.repackaged.com.google.common.collect.Maps;
+
 /**
  * Resource method statistics.
  *
  * @author Miroslav Fuksa (miroslav.fuksa at oracle.com)
  */
-class ResourceMethodStatisticsImpl implements ResourceMethodStatistics {
+final class ResourceMethodStatisticsImpl implements ResourceMethodStatistics {
+
+    /**
+     * Factory for creating and storing resource method statistics. One instance per resource method.
+     */
+    static class Factory {
+
+        private final Map<String, Builder> stringToMethodsBuilders = Maps.newHashMap();
+
+        ResourceMethodStatisticsImpl.Builder getOrCreate(final ResourceMethod resourceMethod) {
+            final String methodUniqueId = MonitoringUtils.getMethodUniqueId(resourceMethod);
+
+            if (!stringToMethodsBuilders.containsKey(methodUniqueId)) {
+                stringToMethodsBuilders.put(methodUniqueId, new ResourceMethodStatisticsImpl.Builder(resourceMethod));
+            }
+            return stringToMethodsBuilders.get(methodUniqueId);
+        }
+    }
+
     /**
      * Builder of resource method statistics.
      */
     static class Builder {
-        private final ExecutionStatisticsImpl.Builder resourceMethodExecutionStatisticsBuilder;
-        private final ExecutionStatisticsImpl.Builder requestExecutionStatisticsBuilder;
+
         private final ResourceMethod resourceMethod;
 
+        private ExecutionStatisticsImpl.Builder resourceMethodExecutionStatisticsBuilder;
+        private ExecutionStatisticsImpl.Builder requestExecutionStatisticsBuilder;
+
+        private ResourceMethodStatisticsImpl cached;
 
         /**
          * Create a new builder instance.
+         *
          * @param resourceMethod Resource method for which statistics are evaluated.
          */
-        Builder(ResourceMethod resourceMethod) {
+        Builder(final ResourceMethod resourceMethod) {
             this.resourceMethod = resourceMethod;
-            this.resourceMethodExecutionStatisticsBuilder = new ExecutionStatisticsImpl.Builder();
-            this.requestExecutionStatisticsBuilder = new ExecutionStatisticsImpl.Builder();
         }
 
         /**
          * Build an instance of resource method statistics.
+         *
          * @return New instance of resource method statistics.
          */
         ResourceMethodStatisticsImpl build() {
-            return new ResourceMethodStatisticsImpl(resourceMethod, resourceMethodExecutionStatisticsBuilder.build(),
-                    requestExecutionStatisticsBuilder.build());
-        }
+            if (cached != null) {
+                return cached;
+            }
+
+            final ExecutionStatistics methodStats = resourceMethodExecutionStatisticsBuilder == null ?
+                    ExecutionStatisticsImpl.EMPTY : resourceMethodExecutionStatisticsBuilder.build();
+            final ExecutionStatistics requestStats = requestExecutionStatisticsBuilder == null ?
+                    ExecutionStatisticsImpl.EMPTY : requestExecutionStatisticsBuilder.build();
+
+            final ResourceMethodStatisticsImpl stats = new ResourceMethodStatisticsImpl(resourceMethod, methodStats, requestStats);
 
+            if (MonitoringUtils.isCacheable(methodStats)) {
+                cached = stats;
+            }
+
+            return stats;
+        }
 
         /**
          * Add execution of the resource method to the statistics.
@@ -85,37 +123,47 @@ class ResourceMethodStatisticsImpl implements ResourceMethodStatistics {
          * @param methodStartTime Time spent on execution of resource method itself (Unix timestamp format).
          * @param methodDuration Time of execution of the resource method.
          * @param requestStartTime Time of whole request processing (from receiving the request
-         *                         until writing the response). (Unix timestamp format)
+         * until writing the response). (Unix timestamp format)
          * @param requestDuration Time when the request matching to the executed resource method has been received
-         *                         by Jersey.
+         * by Jersey.
          */
-        void addResourceMethodExecution(long methodStartTime, long methodDuration,
-                                        long requestStartTime, long requestDuration) {
+        void addResourceMethodExecution(final long methodStartTime, final long methodDuration, final long requestStartTime,
+                                        final long requestDuration) {
+            cached = null;
+
+            if (resourceMethodExecutionStatisticsBuilder == null) {
+                resourceMethodExecutionStatisticsBuilder = new ExecutionStatisticsImpl.Builder();
+            }
             resourceMethodExecutionStatisticsBuilder.addExecution(methodStartTime, methodDuration);
+
+            if (requestExecutionStatisticsBuilder == null) {
+                requestExecutionStatisticsBuilder = new ExecutionStatisticsImpl.Builder();
+            }
             requestExecutionStatisticsBuilder.addExecution(requestStartTime, requestDuration);
         }
     }
 
-    private final ExecutionStatisticsImpl resourceMethodExecutionStatisticsImpl;
-    private final ExecutionStatisticsImpl requestExecutionStatisticsImpl;
+    private final ExecutionStatistics resourceMethodExecutionStatistics;
+    private final ExecutionStatistics requestExecutionStatistics;
     private final ResourceMethod resourceMethod;
 
-
-    private ResourceMethodStatisticsImpl(ResourceMethod resourceMethod, ExecutionStatisticsImpl resourceMethodExecutionStatisticsImpl,
-                                         ExecutionStatisticsImpl requestExecutionStatisticsImpl) {
-        this.resourceMethodExecutionStatisticsImpl = resourceMethodExecutionStatisticsImpl;
+    private ResourceMethodStatisticsImpl(final ResourceMethod resourceMethod,
+                                         final ExecutionStatistics resourceMethodExecutionStatistics,
+                                         final ExecutionStatistics requestExecutionStatistics) {
         this.resourceMethod = resourceMethod;
-        this.requestExecutionStatisticsImpl = requestExecutionStatisticsImpl;
+
+        this.resourceMethodExecutionStatistics = resourceMethodExecutionStatistics;
+        this.requestExecutionStatistics = requestExecutionStatistics;
     }
 
     @Override
     public ExecutionStatistics getRequestStatistics() {
-        return requestExecutionStatisticsImpl;
+        return requestExecutionStatistics;
     }
 
     @Override
     public ExecutionStatistics getMethodStatistics() {
-        return resourceMethodExecutionStatisticsImpl;
+        return resourceMethodExecutionStatistics;
     }
 
     public ResourceMethod getResourceMethod() {
Project jersey/jersey in file ...glassfish.jersey.message.internal.HeaderUtils.java (2014-01-19)
@@ -0,0 +1,293 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2010-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * http://glassfish.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+package org.glassfish.jersey.message.internal;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.AbstractMultivaluedMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.RuntimeDelegate;
+import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
+
+import org.glassfish.jersey.internal.LocalizationMessages;
+import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;
+import org.glassfish.jersey.internal.util.collection.StringKeyIgnoreCaseMultivaluedMap;
+
+import jersey.repackaged.com.google.common.base.Function;
+import jersey.repackaged.com.google.common.collect.Lists;
+import jersey.repackaged.com.google.common.collect.Maps;
+import jersey.repackaged.com.google.common.collect.ImmutableMap;
+
+/**
+ * Utility class supporting the processing of message headers.
+ *
+ * @author Marek Potociar (marek.potociar at oracle.com)
+ * @author Michal Gajdos (michal.gajdos at oracle.com)
+ * @author Libor Kramolis (libor.kramolis at oracle.com)
+ */
+public final class HeaderUtils {
+
+    private final static Logger LOGGER = Logger.getLogger(HeaderUtils.class.getName());
+
+    /**
+     * Create an empty inbound message headers container. Created container is mutable.
+     *
+     * @return a new empty mutable container for storing inbound message headers.
+     */
+    public static AbstractMultivaluedMap<String, String> createInbound() {
+        return new StringKeyIgnoreCaseMultivaluedMap<String>();
+    }
+
+    /**
+     * Get immutable empty message headers container. The factory method can be
+     * used to for both message header container types&nbsp;&nbsp;&ndash;&nbsp;&nbsp;inbound
+     * as well as outbound.
+     *
+     * @param <V> header value type. Typically {@link Object} in case of the outbound
+     *            headers and {@link String} in case of the inbound headers.
+     * @return an immutable empty message headers container.
+     */
+    public static <V> MultivaluedMap<String, V> empty() {
+        return ImmutableMultivaluedMap.empty();
+    }
+
+    /**
+     * Create an empty outbound message headers container. Created container is mutable.
+     *
+     * @return a new empty mutable container for storing outbound message headers.
+     */
+    public static AbstractMultivaluedMap<String, Object> createOutbound() {
+        return new StringKeyIgnoreCaseMultivaluedMap<Object>();
+    }
+
+    /**
+     * Convert a message header value, represented as a general object, to it's
+     * string representation. If the supplied header value is {@code null},
+     * this method returns {@code null}.
+     * <p>
+     * This method defers to {@link RuntimeDelegate#createHeaderDelegate} to
+     * obtain a {@link HeaderDelegate} to convert the value to a {@code String}.
+     * If a {@link HeaderDelegate} is not found then the {@code toString()}
+     * method on the header object is utilized.
+     *
+     * @param headerValue the header value represented as an object.
+     * @param rd          runtime delegate instance to be used for header delegate
+     *                    retrieval. If {@code null}, a default {@code RuntimeDelegate}
+     *                    instance will be {@link RuntimeDelegate#getInstance() obtained} and
+     *                    used.
+     * @return the string representation of the supplied header value or {@code null}
+     *         if the supplied header value is {@code null}.
+     */
+    @SuppressWarnings("unchecked")
+    public static String asString(final Object headerValue, RuntimeDelegate rd) {
+        if (headerValue == null) {
+            return null;
+        }
+        if (headerValue instanceof String) {
+            return (String) headerValue;
+        }
+        if (rd == null) {
+            rd = RuntimeDelegate.getInstance();
+        }
+
+        final HeaderDelegate hp = rd.createHeaderDelegate(headerValue.getClass());
+        return (hp != null) ? hp.toString(headerValue) : headerValue.toString();
+    }
+
+    /**
+     * Returns string view of list of header values. Any modifications to the underlying list are visible to the view,
+     * the view also supports removal of elements. Does not support other modifications.
+     *
+     * @param headerValues header values.
+     * @param rd           RuntimeDelegate instance or {@code null} (in that case {@link RuntimeDelegate#getInstance()}
+     *                     will be called for before element conversion.
+     * @return String view of header values.
+     */
+    public static List<String> asStringList(final List<Object> headerValues, final RuntimeDelegate rd) {
+        if (headerValues == null || headerValues.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final RuntimeDelegate delegate;
+        if (rd == null) {
+            delegate = RuntimeDelegate.getInstance();
+        } else {
+            delegate = rd;
+        }
+
+        return Lists.transform(headerValues, new Function<Object, String>() {
+            @Override
+            public String apply(Object input) {
+                return (input == null) ? "[null]" : HeaderUtils.asString(input, delegate);
+            }
+
+        });
+    }
+
+    /**
+     * Returns string view of passed headers. Any modifications to the headers are visible to the view, the view also
+     * supports removal of elements. Does not support other modifications.
+     *
+     * @param headers headers.
+     * @return String view of headers or {@code null} if {code headers} input parameter is {@code null}.
+     */
+    public static MultivaluedMap<String, String> asStringHeaders(final MultivaluedMap<String, Object> headers) {
+        if (headers == null) {
+            return null;
+        }
+
+        final RuntimeDelegate rd = RuntimeDelegate.getInstance();
+        return new AbstractMultivaluedMap<String, String>(
+                Maps.transformValues(headers, new Function<List<Object>, List<String>>() {
+                    @Override
+                    public List<String> apply(List<Object> input) {
+                        return HeaderUtils.asStringList(input, rd);
+                    }
+                })
+        ) {
+        };
+    }
+
+    /**
+     * Transforms multi value map of headers to single {@code String} value map.
+     *
+     * Returned map is immutable. Map values are formatted using method {@link #asHeaderString}.
+     *
+     * @param headers headers to be formatted
+     * @return immutable single {@code String} value map or
+     *      {@code null} if {@code headers} input parameter is {@code null}.
+     */
+    public static Map<String, String> asStringHeadersSingleValue(final MultivaluedMap<String, Object> headers) {
+        if (headers == null) {
+            return null;
+        }
+
+        final RuntimeDelegate rd = RuntimeDelegate.getInstance();
+        ImmutableMap.Builder<String, String> immutableMapBuilder = new ImmutableMap.Builder<String, String>();
+        for (Map.Entry<? extends String, ? extends List<Object>> entry : headers.entrySet()) {
+            immutableMapBuilder.put(entry.getKey(), asHeaderString(entry.getValue(), rd));
+        }
+        return immutableMapBuilder.build();
+    }
+
+    /**
+     * Converts a list of message header values to a single string value (with individual values separated by
+     * {@code ','}).
+     *
+     * Each single header value is converted to String using a
+     * {@link javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate} if one is available
+     * via {@link javax.ws.rs.ext.RuntimeDelegate#createHeaderDelegate(java.lang.Class)}
+     * for the header value class or using its {@code toString()} method if a header
+     * delegate is not available.
+     *
+     * @param values list of individual header values.
+     * @param rd     {@link RuntimeDelegate} instance or {@code null} (in that case {@link RuntimeDelegate#getInstance()}
+     *               will be called for before conversion of elements).
+     * @return single string consisting of all the values passed in as a parameter. If values parameter is {@code null},
+     *         {@code null} is returned. If the list of values is empty, an empty string is returned.
+     */
+    public static String asHeaderString(List<Object> values, RuntimeDelegate rd) {
+        if (values == null) {
+            return null;
+        }
+        final Iterator<String> stringValues = asStringList(values, rd).iterator();
+        if (!stringValues.hasNext()) {
+            return "";
+        }
+
+        StringBuilder buffer = new StringBuilder(stringValues.next());
+        while (stringValues.hasNext()) {
+            buffer.append(',').append(stringValues.next());
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * Compares two snapshots of headers from jersey {@code ClientRequest} and logs {@code WARNING} in case of difference.
+     *
+     * Current container implementations does not support header modification in {@link javax.ws.rs.ext.WriterInterceptor}
+     * and {@link javax.ws.rs.ext.MessageBodyWriter}. The method checks there are some newly added headers
+     * (probably by WI or MBW) and logs {@code WARNING} message about it.
+     *
+     * @param headersSnapshot first immutable snapshot of headers
+     * @param currentHeaders  current instance of headers tobe compared to
+     * @param connectorName   name of connector the method is invoked from, used just in logged message
+     * @see <a href="https://java.net/jira/browse/JERSEY-2341">JERSEY-2341</a>
+     */
+    public static void checkHeaderChanges(final Map<String, String> headersSnapshot,
+                                          final MultivaluedMap<String, Object> currentHeaders,
+                                          final String connectorName) {
+        if (HeaderUtils.LOGGER.isLoggable(Level.WARNING)) {
+            final RuntimeDelegate rd = RuntimeDelegate.getInstance();
+            Set<String> changedHeaderNames = new HashSet<String>();
+            for (Map.Entry<? extends String, ? extends List<Object>> entry : currentHeaders.entrySet()) {
+                if (!headersSnapshot.containsKey(entry.getKey())) {
+                    changedHeaderNames.add(entry.getKey());
+                } else {
+                    String prevValue = headersSnapshot.get(entry.getKey());
+                    String newValue = asHeaderString(currentHeaders.get(entry.getKey()), rd);
+                    if (!prevValue.equals(newValue)) {
+                        changedHeaderNames.add(entry.getKey());
+                    }
+                }
+            }
+            if (!changedHeaderNames.isEmpty()) {
+                if (HeaderUtils.LOGGER.isLoggable(Level.WARNING)) {
+                    HeaderUtils.LOGGER.warning(LocalizationMessages.SOME_HEADERS_NOT_SENT(connectorName,
+                            changedHeaderNames.toString()));
+                }
+            }
+        }
+    }
+
+    /**
+     * Preventing instantiation.
+     */
+    private HeaderUtils() {
+    }
+}