You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2014/07/20 23:37:36 UTC

git commit: TAP5-2192 : adds the ServiceConfigurationListener interface and the ServiceConfigurationListenerHub to receive the listeners

Repository: tapestry-5
Updated Branches:
  refs/heads/master 6bb909649 -> 90766995f


TAP5-2192 : adds the ServiceConfigurationListener interface and the ServiceConfigurationListenerHub to receive the listeners


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/90766995
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/90766995
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/90766995

Branch: refs/heads/master
Commit: 90766995f59048cb7f7d4cf042a21a9d728583db
Parents: 6bb9096
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sun Jul 20 18:37:08 2014 -0300
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sun Jul 20 18:37:08 2014 -0300

----------------------------------------------------------------------
 .../tapestry5/ioc/internal/RegistryImpl.java    | 178 ++++++++++++++++++-
 .../tapestry5/ioc/internal/ServiceDefImpl.java  |  26 +++
 .../ioc/internal/util/InternalUtils.java        |  26 +++
 .../ioc/modules/TapestryIOCModule.java          |   3 +-
 .../services/ServiceConfigurationListener.java  |  50 ++++++
 .../ServiceConfigurationListenerHub.java        |  44 +++++
 .../test/groovy/ioc/specs/RegistrySpec.groovy   |  37 ++++
 .../CatchAllServiceConfigurationListener.java   |  68 +++++++
 .../org/apache/tapestry5/ioc/FredModule.java    |  17 ++
 9 files changed, 444 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
index 3709fa8..51ca08a 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
@@ -65,7 +65,7 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
     static final String PLASTIC_PROXY_FACTORY_SERVICE_ID = "PlasticProxyFactory";
 
     static final String LOGGER_SOURCE_SERVICE_ID = "LoggerSource";
-
+    
     private final OneShotLock lock = new OneShotLock();
 
     private final OneShotLock eagerLoadLock = new OneShotLock();
@@ -109,7 +109,9 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
     private final Map<Class<? extends Annotation>, Annotation> cachedAnnotationProxies = CollectionFactory.newConcurrentMap();
 
     private final Set<Runnable> startups = CollectionFactory.newSet();
