You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2015/12/26 14:34:42 UTC

svn commit: r1721731 - in /sling/trunk/bundles/commons/osgi/src: main/java/org/apache/sling/commons/osgi/ test/java/org/apache/sling/commons/osgi/

Author: kwin
Date: Sat Dec 26 13:34:42 2015
New Revision: 1721731

URL: http://svn.apache.org/viewvc?rev=1721731&view=rev
Log:
SLING-5041 allow to explicitly give ordering in RankedServices and in ServiceUtil

deprecate constructors not having a dedicated order parameter

Added:
    sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/Order.java   (with props)
Modified:
    sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/RankedServices.java
    sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ServiceUtil.java
    sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/RankedServicesTest.java

Added: sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/Order.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/Order.java?rev=1721731&view=auto
==============================================================================
--- sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/Order.java (added)
+++ sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/Order.java Sat Dec 26 13:34:42 2015
@@ -0,0 +1,37 @@
+/*
+ * 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.sling.commons.osgi;
+
+/**
+ * Order for services being sorted by {@link ServiceUtil#getComparableForServiceRanking(java.util.Map, Order)}
+ * or {@link RankedServices}. Either {@link #ASCENDING} meaning services with lowest service ranking first or 
+ * {@link #DESCENDING} meaning services with highest service ranking first.
+ */
+enum Order {
+    ASCENDING(-1, 1),
+    DESCENDING(1, -1);
+
+    public final int lessThan;
+    public final int greaterThan;
+
+    private Order(int lessThan, int greaterThan) {
+        this.lessThan = lessThan;
+        this.greaterThan = greaterThan;
+    }
+}
\ No newline at end of file

Propchange: sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/Order.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/RankedServices.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/RankedServices.java?rev=1721731&r1=1721730&r2=1721731&view=diff
==============================================================================
--- sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/RankedServices.java (original)
+++ sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/RankedServices.java Sat Dec 26 13:34:42 2015
@@ -27,6 +27,8 @@ import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+import org.osgi.framework.BundleContext;
+
 import aQute.bnd.annotation.ConsumerType;
 import aQute.bnd.annotation.ProviderType;
 
@@ -39,7 +41,7 @@ import aQute.bnd.annotation.ProviderType
  * <pre>
  * &#64;Reference(name = "myService", referenceInterface = MyService.class,
  *     cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
- * private final RankedServices&lt;MyService&gt; myServices = new RankedServices&lt;MyService&gt;();
+ * private final RankedServices&lt;MyService&gt; myServices = new RankedServices&lt;MyService&gt;(Order.DESCENDING);
  * </pre>
  * <p>2. Define bind/unbind methods that delegate to the RankedServices instance:</p>
  * <pre>
@@ -67,19 +69,50 @@ public final class RankedServices<T> imp
   private final ChangeListener changeListener;
   private final SortedMap<Comparable<Object>, T> serviceMap = new TreeMap<Comparable<Object>, T>();
   private volatile Collection<T> sortedServices = Collections.emptyList();
+  private final Order order;
 
   /**
-   * Instantiate without change listener.
+   * Instantiate without change listener in ascending order (lowest service ranking first).
+   * @deprecated Use {@link #RankedService(Order)}) to explicitly give the order.
    */
+  @Deprecated
   public RankedServices() {
-    this(null);
+    this(Order.ASCENDING, null);
+  }
+  
+  /**
+   * Instantiate with change listener in ascending order ((lowest service ranking first).
+   * @param changeListener Change listener
+   * @deprecated use {@link #RankedServices(Order order, ChangeListener changeListener)}  instead 
+   */
+  @Deprecated
+  public RankedServices(ChangeListener changeListener) {
+    this(Order.ASCENDING, changeListener);
+  }
+  
+  /**
+   * Instantiate without change listener but with a given order.
+   * @param order the order in which the services should be returned in {@link #iterator()} and {@link #get()}. 
+   *              Either {@link Order#ASCENDING} or {@link Order#DESCENDING}.
+   *              Use {@link Order#DESCENDING} if you want to have the service with the highest ranking returned first
+   *              (this is the service which would also be chosen by {@link BundleContext#getServiceReference(String)}).
+   * @since 2.4
+   */
+  public RankedServices(Order order) {
+    this(order, null);
   }
 
   /**
    * Instantiate with change listener.
+   * @param order the order in which the services should be returned in {@link #iterator()} and {@link #get()}. 
+   *              Either {@link Order#ASCENDING} or {@link Order#DESCENDING}.
+   *              Use {@link Order#DESCENDING} if you want to have the service with the highest ranking returned first
+   *              (this is the service which would also be chosen by {@link BundleContext#getServiceReference(String)}).
    * @param changeListener Change listener
+   * @since 2.4
    */
