SLING-1031 : Send events when a new adapter factory is added or an old one is removed.
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@790513 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 12e3fbd..83da7fb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -84,7 +84,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.0.2-incubator</version>
+ <version>2.0.5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
diff --git a/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java b/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
index 4be2807..6c2d26f 100644
--- a/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
+++ b/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
@@ -21,17 +21,23 @@
import static org.apache.sling.api.adapter.AdapterFactory.ADAPTABLE_CLASSES;
import static org.apache.sling.api.adapter.AdapterFactory.ADAPTER_CLASSES;
+import java.util.Dictionary;
import java.util.HashMap;
+import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.adapter.AdapterFactory;
import org.apache.sling.api.adapter.AdapterManager;
import org.apache.sling.commons.osgi.OsgiUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
/**
* The <code>AdapterManagerImpl</code> class implements the
@@ -103,6 +109,10 @@
*/
private Map<String, Map<String, AdapterFactory>> factoryCache;
+ /** The service tracker for the event admin
+ */
+ private ServiceTracker eventAdminTracker;
+
// ---------- AdapterManager interface -------------------------------------
/**
@@ -140,6 +150,10 @@
// ----------- SCR integration ---------------------------------------------
protected synchronized void activate(ComponentContext context) {
+ // setup tracker first as this is used in the bind/unbind methods
+ this.eventAdminTracker = new ServiceTracker(context.getBundleContext(),
+ EventAdmin.class.getName(), null);
+ this.eventAdminTracker.open();
this.context = context;
// register all adapter factories bound before activation
@@ -173,7 +187,10 @@
"Not clearing instance field: Set to another manager "
+ AdapterManagerImpl.INSTANCE, null);
}
-
+ if ( this.eventAdminTracker != null ) {
+ this.eventAdminTracker.close();
+ this.eventAdminTracker = null;
+ }
this.context = null;
}
@@ -226,13 +243,21 @@
}
/**
+ * Get the event admin.
+ * @return The event admin or <code>null</code>
+ */
+ private EventAdmin getEventAdmin() {
+ return (EventAdmin) (this.eventAdminTracker != null ? this.eventAdminTracker.getService() : null);
+ }
+
+ /**
* Unregisters the {@link AdapterFactory} referred to by the service
* <code>reference</code> from the registry.
*/
private void registerAdapterFactory(ComponentContext context,
ServiceReference reference) {
- String[] adaptables = OsgiUtil.toStringArray(reference.getProperty(ADAPTABLE_CLASSES));
- String[] adapters = OsgiUtil.toStringArray(reference.getProperty(ADAPTER_CLASSES));
+ final String[] adaptables = OsgiUtil.toStringArray(reference.getProperty(ADAPTABLE_CLASSES));
+ final String[] adapters = OsgiUtil.toStringArray(reference.getProperty(ADAPTER_CLASSES));
if (adaptables == null || adaptables.length == 0 || adapters == null
|| adapters.length == 0) {
@@ -260,6 +285,16 @@
// clear the factory cache to force rebuild on next access
factoryCache = null;
+
+ // send event
+ final EventAdmin localEA = this.getEventAdmin();
+ if ( localEA != null ) {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(SlingConstants.PROPERTY_ADAPTABLE_CLASSES, adaptables);
+ props.put(SlingConstants.PROPERTY_ADAPTER_CLASSES, adapters);
+ localEA.postEvent(new Event(SlingConstants.TOPIC_ADAPTER_FACTORY_ADDED,
+ props));
+ }
}
/**
@@ -269,9 +304,11 @@
private void unregisterAdapterFactory(ServiceReference reference) {
boundAdapterFactories.remove(reference);
- String[] adaptables = OsgiUtil.toStringArray(reference.getProperty(ADAPTABLE_CLASSES));
+ final String[] adaptables = OsgiUtil.toStringArray(reference.getProperty(ADAPTABLE_CLASSES));
+ final String[] adapters = OsgiUtil.toStringArray(reference.getProperty(ADAPTER_CLASSES));
- if (adaptables == null || adaptables.length == 0) {
+ if (adaptables == null || adaptables.length == 0 || adapters == null
+ || adapters.length == 0) {
return;
}
@@ -296,6 +333,16 @@
if (factoriesModified) {
factoryCache = null;
}
+
+ // send event
+ final EventAdmin localEA = this.getEventAdmin();
+ if ( localEA != null ) {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(SlingConstants.PROPERTY_ADAPTABLE_CLASSES, adaptables);
+ props.put(SlingConstants.PROPERTY_ADAPTER_CLASSES, adapters);
+ localEA.postEvent(new Event(SlingConstants.TOPIC_ADAPTER_FACTORY_ADDED,
+ props));
+ }
}
/**
diff --git a/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java b/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java
index f5a77f5..b0d5ee5 100644
--- a/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java
+++ b/src/test/java/org/apache/sling/adapter/internal/AdapterManagerTest.java
@@ -34,7 +34,10 @@
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.runner.RunWith;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
@@ -70,11 +73,21 @@
/**
* Helper method to create a mock component context
*/
- protected ComponentContext createComponentContext() {
+ protected ComponentContext createComponentContext() 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(any(ServiceReference.class)));
will(returnValue(new MockAdapterFactory()));
+ 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;
}
@@ -123,7 +136,7 @@
assertNull("AdapterFactory cache must be null", am.getFactoryCache());
}
- @org.junit.Test public void testInitialized() {
+ @org.junit.Test public void testInitialized() throws Exception {
am.activate(this.createComponentContext());
assertNotNull("AdapterFactoryDescriptors must not be null", am.getFactories());
@@ -131,7 +144,7 @@
assertNull("AdapterFactory cache must be null", am.getFactoryCache());
}
- @org.junit.Test public void testBindBeforeActivate() {
+ @org.junit.Test public void testBindBeforeActivate() throws Exception {
final ServiceReference ref = createServiceReference();
am.bindAdapterFactory(ref);
@@ -148,7 +161,7 @@
assertNull("AdapterFactory cache must be null", am.getFactoryCache());
}
- @org.junit.Test public void testBindAfterActivate() {
+ @org.junit.Test public void testBindAfterActivate() throws Exception {
am.activate(this.createComponentContext());
// no cache and no factories yet
@@ -178,7 +191,7 @@
assertNull(f.get(TestSlingAdaptable2.class.getName()));
}
- @org.junit.Test public void testAdaptBase() {
+ @org.junit.Test public void testAdaptBase() throws Exception {
am.activate(this.createComponentContext());
TestSlingAdaptable data = new TestSlingAdaptable();
@@ -192,7 +205,7 @@
assertTrue(adapter instanceof ITestAdapter);
}
- @org.junit.Test public void testAdaptExtended() {
+ @org.junit.Test public void testAdaptExtended() throws Exception {
am.activate(this.createComponentContext());
TestSlingAdaptable2 data = new TestSlingAdaptable2();
@@ -206,7 +219,7 @@
assertTrue(adapter instanceof ITestAdapter);
}
- @org.junit.Test public void testAdaptBase2() {
+ @org.junit.Test public void testAdaptBase2() throws Exception {
am.activate(this.createComponentContext());
TestSlingAdaptable data = new TestSlingAdaptable();
@@ -223,7 +236,7 @@
assertTrue(adapter instanceof ITestAdapter);
}
- @org.junit.Test public void testAdaptExtended2() {
+ @org.junit.Test public void testAdaptExtended2() throws Exception {
am.activate(this.createComponentContext());
final ServiceReference ref = createServiceReference();