-
+    
+    private DelegatingServiceConfigurationListener serviceConfigurationListener;
+    
     /**
      * Constructs the registry from a set of module definitions and other resources.
      *
@@ -133,7 +135,10 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
         this.operationTracker = operationTracker;
 
         this.proxyFactory = proxyFactory;
-
+        
+        serviceConfigurationListener = new DelegatingServiceConfigurationListener(
+                loggerForBuiltinService(ServiceConfigurationListener.class.getSimpleName()));
+        
         Logger logger = loggerForBuiltinService(PERTHREAD_MANAGER_SERVICE_ID);
 
         PerthreadManagerImpl ptmImpl = new PerthreadManagerImpl(logger);
@@ -202,10 +207,13 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
         addBuiltin(PLASTIC_PROXY_FACTORY_SERVICE_ID, PlasticProxyFactory.class, proxyFactory);
 
         validateContributeDefs(moduleDefs);
+        
+        serviceConfigurationListener.setDelegates(getService(ServiceConfigurationListenerHub.class).getListeners());
 
         scoreboardAndTracker.startup();
 
         SerializationSupport.setProvider(this);
+        
     }
 
     private void addStartupsInModule(ModuleDef2 def, final Module module, final Logger logger)
@@ -425,6 +433,31 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
             {
                 return true;
             }
+            
+            @Override
+            public int hashCode()
+            {
+                final int prime = 31;
+                int result = 1;
+                result = prime * result + ((serviceId == null) ? 0 : serviceId.hashCode());
+                return result;
+            }
+
+            @Override
+            public boolean equals(Object obj)
+            {
+                if (this == obj) { return true; }
+                if (obj == null) { return false; }
+                if (!(obj instanceof ServiceDefImpl)) { return false; }
+                ServiceDef other = (ServiceDef) obj;
+                if (serviceId == null)
+                {
+                    if (other.getServiceId() != null) { return false; }
+                }
+                else if (!serviceId.equals(other.getServiceId())) { return false; }
+                return true;
+            }
+            
         };
 
         for (Class marker : serviceDef.getMarkers())
@@ -508,6 +541,11 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
 
         for (Module m : moduleToServiceDefs.keySet())
             addToUnorderedConfiguration(result, objectType, serviceDef, m);
+        
+        if (!isServiceConfigurationListenerServiceDef(serviceDef))
+        {
+            serviceConfigurationListener.onUnorderedConfiguration(serviceDef, result);
+        }
 
         return result;
     }
@@ -552,7 +590,19 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
         for (OrderedConfigurationOverride<T> override : overrides.values())
             override.apply();
 
-        return orderer.getOrdered();
+        final List<T> result = orderer.getOrdered();
+        
+        if (!isServiceConfigurationListenerServiceDef(serviceDef))
+        {
+            serviceConfigurationListener.onOrderedConfiguration(serviceDef, result);
+        }
+        
+        return result;
+    }
+    
+    private boolean isServiceConfigurationListenerServiceDef(ServiceDef serviceDef)
+    {
+        return serviceDef.getServiceId().equalsIgnoreCase(ServiceConfigurationListener.class.getSimpleName());
     }
 
     @Override
@@ -574,6 +624,11 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
             override.apply();
         }
 
+        if (!isServiceConfigurationListenerServiceDef(serviceDef))
+        {
+            serviceConfigurationListener.onMappedConfiguration(serviceDef, result);
+        }
+        
         return result;
     }
 
@@ -1223,4 +1278,119 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
         }
     }
     
+    final static private class DelegatingServiceConfigurationListener implements ServiceConfigurationListener {
+        
+        final private Logger logger;
+        
+        private List<ServiceConfigurationListener> delegates;
+        private Map<ServiceDef, Map> mapped = CollectionFactory.newMap();
+        private Map<ServiceDef, Collection> unordered = CollectionFactory.newMap();
+        private Map<ServiceDef, List> ordered = CollectionFactory.newMap();
+        
+        public DelegatingServiceConfigurationListener(Logger logger)
+        {
+            this.logger = logger;
+        }
+
+        public void setDelegates(List<ServiceConfigurationListener> delegates)
+        {
+            
+            this.delegates = delegates;
+            
+            for (ServiceDef serviceDef : mapped.keySet())
+            {
+                for (ServiceConfigurationListener delegate : delegates)
+                {
+                    delegate.onMappedConfiguration(serviceDef, Collections.unmodifiableMap(mapped.get(serviceDef)));
+                }
+            }
+
+            for (ServiceDef serviceDef : unordered.keySet())
+            {
+                for (ServiceConfigurationListener delegate : delegates)
+                {
+                    delegate.onUnorderedConfiguration(serviceDef, Collections.unmodifiableCollection(unordered.get(serviceDef)));
+                }
+            }
+
+            for (ServiceDef serviceDef : ordered.keySet())
+            {
+                for (ServiceConfigurationListener delegate : delegates)
+                {
+                    delegate.onOrderedConfiguration(serviceDef, Collections.unmodifiableList(ordered.get(serviceDef)));
+                }
+            }
+            
+            mapped.clear();
+            mapped = null;
+            unordered.clear();
+            unordered = null;
+            ordered.clear();
+            ordered = null;
+
+        }
+        
+        @Override
+        public void onOrderedConfiguration(ServiceDef serviceDef, List configuration)
+        {
+            log("ordered", serviceDef, configuration);
+            if (delegates == null)
+            {
+                ordered.put(serviceDef, configuration);
+            }
+            else
+            {
+                for (ServiceConfigurationListener delegate : delegates)
+                {
+                    delegate.onOrderedConfiguration(serviceDef, Collections.unmodifiableList(configuration));
+                }
+            }
+        }
+
+        @Override
+        public void onUnorderedConfiguration(ServiceDef serviceDef, Collection configuration)
+        {
+            log("unordered", serviceDef, configuration);
+            if (delegates == null)
+            {
+                unordered.put(serviceDef, configuration);
+            }
+            else
+            {
+                for (ServiceConfigurationListener delegate : delegates)
+                {
+                    delegate.onUnorderedConfiguration(serviceDef, Collections.unmodifiableCollection(configuration));
+                }
+            }
+        }
+
+        @Override
+        public void onMappedConfiguration(ServiceDef serviceDef, Map configuration)
+        {
+            log("mapped", serviceDef, configuration);
+            if (delegates == null)
+            {
+                mapped.put(serviceDef, configuration);
+            }
+            else
+            {
+                for (ServiceConfigurationListener delegate : delegates)
+                {
+                    delegate.onMappedConfiguration(serviceDef, Collections.unmodifiableMap(configuration));
+                }
+            }
+            
+        }
+        
+        private void log(String type, ServiceDef serviceDef, Object configuration)
+        {
+            if (logger.isDebugEnabled())
+            {
+                logger.debug(String.format("Service %s %s configuration: %s", 
+                        serviceDef.getServiceId(), type, configuration.toString()));
+            }
+        }
+        
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
index 7e35746..aeccb47 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
@@ -23,6 +23,7 @@ import org.apache.tapestry5.func.Mapper;
 import org.apache.tapestry5.ioc.AnnotationProvider;
 import org.apache.tapestry5.ioc.ObjectCreator;
 import org.apache.tapestry5.ioc.ServiceBuilderResources;
+import org.apache.tapestry5.ioc.def.ServiceDef;
 import org.apache.tapestry5.ioc.def.ServiceDef3;
 import org.apache.tapestry5.ioc.internal.services.AnnotationProviderChain;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
@@ -155,4 +156,29 @@ public class ServiceDefImpl implements ServiceDef3
             }
         }).map(InternalUtils.METHOD_TO_AP_MAPPER).toList());
     }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((serviceId == null) ? 0 : serviceId.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj) { return true; }
+        if (obj == null) { return false; }
+        if (!(obj instanceof ServiceDefImpl)) { return false; }
+        ServiceDef other = (ServiceDef) obj;
+        if (serviceId == null)
+        {
+            if (other.getServiceId() != null) { return false; }
+        }
+        else if (!serviceId.equals(other.getServiceId())) { return false; }
+        return true;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index 96c356b..e9e7806 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -22,6 +22,7 @@ import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.*;
 import org.apache.tapestry5.ioc.def.*;
 import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+import org.apache.tapestry5.ioc.internal.ServiceDefImpl;
 import org.apache.tapestry5.ioc.services.Coercion;
 import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
 import org.apache.tapestry5.ioc.util.ExceptionUtils;
@@ -1025,6 +1026,31 @@ public class InternalUtils
             {
                 return sd.toString();
             }
+            
+            @Override
+            public int hashCode()
+            {
+                final int prime = 31;
+                int result = 1;
+                result = prime * result + ((getServiceId() == null) ? 0 : getServiceId().hashCode());
+                return result;
+            }
+
+            @Override
+            public boolean equals(Object obj)
+            {
+                if (this == obj) { return true; }
+                if (obj == null) { return false; }
+                if (!(obj instanceof ServiceDefImpl)) { return false; }
+                ServiceDef other = (ServiceDef) obj;
+                if (getServiceId() == null)
+                {
+                    if (other.getServiceId() != null) { return false; }
+                }
+                else if (!getServiceId().equals(other.getServiceId())) { return false; }
+                return true;
+            }
+
         };
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
index 6e49788..a9af358 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
@@ -1,4 +1,4 @@
-// Copyright 2006-2013 The Apache Software Foundation
+// Copyright 2006-2014 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -76,6 +76,7 @@ public final class TapestryIOCModule
         binder.bind(UpdateListenerHub.class, UpdateListenerHubImpl.class).preventReloading();
         binder.bind(PeriodicExecutor.class, PeriodicExecutorImpl.class);
         binder.bind(OperationAdvisor.class, OperationAdvisorImpl.class);
+        binder.bind(ServiceConfigurationListenerHub.class);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceConfigurationListener.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceConfigurationListener.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceConfigurationListener.java
new file mode 100644
index 0000000..3531423
--- /dev/null
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceConfigurationListener.java
@@ -0,0 +1,50 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.services;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.def.ServiceDef;
+
+/**
+ * Interface that defines listeners to services getting their distributed configuration.
+ */
+@SuppressWarnings("rawtypes")
+public interface ServiceConfigurationListener
+{
+    
+    /**
+     * Receives a notification of an ordered configuraton being passed to a service.
+     * @param serviceDef a {@link ServiceDef} identifying the service receiving the configuration.
+     * @param configuration a {@link List} containing the configuration itself.
+     */
+    void onOrderedConfiguration(ServiceDef serviceDef, List configuration);
+
+    /**
+     * Receives a notification of an unordered configuraton being passed to a service.
+     * @param serviceDef a {@link ServiceDef} identifying the service receiving the configuration.
+     * @param configuration a {@link Collection} containing the configuration itself.
+     */
+    void onUnorderedConfiguration(ServiceDef serviceDef, Collection configuration);
+
+    /**
+     * Receives a notification of a mapped configuraton being passed to a service.
+     * @param serviceDef a {@link ServiceDef} identifying the service receiving the configuration.
+     * @param configuration a {@link Map} containing the configuration itself.
+     */
+    void onMappedConfiguration(ServiceDef serviceDef, Map configuration);
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceConfigurationListenerHub.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceConfigurationListenerHub.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceConfigurationListenerHub.java
new file mode 100644
index 0000000..a7b7980
--- /dev/null
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ServiceConfigurationListenerHub.java
@@ -0,0 +1,44 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.services;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
+
+/**
+ * Service that collects the {@link ServiceConfigurationListener}s. Don't use this service directly.
+ */
+@UsesOrderedConfiguration(ServiceConfigurationListener.class)
+final public class ServiceConfigurationListenerHub
+{
+    
+    final private List<ServiceConfigurationListener> listeners;
+    
+    public ServiceConfigurationListenerHub(List<ServiceConfigurationListener> listeners)
+    {
+        super();
+        this.listeners = Collections.unmodifiableList(listeners);
+    }
+
+    /**
+     * Returns the list of service configuration listeners. 
+     */
+    public List<ServiceConfigurationListener> getListeners()
+    {
+        return listeners;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/test/groovy/ioc/specs/RegistrySpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/RegistrySpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/RegistrySpec.groovy
index ef0bbc8..d429b0b 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/RegistrySpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/RegistrySpec.groovy
@@ -1,8 +1,13 @@
 package ioc.specs
 
+import org.apache.tapestry5.ioc.BarneyModule;
+import org.apache.tapestry5.ioc.CatchAllServiceConfigurationListener;
 import org.apache.tapestry5.ioc.Greeter
+import org.apache.tapestry5.ioc.FredModule
 import org.apache.tapestry5.ioc.GreeterModule
 import org.apache.tapestry5.ioc.HelterModule
+import org.apache.tapestry5.ioc.NameListHolder;
+import org.apache.tapestry5.ioc.StringLookup;
 import org.apache.tapestry5.ioc.internal.services.StartupModule2
 
 class RegistrySpec extends AbstractRegistrySpecification {
@@ -53,4 +58,36 @@ class RegistrySpec extends AbstractRegistrySpecification {
     StartupModule2.staticStartupInvoked
     StartupModule2.instanceStartupInvoked
   }
+  
+  def "ServiceConfigurationListener"() {
+      
+    buildRegistry FredModule, BarneyModule
+    
+    // for a given service, its configuration is only notified to the ServiceConfigurationListeners 
+    // when the service itself is realized, so we call one method of each to force their realization.
+    getService(StringLookup).keys()
+    getService("OrderedNames", NameListHolder).getNames()
+    getService("UnorderedNames", NameListHolder).getNames()
+      
+    when:
+      
+    def listener = getService CatchAllServiceConfigurationListener
+    def mappedConfiguration = listener.getMappedConfigurations().get("StringLookup")
+    def orderedConfiguration = listener.getOrderedConfigurations().get("OrderedNames");
+    def unorderedConfiguration = listener.getUnorderedConfigurations().get("UnorderedNames");
+      
+    then:
+    mappedConfiguration.size() == 4
+    mappedConfiguration.get("fred").equals("FRED")
+    mappedConfiguration.get("wilma").equals("WILMA")
+    mappedConfiguration.get("barney").equals("BARNEY")
+    mappedConfiguration.get("betty").equals("BETTY")
+    orderedConfiguration == ['BARNEY', 'FRED']
+    unorderedConfiguration.size() == 3
+    unorderedConfiguration.contains 'UnorderedNames'
+    unorderedConfiguration.contains 'Beta'
+    unorderedConfiguration.contains 'Gamma'
+    
+  }
+      
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CatchAllServiceConfigurationListener.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CatchAllServiceConfigurationListener.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CatchAllServiceConfigurationListener.java
new file mode 100644
index 0000000..b6d97df
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CatchAllServiceConfigurationListener.java
@@ -0,0 +1,68 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.def.ServiceDef;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ServiceConfigurationListener;
+
+/**
+ * Just for testing {@link ServiceConfigurationListener}.
+ */
+@SuppressWarnings("rawtypes")
+public class CatchAllServiceConfigurationListener implements ServiceConfigurationListener
+{
+    
+    final private Map<String, Map> mappedConfigurations = CollectionFactory.newCaseInsensitiveMap();
+    final private Map<String, List> orderedConfigurations = CollectionFactory.newCaseInsensitiveMap();
+    final private Map<String, Collection> unorderedConfigurations = CollectionFactory.newCaseInsensitiveMap();
+
+    @Override
+    public void onOrderedConfiguration(ServiceDef serviceDef, List configuration)
+    {
+        orderedConfigurations.put(serviceDef.getServiceId(), configuration);
+    }
+
+    @Override
+    public void onUnorderedConfiguration(ServiceDef serviceDef, Collection configuration)
+    {
+        unorderedConfigurations.put(serviceDef.getServiceId(), configuration);
+    }
+
+    @Override
+    public void onMappedConfiguration(ServiceDef serviceDef, Map configuration)
+    {
+        mappedConfigurations.put(serviceDef.getServiceId(), configuration);
+    }
+
+    public Map<String, Map> getMappedConfigurations()
+    {
+        return mappedConfigurations;
+    }
+
+    public Map<String, List> getOrderedConfigurations()
+    {
+        return orderedConfigurations;
+    }
+
+    public Map<String, Collection> getUnorderedConfigurations()
+    {
+        return unorderedConfigurations;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/90766995/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/FredModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/FredModule.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/FredModule.java
index 7ec3cae..28eac4f 100644
--- a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/FredModule.java
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/FredModule.java
@@ -14,10 +14,13 @@
 
 package org.apache.tapestry5.ioc;
 
+import org.apache.tapestry5.ioc.annotations.Contribute;
 import org.apache.tapestry5.ioc.annotations.Match;
 import org.apache.tapestry5.ioc.annotations.Order;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.ServiceConfigurationListener;
+import org.apache.tapestry5.ioc.services.ServiceConfigurationListenerHub;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -129,4 +132,18 @@ public class FredModule
         configuration.add("fred", "FRED");
         configuration.add("wilma", "WILMA");
     }
+    
+    
+    @Contribute(ServiceConfigurationListenerHub.class)
+    public static void configureServiceConfigurationListener(OrderedConfiguration<ServiceConfigurationListener> configuration, 
+            CatchAllServiceConfigurationListener listener) 
+    {
+        configuration.add("CatchAll", listener);
+    }
+    
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(CatchAllServiceConfigurationListener.class);
+    }
+    
 }