incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r1402507 - in /sling/trunk/bundles/extensions/adapter/src: main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java
Date Fri, 26 Oct 2012 13:35:24 GMT
Author: cziegeler
Date: Fri Oct 26 13:35:24 2012
New Revision: 1402507

URL: http://svn.apache.org/viewvc?rev=1402507&view=rev
Log:
SLING-2630 :  Cannot have multiple Adapter Factories configured to have same adapter / adaptable
combination . Applied patch from Will McGauley

Modified:
    sling/trunk/bundles/extensions/adapter/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
    sling/trunk/bundles/extensions/adapter/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java

Modified: sling/trunk/bundles/extensions/adapter/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/adapter/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java?rev=1402507&r1=1402506&r2=1402507&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/adapter/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
(original)
+++ sling/trunk/bundles/extensions/adapter/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
Fri Oct 26 13:35:24 2012
@@ -24,12 +24,10 @@ import static org.apache.sling.api.adapt
 import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
@@ -67,7 +65,7 @@ import org.slf4j.LoggerFactory;
 
 })
 @Reference(name="AdapterFactory", referenceInterface=AdapterFactory.class,
-    cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE, policy=ReferencePolicy.DYNAMIC)
+cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE, policy=ReferencePolicy.DYNAMIC)
 public class AdapterManagerImpl implements AdapterManager {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
@@ -104,8 +102,8 @@ public class AdapterManagerImpl implemen
      * {@link #getAdapterFactories(Class)} method. It is cleared
      * whenever an adapter factory is registered on unregistered.
      */
-    private final ConcurrentMap<String, Map<String, AdapterFactoryDescriptor>>
factoryCache
-                   = new ConcurrentHashMap<String, Map<String, AdapterFactoryDescriptor>>();
+    private final ConcurrentMap<String, Map<String, List<AdapterFactoryDescriptor>>>
factoryCache
+    = new ConcurrentHashMap<String, Map<String, List<AdapterFactoryDescriptor>>>();
 
     /**
      * The service tracker for the event admin
@@ -125,18 +123,28 @@ public class AdapterManagerImpl implemen
             final Class<AdapterType> type) {
 
         // get the adapter factories for the type of adaptable object
-        final Map<String, AdapterFactoryDescriptor> factories = getAdapterFactories(adaptable.getClass());
+        final Map<String, List<AdapterFactoryDescriptor>> factories = getAdapterFactories(adaptable.getClass());
 
         // get the factory for the target type
-        final AdapterFactoryDescriptor desc = factories.get(type.getName());
-        final AdapterFactory factory = desc == null ? null : desc.getFactory();
+        final List<AdapterFactoryDescriptor> descList = factories.get(type.getName());
 
-        // have the factory adapt the adaptable if the factory exists
-        if (factory != null) {
-            log.debug("Using adapter factory {} to map {} to {}",
-                    new Object [] { factory, adaptable, type });
-
-            return factory.getAdapter(adaptable, type);
+        if (descList != null && descList.size() > 0) {
+            for (AdapterFactoryDescriptor desc : descList) {
+                final AdapterFactory factory = desc == null ? null : desc.getFactory();
+
+                // have the factory adapt the adaptable if the factory exists
+                if (factory != null) {
+                    log.debug("Trying adapter factory {} to map {} to {}",
+                            new Object [] { factory, adaptable, type });
+
+                    AdapterType adaptedObject = factory.getAdapter(adaptable, type);
+                    if (adaptedObject != null) {
+                        log.debug("Using adapter factory {} to map {} to {}",
+                                new Object [] { factory, adaptable, type });
+                        return adaptedObject;
+                    }
+                }
+            }
         }
 
         // no factory has been found, so we cannot adapt
@@ -221,7 +229,7 @@ public class AdapterManagerImpl implemen
      * <strong><em>THIS METHOD IS FOR UNIT TESTING ONLY. IT MAY BE REMOVED OR
      * MODIFIED WITHOUT NOTICE.</em></strong>
      */
-    Map<String, Map<String, AdapterFactoryDescriptor>> getFactoryCache() {
+    Map<String, Map<String, List<AdapterFactoryDescriptor>>> getFactoryCache()
{
         return factoryCache;
     }
 
@@ -235,12 +243,12 @@ public class AdapterManagerImpl implemen
         final String[] adapters = PropertiesUtil.toStringArray(reference.getProperty(ADAPTER_CLASSES));
 
         if (adaptables == null || adaptables.length == 0 || adapters == null
-            || adapters.length == 0) {
+                || adapters.length == 0) {
             return;
         }
 
         final AdapterFactoryDescriptor factoryDesc = new AdapterFactoryDescriptor(context,
-            reference, adapters);
+                reference, adapters);
 
         for (final String adaptable : adaptables) {
             AdapterFactoryDescriptorMap adfMap = null;
@@ -282,7 +290,7 @@ public class AdapterManagerImpl implemen
         final String[] adapters = PropertiesUtil.toStringArray(reference.getProperty(ADAPTER_CLASSES));
 
         if (adaptables == null || adaptables.length == 0 || adapters == null
-            || adapters.length == 0) {
+                || adapters.length == 0) {
             return;
         }
 
@@ -323,14 +331,13 @@ public class AdapterManagerImpl implemen
      *
      * @param clazz The adaptable <code>Class</code> for which to return the
      *            adapter factory map by target class name.
-     * @param cache The cache of already defined adapter factory mappings
      * @return The map of adapter factories by target class name. The map may be
      *         empty if there is no adapter factory for the adaptable
      *         <code>clazz</code>.
      */
-    private Map<String, AdapterFactoryDescriptor> getAdapterFactories(final Class<?>
clazz) {
+    private Map<String, List<AdapterFactoryDescriptor>> getAdapterFactories(final
Class<?> clazz) {
         final String className = clazz.getName();
-        Map<String, AdapterFactoryDescriptor> entry = this.factoryCache.get(className);
+        Map<String, List<AdapterFactoryDescriptor>> entry = this.factoryCache.get(className);
         if (entry == null) {
             // create entry
             entry = createAdapterFactoryMap(clazz);
@@ -344,8 +351,7 @@ public class AdapterManagerImpl implemen
      * Creates a new target adapter factory map for the given <code>clazz</code>.
      * First all factories defined to support the adaptable class by
      * registration are taken. Next all factories for the implemented interfaces
-     * and finally all base class factories are copied. Later adapter factory
-     * entries do NOT overwrite earlier entries.
+     * and finally all base class factories are copied.
      *
      * @param clazz The adaptable <code>Class</code> for which to build the
      *            adapter factory map by target class name.
@@ -353,8 +359,8 @@ public class AdapterManagerImpl implemen
      *         empty if there is no adapter factory for the adaptable
      *         <code>clazz</code>.
      */
-    private Map<String, AdapterFactoryDescriptor> createAdapterFactoryMap(final Class<?>
clazz) {
-        final Map<String, AdapterFactoryDescriptor> afm = new HashMap<String, AdapterFactoryDescriptor>();
+    private Map<String, List<AdapterFactoryDescriptor>> createAdapterFactoryMap(final
Class<?> clazz) {
+        final Map<String, List<AdapterFactoryDescriptor>> afm = new HashMap<String,
List<AdapterFactoryDescriptor>>();
 
         // AdapterFactories for this class
         AdapterFactoryDescriptorMap afdMap = null;
@@ -362,18 +368,20 @@ public class AdapterManagerImpl implemen
             afdMap = this.descriptors.get(clazz.getName());
         }
         if (afdMap != null) {
-            final Set<AdapterFactoryDescriptor> afdSet;
+            final List<AdapterFactoryDescriptor> afdSet;
             synchronized ( afdMap ) {
-                afdSet = new HashSet<AdapterFactoryDescriptor>(afdMap.values());
+                afdSet = new ArrayList<AdapterFactoryDescriptor>(afdMap.values());
             }
             for (final AdapterFactoryDescriptor afd : afdSet) {
                 final String[] adapters = afd.getAdapters();
                 for (final String adapter : adapters) {
-                    // to handle service ranking, we only add if the map does not
-                    // have a value for this adapter yet
-                    if (!afm.containsKey(adapter)) {
-                        afm.put(adapter, afd);
+                    // to handle service ranking, we add to the end of the list or create
a new list
+                    List<AdapterFactoryDescriptor> factoryDescriptors = afm.get(adapter);
+                    if (factoryDescriptors == null) {
+                        factoryDescriptors = new ArrayList<AdapterFactoryDescriptor>();
+                        afm.put(adapter, factoryDescriptors);
                     }
+                    factoryDescriptors.add(afd);
                 }
             }
         }
@@ -405,17 +413,23 @@ public class AdapterManagerImpl implemen
      * @param clazz The adaptable class whose adapter factories are considered
      *            for adding into <code>dest</code>.
      */
-    private void copyAdapterFactories(final Map<String, AdapterFactoryDescriptor> dest,
+    private void copyAdapterFactories(final Map<String, List<AdapterFactoryDescriptor>>
dest,
             final Class<?> clazz) {
 
         // get the adapter factories for the adaptable clazz
-        final Map<String, AdapterFactoryDescriptor> scMap = getAdapterFactories(clazz);
+        final Map<String, List<AdapterFactoryDescriptor>> scMap = getAdapterFactories(clazz);
 
-        // for each target class copy the entry to dest if dest does
-        // not contain the target class already
-        for (Map.Entry<String, AdapterFactoryDescriptor> entry : scMap.entrySet())
{
-            if (!dest.containsKey(entry.getKey())) {
-                dest.put(entry.getKey(), entry.getValue());
+        // for each target class copy the entry to dest and put it in the list or create
the list
+        for (Map.Entry<String, List<AdapterFactoryDescriptor>> entry : scMap.entrySet())
{
+
+            List<AdapterFactoryDescriptor> factoryDescriptors = dest.get(entry.getKey());
+
+            if (factoryDescriptors == null) {
+                factoryDescriptors = new ArrayList<AdapterFactoryDescriptor>();
+                dest.put(entry.getKey(), factoryDescriptors);
+            }
+            for (AdapterFactoryDescriptor descriptor : entry.getValue()) {
+                factoryDescriptors.add(descriptor);
             }
         }
     }

Modified: sling/trunk/bundles/extensions/adapter/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/adapter/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java?rev=1402507&r1=1402506&r2=1402507&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/adapter/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java
(original)
+++ sling/trunk/bundles/extensions/adapter/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java
Fri Oct 26 13:35:24 2012
@@ -18,16 +18,11 @@
  */
 package org.apache.sling.adapter.internal;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Map;
-
 import org.apache.sling.adapter.mock.MockAdapterFactory;
 import org.apache.sling.api.adapter.AdapterFactory;
 import org.apache.sling.api.adapter.SlingAdaptable;
+import org.hamcrest.Matcher;
+import org.hamcrest.core.IsAnything;
 import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.jmock.integration.junit4.JMock;
@@ -41,6 +36,13 @@ import org.osgi.framework.ServiceListene
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
 
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 @RunWith(JMock.class)
 public class AdapterManagerTest {
 
@@ -90,11 +92,39 @@ public class AdapterManagerTest {
         return ctx;
     }
 
+        /**
+     * Helper method to create a mock component context
+     */
+    protected ComponentContext createMultipleAdaptersComponentContext(final ServiceReference
firstServiceReference, final ServiceReference secondServiceReference) throws Exception {
+        final BundleContext bundleCtx = this.context.mock(BundleContext.class);
+        final Filter filter = this.context.mock(Filter.class);
+        final ComponentContext ctx = this.context.mock(ComponentContext.class);
+        this.context.checking(new Expectations() {{
+            allowing(ctx).locateService(with(any(String.class)), with(firstServiceReference));
+            will(returnValue(new FirstImplementationAdapterFactory()));
+            allowing(ctx).locateService(with(any(String.class)), with(secondServiceReference));
+            will(returnValue(new SecondImplementationAdapterFactory()));
+            allowing(ctx).getBundleContext();
+            will(returnValue(bundleCtx));
+            allowing(bundleCtx).createFilter(with(any(String.class)));
+            will(returnValue(filter));
+            allowing(bundleCtx).addServiceListener(with(any(ServiceListener.class)), with(any(String.class)));
+            allowing(bundleCtx).getServiceReferences(with(any(String.class)), with(any(String.class)));
+            will(returnValue(null));
+            allowing(bundleCtx).removeServiceListener(with(any(ServiceListener.class)));
+        }});
+        return ctx;
+    }
+
+    public static <T> Matcher<T> any(@SuppressWarnings("unused") Class<T>
type) {
+        return new IsAnything<T>();
+    }
+
     /**
      * Helper method to create a mock service reference
      */
     protected ServiceReference createServiceReference() {
-        final ServiceReference ref = new ServiceReferenceImpl(1, new String[]{ TestSlingAdaptable.class.getName()
}, ITestAdapter.class.getName());
+        final ServiceReference ref = new ServiceReferenceImpl(1, new String[]{ TestSlingAdaptable.class.getName()
}, new String[]{ITestAdapter.class.getName()});
         return ref;
     }
 
@@ -102,9 +132,9 @@ public class AdapterManagerTest {
 
         private int ranking;
         private String[] adapters;
-        private String classes;
+        private String[] classes;
 
-        public ServiceReferenceImpl(final int order, final String[] adapters, final String
classes) {
+        public ServiceReferenceImpl(final int order, final String[] adapters, final String[]
classes) {
             this.ranking = order;
             this.adapters = adapters;
             this.classes = classes;
@@ -154,7 +184,7 @@ public class AdapterManagerTest {
      * Helper method to create a mock service reference
      */
     protected ServiceReference createServiceReference2() {
-        final ServiceReference ref = new ServiceReferenceImpl(2, new String[]{ TestSlingAdaptable2.class.getName()
}, TestAdapter.class.getName());
+        final ServiceReference ref = new ServiceReferenceImpl(2, new String[]{ TestSlingAdaptable2.class.getName()
}, new String[]{TestAdapter.class.getName()});
         return ref;
     }
 
@@ -289,6 +319,144 @@ public class AdapterManagerTest {
         assertTrue(adapter instanceof TestAdapter);
     }
 
+    @org.junit.Test public void testAdaptMultipleAdapterFactories() throws Exception {
+        final ServiceReference firstAdaptable = new ServiceReferenceImpl(1, new String[]{AdapterObject.class.getName()},
 new String[]{ ParentInterface.class.getName(), FirstImplementation.class.getName()});
+        final ServiceReference secondAdaptable = new ServiceReferenceImpl(2, new String[]{
AdapterObject.class.getName() }, new String[]{ParentInterface.class.getName(), SecondImplementation.class.getName()});
+
+        am.activate(this.createMultipleAdaptersComponentContext(firstAdaptable, secondAdaptable));
+
+        AdapterObject first = new AdapterObject(Want.FIRST_IMPL);
+        assertNull("Expect no adapter", am.getAdapter(first, ParentInterface.class));
+
+        AdapterObject second = new AdapterObject(Want.SECOND_IMPL);
+        assertNull("Expect no adapter", am.getAdapter(second, ParentInterface.class));
+
+        am.bindAdapterFactory(firstAdaptable);
+        am.bindAdapterFactory(secondAdaptable);
+
+        Object adapter = am.getAdapter(first, ParentInterface.class);
+        assertNotNull("Did not get an adapter back for first implementation, service ranking
1", adapter);
+        assertTrue("Did not get the correct adaptable back for first implementation, service
ranking 1, ", adapter instanceof FirstImplementation);
+
+        adapter = am.getAdapter(second, ParentInterface.class);
+        assertNotNull("Did not get an adapter back for second implementation, service ranking
2", adapter);
+        assertTrue("Did not get the correct adaptable back for second implementation, service
ranking 2, ", adapter instanceof SecondImplementation);
+
+        adapter = am.getAdapter(first, FirstImplementation.class);
+        assertNotNull("Did not get an adapter back for first implementation, service ranking
1", adapter);
+        assertTrue("Did not get the correct adaptable back for first implementation, service
ranking 1, ", adapter instanceof FirstImplementation);
+
+        adapter = am.getAdapter(second, SecondImplementation.class);
+        assertNotNull("Did not get an adapter back for second implementation, service ranking
2", adapter);
+        assertTrue("Did not get the correct adaptable back for second implementation, service
ranking 2, ", adapter instanceof SecondImplementation);
+    }
+
+    @org.junit.Test public void testAdaptMultipleAdapterFactoriesReverseOrder() throws Exception
{
+        final ServiceReference firstAdaptable = new ServiceReferenceImpl(2, new String[]{AdapterObject.class.getName()},
 new String[]{ ParentInterface.class.getName()});
+        final ServiceReference secondAdaptable = new ServiceReferenceImpl(1, new String[]{AdapterObject.class.getName()},
 new String[]{ ParentInterface.class.getName()});
+        am.activate(this.createMultipleAdaptersComponentContext(firstAdaptable, secondAdaptable));
+
+        AdapterObject first = new AdapterObject(Want.FIRST_IMPL);
+        assertNull("Expect no adapter", am.getAdapter(first, ParentInterface.class));
+
+        AdapterObject second = new AdapterObject(Want.SECOND_IMPL);
+        assertNull("Expect no adapter", am.getAdapter(second, ParentInterface.class));
+
+        am.bindAdapterFactory(firstAdaptable);
+        am.bindAdapterFactory(secondAdaptable);
+
+        Object adapter = am.getAdapter(first, ParentInterface.class);
+        assertNotNull("Did not get an adapter back for first implementation, service ranking
2", adapter);
+        assertTrue("Did not get the correct adaptable back for first implementation, service
ranking 2, ", adapter instanceof FirstImplementation);
+
+    }
+
+    @org.junit.Test public void testAdaptMultipleAdapterFactoriesServiceRanking() throws
Exception {
+        final ServiceReference firstAdaptable = new ServiceReferenceImpl(1, new String[]{AdapterObject.class.getName()},
 new String[]{ ParentInterface.class.getName(), FirstImplementation.class.getName()});
+        final ServiceReference secondAdaptable = new ServiceReferenceImpl(2, new String[]{
AdapterObject.class.getName() }, new String[]{ParentInterface.class.getName(), SecondImplementation.class.getName()});
+
+        am.activate(this.createMultipleAdaptersComponentContext(firstAdaptable, secondAdaptable));
+
+        AdapterObject first = new AdapterObject(Want.INDIFFERENT);
+        assertNull("Expect no adapter", am.getAdapter(first, ParentInterface.class));
+
+        AdapterObject second = new AdapterObject(Want.INDIFFERENT);
+        assertNull("Expect no adapter", am.getAdapter(second, ParentInterface.class));
+
+        am.bindAdapterFactory(firstAdaptable);
+        am.bindAdapterFactory(secondAdaptable);
+
+        Object adapter = am.getAdapter(first, ParentInterface.class);
+        assertNotNull("Did not get an adapter back for first implementation (from ParentInterface),
service ranking 1", adapter);
+        assertTrue("Did not get the correct adaptable back for first implementation, service
ranking 1, ", adapter instanceof FirstImplementation);
+
+        adapter = am.getAdapter(first, FirstImplementation.class);
+        assertNotNull("Did not get an adapter back for first implementation, service ranking
1", adapter);
+        assertTrue("Did not get the correct adaptable back for first implementation, service
ranking 1, ", adapter instanceof FirstImplementation);
+
+        adapter = am.getAdapter(second, SecondImplementation.class);
+        assertNotNull("Did not get an adapter back for second implementation, service ranking
2", adapter);
+        assertTrue("Did not get the correct adaptable back for second implementation, service
ranking 2, ", adapter instanceof SecondImplementation);
+    }
+
+    @org.junit.Test public void testAdaptMultipleAdapterFactoriesServiceRankingSecondHigherOrder()
throws Exception {
+        final ServiceReference firstAdaptable = new ServiceReferenceImpl(2, new String[]{AdapterObject.class.getName()},
 new String[]{ ParentInterface.class.getName(), FirstImplementation.class.getName()});
+        final ServiceReference secondAdaptable = new ServiceReferenceImpl(1, new String[]{
AdapterObject.class.getName() }, new String[]{ParentInterface.class.getName(), SecondImplementation.class.getName()});
+
+        am.activate(this.createMultipleAdaptersComponentContext(firstAdaptable, secondAdaptable));
+
+        AdapterObject first = new AdapterObject(Want.INDIFFERENT);
+        assertNull("Expect no adapter", am.getAdapter(first, ParentInterface.class));
+
+        AdapterObject second = new AdapterObject(Want.INDIFFERENT);
+        assertNull("Expect no adapter", am.getAdapter(second, ParentInterface.class));
+
+        am.bindAdapterFactory(firstAdaptable);
+        am.bindAdapterFactory(secondAdaptable);
+
+        Object adapter = am.getAdapter(first, ParentInterface.class);
+        assertNotNull("Did not get an adapter back for second implementation (from ParentInterface),
service ranking 1", adapter);
+        assertTrue("Did not get the correct adaptable back for second implementation, service
ranking 1, ", adapter instanceof SecondImplementation);
+
+        adapter = am.getAdapter(first, FirstImplementation.class);
+        assertNotNull("Did not get an adapter back for first implementation, service ranking
1", adapter);
+        assertTrue("Did not get the correct adaptable back for first implementation, service
ranking 1, ", adapter instanceof FirstImplementation);
+
+        adapter = am.getAdapter(second, SecondImplementation.class);
+        assertNotNull("Did not get an adapter back for second implementation, service ranking
2", adapter);
+        assertTrue("Did not get the correct adaptable back for second implementation, service
ranking 2, ", adapter instanceof SecondImplementation);
+    }
+
+    @org.junit.Test public void testAdaptMultipleAdapterFactoriesServiceRankingReverse()
throws Exception {
+        final ServiceReference firstAdaptable = new ServiceReferenceImpl(1, new String[]{AdapterObject.class.getName()},
 new String[]{ ParentInterface.class.getName(), FirstImplementation.class.getName()});
+        final ServiceReference secondAdaptable = new ServiceReferenceImpl(2, new String[]{
AdapterObject.class.getName() }, new String[]{ParentInterface.class.getName(), SecondImplementation.class.getName()});
+
+        am.activate(this.createMultipleAdaptersComponentContext(firstAdaptable, secondAdaptable));
+
+        AdapterObject first = new AdapterObject(Want.INDIFFERENT);
+        assertNull("Expect no adapter", am.getAdapter(first, ParentInterface.class));
+
+        AdapterObject second = new AdapterObject(Want.INDIFFERENT);
+        assertNull("Expect no adapter", am.getAdapter(second, ParentInterface.class));
+
+        // bind these in reverse order from the non-reverse test
+        am.bindAdapterFactory(secondAdaptable);
+        am.bindAdapterFactory(firstAdaptable);
+
+        Object adapter = am.getAdapter(first, ParentInterface.class);
+        assertNotNull("Did not get an adapter back for first implementation (from ParentInterface),
service ranking 1", adapter);
+        assertTrue("Did not get the correct adaptable back for first implementation, service
ranking 1, ", adapter instanceof FirstImplementation);
+
+        adapter = am.getAdapter(first, FirstImplementation.class);
+        assertNotNull("Did not get an adapter back for first implementation, service ranking
1", adapter);
+        assertTrue("Did not get the correct adaptable back for first implementation, service
ranking 1, ", adapter instanceof FirstImplementation);
+
+        adapter = am.getAdapter(second, SecondImplementation.class);
+        assertNotNull("Did not get an adapter back for second implementation, service ranking
2", adapter);
+        assertTrue("Did not get the correct adaptable back for second implementation, service
ranking 2, ", adapter instanceof SecondImplementation);
+    }
+
+
     //---------- Test Adaptable and Adapter Classes ---------------------------
 
     public static class TestSlingAdaptable extends SlingAdaptable {
@@ -307,4 +475,77 @@ public class AdapterManagerTest {
 
     }
 
+    public class FirstImplementationAdapterFactory implements AdapterFactory {
+
+        public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType>
type) {
+            if (adaptable instanceof AdapterObject) {
+                AdapterObject adapterObject = (AdapterObject) adaptable;
+                switch (adapterObject.getWhatWeWant()) {
+                    case FIRST_IMPL:
+                    case INDIFFERENT:
+                        return (AdapterType) new FirstImplementation();
+                    case SECOND_IMPL:
+                        return null;
+                }
+            }
+            throw new RuntimeException("Must pass the correct adaptable");
+        }
+    }
+
+    public class SecondImplementationAdapterFactory implements AdapterFactory {
+
+        public <AdapterType> AdapterType getAdapter(Object adaptable, Class<AdapterType>
type) {
+            if (adaptable instanceof AdapterObject) {
+                AdapterObject adapterObject = (AdapterObject) adaptable;
+                switch (adapterObject.getWhatWeWant()) {
+                    case SECOND_IMPL:
+                    case INDIFFERENT:
+                        return (AdapterType) new SecondImplementation();
+                    case FIRST_IMPL:
+                        return null;
+                }
+            }
+            throw new RuntimeException("Must pass the correct adaptable");
+        }
+    }
+
+    public static interface ParentInterface {
+    }
+
+    public static class FirstImplementation implements ParentInterface {
+    }
+
+    public static class SecondImplementation implements ParentInterface {
+    }
+
+    public enum Want {
+
+        /**
+         * Indicates we definitively want the "first implementation" adapter factory to execute
the adapt
+         */
+        FIRST_IMPL,
+
+        /**
+         * Indicates we definitively want the "second implementation" adapter factory to
execute the adapt
+         */
+        SECOND_IMPL,
+
+        /**
+         * Indicates we are indifferent to which factory is used to execute the adapt, used
for testing service ranking
+         */
+        INDIFFERENT
+    }
+
+    public static class AdapterObject {
+        private Want whatWeWant;
+
+        public AdapterObject(Want whatWeWant) {
+            this.whatWeWant = whatWeWant;
+        }
+
+        public Want getWhatWeWant() {
+            return whatWeWant;
+        }
+    }
+
 }



Mime
View raw message