-  public RankedServices(ChangeListener changeListener) {
+  public RankedServices(Order order, ChangeListener changeListener) {
+    this.order = order;
     this.changeListener = changeListener;
   }
 
@@ -90,7 +123,7 @@ public final class RankedServices<T> imp
    */
   public void bind(T service, Map<String, Object> props) {
     synchronized (serviceMap) {
-      serviceMap.put(ServiceUtil.getComparableForServiceRanking(props), service);
+      serviceMap.put(ServiceUtil.getComparableForServiceRanking(props, order), service);
       updateSortedServices();
     }
   }
@@ -102,7 +135,7 @@ public final class RankedServices<T> imp
    */
   public void unbind(T service, Map<String, Object> props) {
     synchronized (serviceMap) {
-      serviceMap.remove(ServiceUtil.getComparableForServiceRanking(props));
+      serviceMap.remove(ServiceUtil.getComparableForServiceRanking(props, order));
       updateSortedServices();
     }
   }
@@ -119,7 +152,8 @@ public final class RankedServices<T> imp
   }
 
   /**
-   * Lists all services registered in OSGi, sorted by service ranking.
+   * Lists all services registered in OSGi, sorted by service ranking
+   * (either ascending or descending depending on the order given in the constructor).
    * @return Collection of service instances
    */
   public Collection<T> get() {
@@ -127,7 +161,8 @@ public final class RankedServices<T> imp
   }
 
   /**
-   * Iterates all services registered in OSGi, sorted by service ranking.
+   * Iterates all services registered in OSGi, sorted by service ranking
+   * (either ascending or descending depending on the order given in the constructor).
    * @return Iterator with service instances.
    */
   public Iterator<T> iterator() {

Modified: sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ServiceUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ServiceUtil.java?rev=1721731&r1=1721730&r2=1721731&view=diff
==============================================================================
--- sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ServiceUtil.java (original)
+++ sling/trunk/bundles/commons/osgi/src/main/java/org/apache/sling/commons/osgi/ServiceUtil.java Sat Dec 26 13:34:42 2015
@@ -20,6 +20,7 @@ package org.apache.sling.commons.osgi;
 
 import java.util.Map;
 
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 
@@ -31,22 +32,41 @@ import org.osgi.framework.ServiceReferen
 public class ServiceUtil {
 
     /**
+     * @deprecated Use {@link #getComparableForServiceRanking(Map, Order)} instead.
+     * @param props The service properties.
+     * @return the same comparable as returned by {@link #getComparableForServiceRanking(Map, Order.ASCENDING)}
+     * @see #getComparableForServiceRanking(Map, Order)
+     */
+    @Deprecated
+    public static Comparable<Object> getComparableForServiceRanking(final Map<String, Object> props) {
+        return getComparableForServiceRanking(props, Order.ASCENDING);
+    }
+
+    /**
      * Create a comparable object out of the service properties. With the result
      * it is possible to compare service properties based on the service ranking
-     * of a service. Therefore this object acts like {@link ServiceReference#compareTo(Object)}.
+     * of a service. This object acts like {@link ServiceReference#compareTo(Object)}.
+     * The comparator will return the services in the given order. In ascending order the 
+     * service with the lowest ranking comes first, in descending order the service with the 
+     * highest ranking comes first. The latter is useful if you want to have the service 
+     * returned first which is also chosen by {@link BundleContext#getServiceReference(String)}).
      * @param props The service properties.
+     * @param order The order (either ascending or descending).
      * @return A comparable for the ranking of the service
+     * @since 2.4
      */
-    public static Comparable<Object> getComparableForServiceRanking(final Map<String, Object> props) {
-        return new ComparableImplementation(props);
+    public static Comparable<Object> getComparableForServiceRanking(final Map<String, Object> props, Order order) {
+        return new ComparableImplementation(props, order);
     }
 
     private static final class ComparableImplementation implements Comparable<Object> {
 
         private final Map<String, Object> props;
+        private final Order order;
 
-        private ComparableImplementation(Map<String, Object> props) {
+        private ComparableImplementation(Map<String, Object> props, Order order) {
             this.props = props;
+            this.order = order;
         }
 
         @SuppressWarnings("unchecked")
@@ -83,15 +103,15 @@ public class ServiceUtil {
             Integer otherRank = (otherRankObj instanceof Integer)
                 ? (Integer) otherRankObj : new Integer(0);
 
-            // Sort by rank in ascending order.
+            // Sort by rank.
             if (rank.compareTo(otherRank) < 0) {
-                return -1; // lower rank
+                return order.lessThan; // lower rank
             } else if (rank.compareTo(otherRank) > 0) {
-                return 1; // higher rank
+                return order.greaterThan; // higher rank
             }
 
-            // If ranks are equal, then sort by service id in descending order.
-            return (id.compareTo(otherId) < 0) ? 1 : -1;
+            // If ranks are equal, then sort by service id.
+            return (id.compareTo(otherId) < 0) ? order.greaterThan : order.lessThan;
         }
 
         @Override

Modified: sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/RankedServicesTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/RankedServicesTest.java?rev=1721731&r1=1721730&r2=1721731&view=diff
==============================================================================
--- sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/RankedServicesTest.java (original)
+++ sling/trunk/bundles/commons/osgi/src/test/java/org/apache/sling/commons/osgi/RankedServicesTest.java Sat Dec 26 13:34:42 2015
@@ -45,7 +45,7 @@ public class RankedServicesTest {
       .put(Constants.SERVICE_RANKING, 100).put(Constants.SERVICE_ID, 3L).build();
 
   @Test
-  public void testSortedServices() {
+  public void testSortedServicesAscending() {
     RankedServices<Comparable> underTest = new RankedServices<Comparable>();
     assertEquals(0, underTest.get().size());
 
@@ -69,6 +69,32 @@ public class RankedServicesTest {
     assertSame(SERVICE_3, services[1]);
   }
 
+
+  @Test
+  public void testSortedServicesDescending() {
+    RankedServices<Comparable> underTest = new RankedServices<Comparable>(Order.DESCENDING);
+    assertEquals(0, underTest.get().size());
+
+    underTest.bind(SERVICE_1, SERVICE_1_PROPS);
+    assertEquals(1, underTest.get().size());
+    Comparable[] services = Iterators.toArray(underTest.get().iterator(), Comparable.class);
+    assertSame(SERVICE_1, services[0]);
+
+    underTest.bind(SERVICE_2, SERVICE_2_PROPS);
+    underTest.bind(SERVICE_3, SERVICE_3_PROPS);
+    assertEquals(3, underTest.get().size());
+    services = Iterators.toArray(underTest.get().iterator(), Comparable.class);
+    assertSame(SERVICE_3, services[0]);
+    assertSame(SERVICE_1, services[1]);
+    assertSame(SERVICE_2, services[2]);
+
+    underTest.unbind(SERVICE_2, SERVICE_2_PROPS);
+    assertEquals(2, underTest.get().size());
+    services = Iterators.toArray(underTest.get().iterator(), Comparable.class);
+    assertSame(SERVICE_3, services[0]);
+    assertSame(SERVICE_1, services[1]);
+  }
+
   @Test
   public void testChangeListener() {
     ChangeListener changeListener = mock(ChangeListener.class);