You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cl...@apache.org on 2009/01/19 09:50:51 UTC
svn commit: r735632 - in /felix/trunk/ipojo: ./ handler/temporal/
handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/
tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/
Author: clement
Date: Mon Jan 19 00:50:50 2009
New Revision: 735632
URL: http://svn.apache.org/viewvc?rev=735632&view=rev
Log:
Fix the issue Felix-860.
Replace dynamic proxies by proxies generated with ASM.
Moreover, non proxied dependencies use a ThreadLocal mechanism to guaranty the consistency of injected services (as for regular service dependency).
Added:
felix/trunk/ipojo/handler/temporal/LICENSE.asm
felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java (with props)
felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java (with props)
Removed:
felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceProxy.java
Modified:
felix/trunk/ipojo/handler/temporal/NOTICE
felix/trunk/ipojo/handler/temporal/pom.xml
felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java
felix/trunk/ipojo/pom.xml
felix/trunk/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java
Added: felix/trunk/ipojo/handler/temporal/LICENSE.asm
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/LICENSE.asm?rev=735632&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/temporal/LICENSE.asm (added)
+++ felix/trunk/ipojo/handler/temporal/LICENSE.asm Mon Jan 19 00:50:50 2009
@@ -0,0 +1,28 @@
+
+ ASM: a very small and fast Java bytecode manipulation framework
+ Copyright (c) 2000-2005 INRIA, France Telecom
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
Modified: felix/trunk/ipojo/handler/temporal/NOTICE
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/NOTICE?rev=735632&r1=735631&r2=735632&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/temporal/NOTICE (original)
+++ felix/trunk/ipojo/handler/temporal/NOTICE Mon Jan 19 00:50:50 2009
@@ -7,6 +7,10 @@
The Apache Software Foundation (http://www.apache.org/).
Licensed under the Apache License 2.0.
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
II. Used Software
This product uses software developed at
@@ -16,3 +20,5 @@
III. License Summary
- Apache License 2.0
+- BSD Licence
+
Modified: felix/trunk/ipojo/handler/temporal/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/pom.xml?rev=735632&r1=735631&r2=735632&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/temporal/pom.xml (original)
+++ felix/trunk/ipojo/handler/temporal/pom.xml Mon Jan 19 00:50:50 2009
@@ -41,6 +41,17 @@
<artifactId>org.apache.felix.ipojo</artifactId>
<version>1.1.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>asm</groupId>
+ <artifactId>asm-all</artifactId>
+ <version>3.0</version>
+ <exclusions>
+ <exclusion>
+ <groupId>asm</groupId>
+ <artifactId>asm-tree</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
<build>
<plugins>
@@ -51,10 +62,13 @@
<extensions>true</extensions>
<configuration>
<instructions>
- <Private-Package> org.apache.felix.ipojo.handler.temporal
+ <Private-Package>
+ org.apache.felix.ipojo.handler.temporal,
+ org.objectweb.asm
</Private-Package>
<Bundle-Name>${pom.name}</Bundle-Name>
<Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+ <Import-Package>!org.objectweb.asm.tree, *</Import-Package>
<Bundle-Vendor> The Apache Software Foundation </Bundle-Vendor>
<Bundle-Description> iPOJO Temporal Dependency Handler
</Bundle-Description>
@@ -62,7 +76,9 @@
http://felix.apache.org/site/temporal-service-dependency.html
</Bundle-DocURL>
<Include-Resource> META-INF/LICENCE=LICENSE,
- META-INF/NOTICE=NOTICE </Include-Resource>
+ META-INF/LICENCE.asm=LICENSE.asm,
+ META-INF/NOTICE=NOTICE
+ </Include-Resource>
</instructions>
</configuration>
</plugin>
Added: felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java?rev=735632&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java (added)
+++ felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java Mon Jan 19 00:50:50 2009
@@ -0,0 +1,183 @@
+/*
+ * 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.ipojo.handler.temporal;
+
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Generates proxy class delegating operation invocations thanks to a
+ * a temporal dependency.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProxyGenerator implements Opcodes {
+
+ /**
+ * The temporal dependency name.
+ */
+ private static final String DEPENDENCY = "m_dependency";
+
+ /**
+ * The Temporal Dependency descriptor.
+ */
+ private static final String DEPENDENCY_DESC = Type.getDescriptor(TemporalDependency.class);
+
+ /**
+ * Temporal dependency internal class name.
+ */
+ private static final String TEMPORAL_DEPENDENCY = "org/apache/felix/ipojo/handler/temporal/TemporalDependency";
+
+ /**
+ * Gets the internal names of the given class objects.
+ * @param classes the classes
+ * @return the array containing internal names of the given class array.
+ */
+ private static String[] getInternalClassNames(Class[] classes) {
+ final String[] names = new String[classes.length];
+ for (int i = 0; i < names.length; i++) {
+ names[i] = Type.getInternalName(classes[i]);
+ }
+ return names;
+ }
+
+ /**
+ * Generates a proxy class.
+ * @param spec the proxied service specification
+ * @return the byte[] for the generated proxy class.
+ */
+ public static byte[] dumpProxy(Class spec) {
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ String internalClassName = Type.getInternalName(spec); // Specification class internal name.
+ String[] itfs = new String[] {internalClassName}; // Implemented interface.
+ String className = internalClassName + "$$Proxy"; // Unique name.
+ Method[] methods = spec.getMethods(); // Method to delegate
+
+ cw.visit(Opcodes.V1_3, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, className, null, "java/lang/Object", itfs);
+ addDependencyField(cw);
+ generateConstructor(cw, className);
+
+ // For each method, create the delegator code.
+ for (int i = 0; i < methods.length; i++) {
+ if ((methods[i].getModifiers() & (Modifier.STATIC | Modifier.FINAL)) == 0) {
+ generateDelegator(cw, methods[i], className, internalClassName);
+ }
+ }
+
+ cw.visitEnd();
+
+ return cw.toByteArray();
+
+ }
+
+ /**
+ * Generates a delegated method.
+ * @param cw the class writer
+ * @param method the method object to delegate
+ * @param className the generated class name
+ * @param itfName the internal specification class name
+ */
+ private static void generateDelegator(ClassWriter cw, Method method,
+ String className, String itfName) {
+ String methodName = method.getName();
+ String desc = Type.getMethodDescriptor(method);
+ String[] exceptions = getInternalClassNames(method.getExceptionTypes());
+ int modifiers = method.getModifiers()
+ & ~(Modifier.ABSTRACT | Modifier.NATIVE | Modifier.SYNCHRONIZED);
+ Type[] types = Type.getArgumentTypes(method);
+
+ int freeRoom = 1;
+ for (int t = 0; t < types.length; t++) {
+ freeRoom = freeRoom + types[t].getSize();
+ }
+
+ MethodVisitor mv = cw.visitMethod(modifiers, methodName, desc, null,
+ exceptions);
+ mv.visitCode();
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, DEPENDENCY, DEPENDENCY_DESC); // The temporal dependency is on the stack.
+ mv.visitMethodInsn(INVOKEVIRTUAL, TEMPORAL_DEPENDENCY, "getService", // Call getService
+ "()Ljava/lang/Object;"); // The service object is on the stack.
+ int varSvc = freeRoom;
+ freeRoom = freeRoom + 1; // Object Reference.
+ mv.visitVarInsn(ASTORE, varSvc); // Store the service object.
+
+ // Invoke the method on the service object.
+ mv.visitVarInsn(ALOAD, varSvc);
+ // Push argument on the stack.
+ int i = 1; // Arguments. (non static method)
+ for (int t = 0; t < types.length; t++) {
+ mv.visitVarInsn(types[t].getOpcode(ILOAD), i);
+ i = i + types[t].getSize();
+ }
+ // Invocation
+ mv.visitMethodInsn(INVOKEINTERFACE, itfName, methodName, desc);
+
+ // Return the result
+ Type returnType = Type.getReturnType(desc);
+ if (returnType.getSort() != Type.VOID) {
+ mv.visitInsn(returnType.getOpcode(IRETURN));
+ } else {
+ mv.visitInsn(RETURN);
+ }
+
+ // End of the method.
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generates the constructors. The constructor receives a temporal dependency
+ * and set the {@link ProxyGenerator#DEPENDENCY} field.
+ * @param cw the class writer
+ * @param className the generated class name.
+ */
+ private static void generateConstructor(ClassWriter cw, String className) {
+ MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", '(' + DEPENDENCY_DESC + ")V", null, null);
+ mv.visitCode();
+
+ mv.visitVarInsn(ALOAD, 0); // Load this
+ mv.visitInsn(DUP); // Dup
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); // Call super
+ mv.visitVarInsn(ALOAD, 1); // Load the argument
+ mv.visitFieldInsn(PUTFIELD, className, DEPENDENCY, DEPENDENCY_DESC); // Assign the dependency field
+ mv.visitInsn(RETURN); // Return void
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Adds the temporal dependency field {@link ProxyGenerator#DEPENDENCY}.
+ * @param cw the class writer
+ */
+ private static void addDependencyField(ClassWriter cw) {
+ cw.visitField(Opcodes.ACC_FINAL, DEPENDENCY, DEPENDENCY_DESC, null, null);
+ cw.visitEnd();
+ }
+
+
+
+}
Propchange: felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java?rev=735632&view=auto
==============================================================================
--- felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java (added)
+++ felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java Mon Jan 19 00:50:50 2009
@@ -0,0 +1,77 @@
+/*
+ * 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.ipojo.handler.temporal;
+
+
+/**
+ * Object managing thread local copy of required services.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceUsage extends ThreadLocal {
+
+ /**
+ * Structure contained in the Thread Local.
+ */
+ public static class Usage {
+
+ /**
+ * Stack Size.
+ */
+ int m_stack = 0;
+ /**
+ * Object to inject.
+ */
+ Object m_object;
+
+ /**
+ * Increment the stack level.
+ */
+ public void inc() {
+ m_stack++;
+ }
+
+ /**
+ * Decrement the stack level.
+ * @return true if the stack is 0 after the decrement.
+ */
+ public boolean dec() {
+ m_stack--;
+ return m_stack == 0;
+ }
+
+ /**
+ * Clear the service object array.
+ */
+ public void clear() {
+ m_object = null;
+ }
+
+ }
+
+ /**
+ * Initialize the cached object.
+ * @return an empty Usage object.
+ * @see java.lang.ThreadLocal#initialValue()
+ */
+ public Object initialValue() {
+ return new Usage();
+ }
+
+}
Propchange: felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java?rev=735632&r1=735631&r2=735632&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java (original)
+++ felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java Mon Jan 19 00:50:50 2009
@@ -19,14 +19,18 @@
package org.apache.felix.ipojo.handler.temporal;
import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.felix.ipojo.FieldInterceptor;
+import org.apache.felix.ipojo.MethodInterceptor;
import org.apache.felix.ipojo.Nullable;
import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.handler.temporal.ServiceUsage.Usage;
import org.apache.felix.ipojo.handlers.dependency.NullableObject;
import org.apache.felix.ipojo.util.DependencyModel;
import org.osgi.framework.BundleContext;
@@ -40,7 +44,7 @@
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class TemporalDependency extends DependencyModel implements
- FieldInterceptor {
+ FieldInterceptor, MethodInterceptor {
/**
* The timeout.
@@ -81,6 +85,18 @@
* Enables the proxy mode.
*/
private boolean m_proxy;
+
+ /**
+ * Service Usage (Thread Local).
+ */
+ private ServiceUsage m_usage;
+
+ /**
+ * The proxy object.
+ * This field is used for scalar proxied temporal dependency.
+ */
+ private Object m_proxyObject;
+
/**
* Creates a temporal dependency.
@@ -106,6 +122,12 @@
m_handler = handler;
m_collection = collection;
m_proxy = proxy;
+ if (! proxy) { // No proxy => initialize the Thread local.
+ m_usage = new ServiceUsage();
+ } else if (proxy && ! agg) { // Scalar proxy => Create the proxy.
+ ProxyFactory proxyFactory = new ProxyFactory(this.getSpecification().getClassLoader(), this.getClass().getClassLoader());
+ m_proxyObject = proxyFactory.getProxy(getSpecification(), this);
+ }
}
/**
@@ -123,23 +145,20 @@
/**
* A provider arrives.
- * @param arg0 service reference of the new provider.
+ * @param ref service reference of the new provider.
* @see org.apache.felix.ipojo.util.DependencyModel#onServiceArrival(org.osgi.framework.ServiceReference)
*/
- public void onServiceArrival(ServiceReference arg0) {
+ public synchronized void onServiceArrival(ServiceReference ref) {
// Notify if a thread is waiting.
- synchronized (this) {
- notifyAll();
- }
+ notifyAll();
}
/**
- * A provider leaves. Nothing to do.
+ * A provider leaves.
* @param arg0 leaving service references.
* @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference)
*/
- public synchronized void onServiceDeparture(ServiceReference arg0) {
- }
+ public void onServiceDeparture(ServiceReference arg0) { }
/**
* The code require a value of the monitored field. If providers are
@@ -153,12 +172,20 @@
* @see org.apache.felix.ipojo.FieldInterceptor#onGet(java.lang.Object, java.lang.String, java.lang.Object)
*/
public synchronized Object onGet(Object arg0, String arg1, Object arg2) {
+ // Check if the Thread local as a value
+ if (! m_proxy) {
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack > 0) {
+ return usage.m_object;
+ }
+ }
+
ServiceReference[] refs = getServiceReferences();
if (refs != null) {
// Immediate return.
return getServiceObjects(refs);
} else {
- // Begin to wait ...
+ // Begin to wait ...
long enter = System.currentTimeMillis();
boolean exhausted = false;
synchronized (this) {
@@ -184,6 +211,65 @@
}
/**
+ * A POJO method will be invoked.
+ * @param pojo : Pojo object
+ * @param method : called method
+ * @param args : arguments
+ * @see org.apache.felix.ipojo.MethodInterceptor#onEntry(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+ */
+ public void onEntry(Object pojo, Method method, Object[] args) {
+ if (m_usage != null) {
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack > 0) {
+ usage.inc();
+ m_usage.set(usage); // Set the Thread local as value has been modified
+ }
+ }
+ }
+
+ /**
+ * A POJO method has thrown an error.
+ * This method does nothing and wait for the finally.
+ * @param pojo : POJO object.
+ * @param method : Method object.
+ * @param throwable : thrown error
+ * @see org.apache.felix.ipojo.MethodInterceptor#onError(java.lang.Object, java.lang.reflect.Method, java.lang.Throwable)
+ */
+ public void onError(Object pojo, Method method, Throwable throwable) {
+ // Nothing to do : wait onFinally
+ }
+
+ /**
+ * A POJO method has returned.
+ * @param pojo : POJO object.
+ * @param method : Method object.
+ * @param returnedObj : returned object (null for void method)
+ * @see org.apache.felix.ipojo.MethodInterceptor#onExit(java.lang.Object, java.lang.reflect.Method, java.lang.Object)
+ */
+ public void onExit(Object pojo, Method method, Object returnedObj) {
+ // Nothing to do : wait onFinally
+ }
+
+ /**
+ * A POJO method is finished.
+ * @param pojo : POJO object.
+ * @param method : Method object.
+ * @see org.apache.felix.ipojo.MethodInterceptor#onFinally(java.lang.Object, java.lang.reflect.Method)
+ */
+ public void onFinally(Object pojo, Method method) {
+ if (m_usage != null) {
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack > 0) {
+ if (usage.dec()) {
+ // Exit the method flow => Release all objects
+ usage.clear();
+ m_usage.set(usage); // Set the Thread local as value has been modified
+ }
+ }
+ }
+ }
+
+ /**
* Creates and returns object to inject in the dependency.
* This method handles aggregate, collection and proxy cases.
* @param refs the available service references
@@ -192,35 +278,80 @@
*/
private Object getServiceObjects(ServiceReference [] refs) {
if (m_proxy) {
- if (isAggregate()) { // Necessary a collection
+ if (m_proxyObject == null) { // Not aggregate.
return new ServiceCollection(this);
} else {
- return Proxy.newProxyInstance(m_handler
- .getInstanceManager().getClazz().getClassLoader(),
- new Class[] { getSpecification() },
- new ServiceProxy(this)); // NOPMD
+ return m_proxyObject;
}
} else {
- if (isAggregate()) {
- if (m_collection) {
- Collection svc = new ArrayList(refs.length); // Use an array list as collection implementation.
- for (int i = 0; i < refs.length; i++) {
- svc.add(getService(refs[i]));
+ // Initialize the thread local object is not already touched.
+ Usage usage = (Usage) m_usage.get();
+ if (usage.m_stack == 0) { // uninitialized usage.
+ if (isAggregate()) {
+ if (m_collection) {
+ Collection svc = new ArrayList(refs.length); // Use an array list as collection implementation.
+ for (int i = 0; i < refs.length; i++) {
+ svc.add(getService(refs[i]));
+ }
+ usage.m_object = svc;
+ } else {
+ Object[] svc = (Object[]) Array.newInstance(getSpecification(),
+ refs.length);
+ for (int i = 0; i < svc.length; i++) {
+ svc[i] = getService(refs[i]);
+ }
+ usage.m_object = svc;
}
- return svc;
} else {
- Object[] svc = (Object[]) Array.newInstance(getSpecification(),
- refs.length);
- for (int i = 0; i < svc.length; i++) {
- svc[i] = getService(refs[i]);
+ usage.m_object = getService(refs[0]);
+ }
+ usage.inc(); // Start the caching, so set the stack level to 1
+ m_usage.set(usage);
+ }
+ return usage.m_object;
+ }
+
+ }
+
+ /**
+ * Called by the proxy to get a service object to delegate a method.
+ * This methods manages the waited time and on timeout policies.
+ * @return a service object or a nullable/default-implmentation object.
+ */
+ public Object getService() {
+ ServiceReference ref = getServiceReference();
+ if (ref != null) {
+ return getService(ref); // Return immediately the service object.
+ } else {
+ // Begin to wait ...
+ long enter = System.currentTimeMillis();
+ boolean exhausted = false;
+ synchronized (this) {
+ while (ref == null && !exhausted) {
+ try {
+ wait(1);
+ } catch (InterruptedException e) {
+ // We was interrupted ....
+ } finally {
+ long end = System.currentTimeMillis();
+ exhausted = (end - enter) > m_timeout;
+ ref = getServiceReference();
}
- return svc;
+ }
+ }
+ // Check
+ if (exhausted) {
+ Object obj = onTimeout(); // Throw the Runtime Exception
+ if (obj == null) {
+ throw new NullPointerException("No service available"); // NPE if null.
+ } else {
+ return obj; // Return a nullable or DI
}
} else {
- return getService(refs[0]);
+ // If not exhausted, ref is not null.
+ return getService(ref);
}
}
-
}
/**
@@ -316,6 +447,7 @@
public void stop() {
super.stop();
m_nullableObject = null;
+ m_proxyObject = null;
}
/**
@@ -325,8 +457,7 @@
* @param arg2 received value
* @see org.apache.felix.ipojo.FieldInterceptor#onSet(java.lang.Object, java.lang.String, java.lang.Object)
*/
- public void onSet(Object arg0, String arg1, Object arg2) {
- }
+ public void onSet(Object arg0, String arg1, Object arg2) { }
/**
* Implements the timeout policy according to the specified configuration.
@@ -351,6 +482,77 @@
return m_timeout;
}
+ /**
+ * Creates proxy object for proxied scalar dependencies.
+ */
+ private class ProxyFactory extends ClassLoader {
+
+ /**
+ * Instance classloader, used to load specification and dependent classes.
+ */
+ private ClassLoader m_instanceCL;
+
+ /**
+ * Handler classloader, used to load the temporal dependency class.
+ */
+ private ClassLoader m_handlerCL;
+
+ /**
+ * Creates the proxy classloader.
+ * @param parent1 the instance classloader.
+ * @param parent2 the handler classloader.
+ */
+ public ProxyFactory(ClassLoader parent1, ClassLoader parent2) {
+ this.m_instanceCL = parent1;
+ this.m_handlerCL = parent2;
+ }
+
+ /**
+ * Loads a proxy class generated for the given (interface) class.
+ * @param clazz the service specification to proxy
+ * @return the Class object of the proxy.
+ */
+ protected Class getProxyClass(Class clazz) {
+ byte[] clz = ProxyGenerator.dumpProxy(clazz); // Generate the proxy.
+ return defineClass(clazz.getName() + "$$Proxy", clz, 0, clz.length);
+ }
+
+ /**
+ * Create a proxy object for the given specification. The proxy
+ * uses the given temporal dependency to get the service object.
+ * @param spec the service specification (interface)
+ * @param dep the temporal dependency used to get the service
+ * @return the proxy object.
+ */
+ public Object getProxy(Class spec, TemporalDependency dep) {
+ try {
+ Class clazz = getProxyClass(getSpecification());
+ Constructor constructor = clazz.getConstructor(new Class[] {dep.getClass()}); // The proxy constructor
+ return constructor.newInstance(new Object[] {dep});
+ } catch (Throwable e) {
+ m_handler.error("Cannot create the proxy object", e);
+ m_handler.getInstanceManager().stop();
+ return null;
+ }
+ }
+
+ /**
+ * Loads the given class.
+ * This class use the classloader of the specification class
+ * or the handler class loader.
+ * @param name the class name
+ * @return the class object
+ * @throws ClassNotFoundException if the class is not found by the two classloaders.
+ * @see java.lang.ClassLoader#loadClass(java.lang.String)
+ */
+ public Class loadClass(String name) throws ClassNotFoundException {
+ try {
+ return m_instanceCL.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ return m_handlerCL.loadClass(name);
+ }
+ }
+ }
}
Modified: felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java?rev=735632&r1=735631&r2=735632&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java (original)
+++ felix/trunk/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java Mon Jan 19 00:50:50 2009
@@ -27,6 +27,7 @@
import org.apache.felix.ipojo.PrimitiveHandler;
import org.apache.felix.ipojo.metadata.Element;
import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.apache.felix.ipojo.parser.MethodMetadata;
import org.apache.felix.ipojo.parser.PojoMetadata;
import org.apache.felix.ipojo.util.DependencyModel;
import org.apache.felix.ipojo.util.DependencyStateListener;
@@ -190,6 +191,13 @@
TemporalDependency dep = new TemporalDependency(specification, agg, collection, proxy, filter, getInstanceManager().getContext(), timeout, policy, di, this);
m_dependencies.add(dep);
+ if (! proxy) { // Register method interceptor only if are not a proxy
+ MethodMetadata[] methods = manipulation.getMethods();
+ for (int k = 0; k < methods.length; k++) {
+ getInstanceManager().register(methods[k], dep);
+ }
+ }
+
getInstanceManager().register(fieldmeta, dep);
}
}
Modified: felix/trunk/ipojo/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/pom.xml?rev=735632&r1=735631&r2=735632&view=diff
==============================================================================
--- felix/trunk/ipojo/pom.xml (original)
+++ felix/trunk/ipojo/pom.xml Mon Jan 19 00:50:50 2009
@@ -43,7 +43,7 @@
<module>handler/temporal</module>
<module>handler/eventadmin</module>
<module>handler/whiteboard</module>
- <module>junit4osgi</module>
+
</modules>
Modified: felix/trunk/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java?rev=735632&r1=735631&r2=735632&view=diff
==============================================================================
--- felix/trunk/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java (original)
+++ felix/trunk/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java Mon Jan 19 00:50:50 2009
@@ -44,16 +44,18 @@
// Stop the provider.
provider.stop();
+ assertNull("No FooService", Utils.getServiceReference(context, FooService.class.getName(), null));
ref_cs = Utils.getServiceReferenceByName(context, CheckService.class.getName(), un);
assertNotNull("Check cs availability - 2", ref_cs);
long begin = System.currentTimeMillis();
DelayedProvider dp = new DelayedProvider(provider, 200);
dp.start();
cs = (CheckService) context.getService(ref_cs);
+
assertTrue("Check invocation - 2", cs.check());
long end = System.currentTimeMillis();
- assertTrue("Assert delay", (end - begin) >= 200);
+ assertTrue("Assert delay (" + (end - begin) + ")", (end - begin) >= 200);
ref_cs = Utils.getServiceReferenceByName(context, CheckService.class.getName(), un);
assertNotNull("Check cs availability - 3", ref_cs);
@@ -80,7 +82,7 @@
CheckService cs = (CheckService) context.getService(ref_cs);
assertTrue("Check invocation", cs.check());
-
+
// Stop the provider.
provider.stop();
ref_cs = Utils.getServiceReferenceByName(context, CheckService.class.getName(), un);
@@ -105,6 +107,7 @@
under.dispose();
}
+
public void testTimeout() {
String prov = "provider";
ComponentInstance provider = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);
@@ -142,6 +145,7 @@
fail("Timeout expected");
}
+
public void testTimeoutWithProxy() {
String prov = "provider";
ComponentInstance provider = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);
@@ -178,7 +182,8 @@
fail("Timeout expected");
}
-
+
+
public void testDelayTimeout() {
String prov = "provider";
ComponentInstance provider = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);
@@ -217,7 +222,7 @@
under.stop();
under.dispose();
}
-
+
public void testDelayTimeoutWithProxy() {
String prov = "provider";
ComponentInstance provider = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);
@@ -256,7 +261,7 @@
under.stop();
under.dispose();
}
-
+
public void testSetTimeout() {
String prov = "provider";
ComponentInstance provider = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);
@@ -293,7 +298,8 @@
fail("Timeout expected");
}
-
+
+
public void testSetTimeoutWithProxy() {
String prov = "provider";
ComponentInstance provider = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);
@@ -330,7 +336,7 @@
fail("Timeout expected");
}
-
+
public void testDelayOnMultipleDependency() {
String prov = "provider";
ComponentInstance provider1 = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);
@@ -379,7 +385,8 @@
under.stop();
under.dispose();
}
-
+
+
public void testDelayOnCollectionDependency() {
String prov = "provider";
ComponentInstance provider1 = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);
@@ -428,7 +435,8 @@
under.stop();
under.dispose();
}
-
+
+
public void testDelayOnProxiedCollectionDependency() {
String prov = "provider";
ComponentInstance provider1 = Utils.getComponentInstanceByName(context, "TEMPORAL-FooProvider", prov);