Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 3D2D8D0DE for ; Fri, 26 Oct 2012 13:36:15 +0000 (UTC) Received: (qmail 33157 invoked by uid 500); 26 Oct 2012 13:36:14 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 33034 invoked by uid 500); 26 Oct 2012 13:36:11 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 32995 invoked by uid 99); 26 Oct 2012 13:36:10 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 26 Oct 2012 13:36:10 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 26 Oct 2012 13:36:08 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id AA97723889F7; Fri, 26 Oct 2012 13:35:24 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit 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 -0000 To: commits@sling.apache.org From: cziegeler@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20121026133524.AA97723889F7@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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> factoryCache - = new ConcurrentHashMap>(); + private final ConcurrentMap>> factoryCache + = new ConcurrentHashMap>>(); /** * The service tracker for the event admin @@ -125,18 +123,28 @@ public class AdapterManagerImpl implemen final Class type) { // get the adapter factories for the type of adaptable object - final Map factories = getAdapterFactories(adaptable.getClass()); + final Map> 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 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 * THIS METHOD IS FOR UNIT TESTING ONLY. IT MAY BE REMOVED OR * MODIFIED WITHOUT NOTICE. */ - Map> getFactoryCache() { + Map>> 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 Class 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 * clazz. */ - private Map getAdapterFactories(final Class clazz) { + private Map> getAdapterFactories(final Class clazz) { final String className = clazz.getName(); - Map entry = this.factoryCache.get(className); + Map> 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 clazz. * 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 Class 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 * clazz. */ - private Map createAdapterFactoryMap(final Class clazz) { - final Map afm = new HashMap(); + private Map> createAdapterFactoryMap(final Class clazz) { + final Map> afm = new HashMap>(); // 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 afdSet; + final List afdSet; synchronized ( afdMap ) { - afdSet = new HashSet(afdMap.values()); + afdSet = new ArrayList(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 factoryDescriptors = afm.get(adapter); + if (factoryDescriptors == null) { + factoryDescriptors = new ArrayList(); + 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 dest. */ - private void copyAdapterFactories(final Map dest, + private void copyAdapterFactories(final Map> dest, final Class clazz) { // get the adapter factories for the adaptable clazz - final Map scMap = getAdapterFactories(clazz); + final Map> scMap = getAdapterFactories(clazz); - // for each target class copy the entry to dest if dest does - // not contain the target class already - for (Map.Entry 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> entry : scMap.entrySet()) { + + List factoryDescriptors = dest.get(entry.getKey()); + + if (factoryDescriptors == null) { + factoryDescriptors = new ArrayList(); + 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 Matcher any(@SuppressWarnings("unused") Class type) { + return new IsAnything(); + } + /** * 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 getAdapter(Object adaptable, Class 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 getAdapter(Object adaptable, Class 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; + } + } + }