Author: marrs
Date: Wed May 19 11:56:44 2010
New Revision: 946137
URL: http://svn.apache.org/viewvc?rev=946137&view=rev
Log:
Completed support for using dynamic proxies as generic aspects. Added a test to
validate this behaviour.
Added:
felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/DynamicProxyAspectTest.java
Modified:
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java
Modified:
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java?rev=946137&r1=946136&r2=946137&view=diff
==============================================================================
---
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
(original)
+++
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyActivatorBase.java
Wed May 19 11:56:44 2010
@@ -163,6 +163,9 @@ public abstract class DependencyActivato
public Service createAspectService(Class serviceInterface, String
serviceFilter, int ranking, Object factory, String factoryCreateMethod,
Dictionary properties) {
return m_manager.createAspectService(serviceInterface, serviceFilter,
ranking, factory, factoryCreateMethod, properties);
}
+ public Service createAspectService(Class serviceInterface, String
serviceFilter, int ranking, Object factory, String factoryCreateMethod, String
attributeName, Dictionary properties) {
+ return m_manager.createAspectService(serviceInterface, serviceFilter,
ranking, factory, factoryCreateMethod, attributeName, properties);
+ }
public Service createAdapterService(Class serviceInterface, String
serviceFilter, String adapterInterface, Object adapterImplementation,
Dictionary adapterProperties) {
return m_manager.createAdapterService(serviceInterface, serviceFilter,
adapterInterface, adapterImplementation, adapterProperties);
Modified:
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java?rev=946137&r1=946136&r2=946137&view=diff
==============================================================================
---
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
(original)
+++
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
Wed May 19 11:56:44 2010
@@ -33,9 +33,9 @@ import org.apache.felix.dm.dependencies.
import org.apache.felix.dm.impl.AdapterImpl;
import org.apache.felix.dm.impl.AspectImpl;
import org.apache.felix.dm.impl.BundleAdapterImpl;
+import org.apache.felix.dm.impl.FactoryConfigurationAdapterImpl;
import org.apache.felix.dm.impl.FactoryConfigurationAdapterMetaTypeImpl;
import org.apache.felix.dm.impl.Logger;
-import org.apache.felix.dm.impl.FactoryConfigurationAdapterImpl;
import org.apache.felix.dm.impl.ResourceAdapterImpl;
import org.apache.felix.dm.impl.ServiceImpl;
import org.apache.felix.dm.impl.dependencies.BundleDependencyImpl;
@@ -201,6 +201,15 @@ public class DependencyManager {
.setCallbacks("added", "removed")
);
}
+ public Service createAspectService(Class serviceInterface, String
serviceFilter, int ranking, Object factory, String factoryCreateMethod, String
attributeName, Dictionary aspectProperties) {
+ return createService()
+ .setImplementation(new AspectImpl(serviceInterface, serviceFilter,
ranking, factory, factoryCreateMethod, attributeName, aspectProperties))
+ .add(createServiceDependency()
+ .setService(serviceInterface,
createAspectFilter(serviceFilter))
+ .setAutoConfig(false)
+ .setCallbacks("added", "removed")
+ );
+ }
private String createAspectFilter(String filter) {
// we only want to match services which are not themselves aspects
if (filter == null || filter.length() == 0) {
Modified:
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java?rev=946137&r1=946136&r2=946137&view=diff
==============================================================================
---
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java
(original)
+++
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectImpl.java
Wed May 19 11:56:44 2010
@@ -37,6 +37,7 @@ public class AspectImpl extends Abstract
private final Object m_factory;
private final String m_factoryCreateMethod;
private final int m_ranking;
+ private final String m_attributeName;
public AspectImpl(Class serviceInterface, String serviceFilter, int
ranking, Object aspectImplementation, Dictionary properties) {
m_serviceInterface = serviceInterface;
@@ -46,6 +47,7 @@ public class AspectImpl extends Abstract
m_factory = null;
m_factoryCreateMethod = null;
m_ranking = ranking;
+ m_attributeName = null;
}
public AspectImpl(Class serviceInterface, String serviceFilter, int
ranking, Object factory, String factoryCreateMethod, Dictionary properties) {
@@ -56,6 +58,18 @@ public class AspectImpl extends Abstract
m_aspectProperties = properties;
m_aspectImplementation = null;
m_ranking = ranking;
+ m_attributeName = null;
+ }
+
+ public AspectImpl(Class serviceInterface, String serviceFilter, int
ranking, Object factory, String factoryCreateMethod, String attributeName,
Dictionary properties) {
+ m_serviceInterface = serviceInterface;
+ m_serviceFilter = serviceFilter;
+ m_factory = factory;
+ m_factoryCreateMethod = factoryCreateMethod;
+ m_attributeName = attributeName;
+ m_aspectProperties = properties;
+ m_aspectImplementation = null;
+ m_ranking = ranking;
}
public Service createService(Object[] properties) {
@@ -80,13 +94,25 @@ public class AspectImpl extends Abstract
List dependencies = m_service.getDependencies();
dependencies.remove(0);
if (m_aspectImplementation == null) {
- return m_manager.createService()
- .setInterface(m_serviceInterface.getName(), props)
- .setFactory(m_factory, m_factoryCreateMethod)
- .add(dependencies)
- .add(m_manager.createServiceDependency()
- .setService(m_serviceInterface,
createAspectFilter(m_serviceFilter))
- .setRequired(true));
+ if (m_attributeName == null) {
+ return m_manager.createService()
+ .setInterface(m_serviceInterface.getName(), props)
+ .setFactory(m_factory, m_factoryCreateMethod)
+ .add(dependencies)
+ .add(m_manager.createServiceDependency()
+ .setService(m_serviceInterface,
createAspectFilter(m_serviceFilter))
+ .setRequired(true));
+ }
+ else {
+ return m_manager.createService()
+ .setInterface(m_serviceInterface.getName(), props)
+ .setFactory(m_factory, m_factoryCreateMethod)
+ .add(dependencies)
+ .add(m_manager.createServiceDependency()
+ .setService(m_serviceInterface,
createAspectFilter(m_serviceFilter))
+ .setAutoConfig(m_attributeName)
+ .setRequired(true));
+ }
}
else {
return m_manager.createService()
Modified:
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java?rev=946137&r1=946136&r2=946137&view=diff
==============================================================================
---
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java
(original)
+++
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/InvocationUtil.java
Wed May 19 11:56:44 2010
@@ -20,7 +20,7 @@ public class InvocationUtil {
throw new NoSuchMethodException(methodName);
}
- public static void invokeMethod(Object object, Class clazz, String name,
Class[][] signatures, Object[][] parameters, boolean isSuper) throws
NoSuchMethodException, InvocationTargetException, IllegalArgumentException,
IllegalAccessException {
+ public static Object invokeMethod(Object object, Class clazz, String name,
Class[][] signatures, Object[][] parameters, boolean isSuper) throws
NoSuchMethodException, InvocationTargetException, IllegalArgumentException,
IllegalAccessException {
if (object == null) {
throw new IllegalArgumentException("Instance cannot be null");
}
@@ -34,8 +34,7 @@ public class InvocationUtil {
m = clazz.getDeclaredMethod(name, signature);
if (!(isSuper && Modifier.isPrivate(m.getModifiers()))) {
m.setAccessible(true);
- m.invoke(object, parameters[i]);
- return;
+ return m.invoke(object, parameters[i]);
}
}
catch (NoSuchMethodException e) {
Modified:
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java?rev=946137&r1=946136&r2=946137&view=diff
==============================================================================
---
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java
(original)
+++
felix/trunk/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceImpl.java
Wed May 19 11:56:44 2010
@@ -684,8 +684,10 @@ public class ServiceImpl implements Serv
}
else {
try {
- Method m =
factory.getClass().getDeclaredMethod(m_instanceFactoryCreateMethod, null);
- m_serviceInstance =
m.invoke(factory, null);
+// Method m =
factory.getClass().getDeclaredMethod(m_instanceFactoryCreateMethod, null);
+// m_serviceInstance =
m.invoke(factory, null);
+//
+ m_serviceInstance =
InvocationUtil.invokeMethod(factory, factory.getClass(),
m_instanceFactoryCreateMethod, new Class[][] {{}}, new Object[][] {{}}, false);
}
catch (Exception e) {
m_logger.log(Logger.LOG_ERROR, "Could not create
service instance using factory " + factory + " method " +
m_instanceFactoryCreateMethod + ".", e);
Added:
felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/DynamicProxyAspectTest.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/DynamicProxyAspectTest.java?rev=946137&view=auto
==============================================================================
---
felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/DynamicProxyAspectTest.java
(added)
+++
felix/trunk/dependencymanager/test/src/test/java/org/apache/felix/dm/test/DynamicProxyAspectTest.java
Wed May 19 11:56:44 2010
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.test;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import junit.framework.Assert;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.service.Service;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+
+...@runwith(JUnit4TestRunner.class)
+public class DynamicProxyAspectTest extends Base {
+ @Configuration
+ public static Option[] configuration() {
+ return options(
+ provision(
+
mavenBundle().groupId("org.osgi").artifactId("org.osgi.compendium").version("4.1.0"),
+
mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.dependencymanager").versionAsInProject()
+ )
+ );
+ }
+
+ @Test
+ public void testImplementGenericAspectWithDynamicProxy(BundleContext
context) {
+ DependencyManager m = new DependencyManager(context);
+ // helper class that ensures certain steps get executed in sequence
+ Ensure e = new Ensure();
+
+ // create two service providers, each providing a different service
interface
+ Service sp1 = m.createService().setImplementation(new
ServiceProvider(e)).setInterface(ServiceInterface.class.getName(), null);
+ Service sp2 = m.createService().setImplementation(new
ServiceProvider2(e)).setInterface(ServiceInterface2.class.getName(), null);
+
+ // create a dynamic proxy based aspect and hook it up to both services
+ Service a1 = m.createAspectService(ServiceInterface.class, null, 10,
new Factory(e, ServiceInterface.class, "ServiceInterfaceProxy"), "create",
"m_service", null);
+ Service a2 = m.createAspectService(ServiceInterface2.class, null, 10,
new Factory(e, ServiceInterface2.class, "ServiceInterfaceProxy2"), "create",
"m_service", null);
+
+ // create a client that invokes a method on boths services, validate
that it goes
+ // through the proxy twice
+ Service sc = m.createService()
+ .setImplementation(new ServiceConsumer(e))
+
.add(m.createServiceDependency().setService(ServiceInterface.class).setRequired(true))
+
.add(m.createServiceDependency().setService(ServiceInterface2.class).setRequired(true))
+ ;
+
+ // register both producers, validate that both services are started
+ m.add(sp1);
+ e.waitForStep(1, 2000);
+ m.add(sp2);
+ e.waitForStep(2, 2000);
+
+ // add both aspects, and validate that both instances have been created
+ m.add(a1);
+ m.add(a2);
+ e.waitForStep(4, 4000);
+
+ // add the client, which will automatically invoke both services
+ m.add(sc);
+
+ // wait until both services have been invoked
+ e.waitForStep(6, 4000);
+
+ // make sure the proxy has been called twice
+ Assert.assertEquals("Proxy should have been invoked this many times.",
2, DynamicProxyHandler.getCounter());
+ }
+
+ static interface ServiceInterface {
+ public void invoke(Runnable run);
+ }
+
+ static interface ServiceInterface2 {
+ public void invoke(Runnable run);
+ }
+
+ static class ServiceProvider implements ServiceInterface {
+ private final Ensure m_ensure;
+ public ServiceProvider(Ensure e) {
+ m_ensure = e;
+ }
+ public void start() {
+ m_ensure.step(1);
+ }
+ public void invoke(Runnable run) {
+ run.run();
+ }
+ }
+
+ static class ServiceProvider2 implements ServiceInterface2 {
+ private final Ensure m_ensure;
+ public ServiceProvider2(Ensure ensure) {
+ m_ensure = ensure;
+ }
+ public void start() {
+ m_ensure.step(2);
+ }
+ public void invoke(Runnable run) {
+ run.run();
+ }
+ }
+
+ static class ServiceConsumer implements Runnable {
+ private volatile ServiceInterface m_service;
+ private volatile ServiceInterface2 m_service2;
+ private final Ensure m_ensure;
+
+ public ServiceConsumer(Ensure e) {
+ m_ensure = e;
+ }
+
+ public void init() {
+ Thread t = new Thread(this);
+ t.start();
+ }
+
+ public void run() {
+ m_service.invoke(Ensure.createRunnableStep(m_ensure, 5));
+ m_service2.invoke(Ensure.createRunnableStep(m_ensure, 6));
+ }
+ }
+
+ static class DynamicProxyHandler implements InvocationHandler {
+ public volatile Object m_service; // ISSUE, we cannot inject into
"Object" at the moment
+ private final String m_label;
+ private static volatile int m_counter = 0;
+
+ public DynamicProxyHandler(String label) {
+ m_label = label;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
+ if (m_service == null) {
+ Assert.fail("No service was injected into dynamic proxy
handler " + m_label);
+ }
+ Method m = m_service.getClass().getMethod(method.getName(),
method.getParameterTypes());
+ if (m == null) {
+ Assert.fail("No method " + method.getName() + " was found in
instance " + m_service + " in dynamic proxy handler " + m_label);
+ }
+ m_counter++;
+ return m.invoke(m_service, args);
+ }
+
+ public static int getCounter() {
+ return m_counter;
+ }
+ }
+
+ static class Factory {
+ private final String m_label;
+ private Class m_class;
+ private final Ensure m_ensure;
+
+ public Factory(Ensure ensure, Class clazz, String label) {
+ m_ensure = ensure;
+ m_class = clazz;
+ m_label = label;
+ }
+
+ public Object create() {
+ m_ensure.step();
+ return Proxy.newProxyInstance(m_class.getClassLoader(), new
Class[] { m_class }, new DynamicProxyHandler(m_label));
+ }
+ }
+}