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).

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@735632 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/handler/temporal/LICENSE.asm b/ipojo/handler/temporal/LICENSE.asm
new file mode 100644
index 0000000..9496b17
--- /dev/null
+++ b/ipojo/handler/temporal/LICENSE.asm
@@ -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.

diff --git a/ipojo/handler/temporal/NOTICE b/ipojo/handler/temporal/NOTICE
index fbaec6c..59c055e 100644
--- a/ipojo/handler/temporal/NOTICE
+++ b/ipojo/handler/temporal/NOTICE
@@ -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
+
diff --git a/ipojo/handler/temporal/pom.xml b/ipojo/handler/temporal/pom.xml
index dfb467e..21c8c93 100644
--- a/ipojo/handler/temporal/pom.xml
+++ b/ipojo/handler/temporal/pom.xml
@@ -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>
diff --git a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java
new file mode 100644
index 0000000..90013a3
--- /dev/null
+++ b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ProxyGenerator.java
@@ -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();
+    }
+    
+   
+
+}
diff --git a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceProxy.java b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceProxy.java
deleted file mode 100644
index 69aa1a4..0000000
--- a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceProxy.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/* 
- * 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.InvocationHandler;
-import java.lang.reflect.Method;
-
-import org.osgi.framework.ServiceReference;
-
-/**
- * Wrapper in front of a temporal service dependencies.
- * This proxy can be used by collaborators. Service lookup 
- * and on timeout policies are executed when a method is invoked.
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
-public class ServiceProxy implements InvocationHandler {
-    
-    /**
-     * The wrapped temporal dependency. 
-     */
-    private TemporalDependency m_dependency;
-    
-    /**
-     * Creates a Service Proxy.
-     * @param dep the wrapped temporal dependency
-     */
-    public ServiceProxy(TemporalDependency dep) {
-        m_dependency = dep;
-    }
-
-    /**
-     * Intercept a method invocation.
-     * This method looks for a service provider, wait for timeout and
-     * depending on the lookup result either call the method
-     * on a service object or executed the on timeout policy.
-     * In this latter case, this methods can throw a {@link RuntimeException},
-     * throws a {@link NullPointerException} (null policy) or invokes the 
-     * method on a nullable/default-implementation object.
-     * @param proxy the proxy on which the method is invoked
-     * @param method the invoked method
-     * @param args the arguments
-     * @return the invocation result.
-     * @throws Exception an exception occurs either during the invocation or 
-     * is the result to the on timeout policy.
-     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
-     */
-    public Object invoke(Object proxy, Method method, Object[] args)
-        throws Exception {
-        ServiceReference ref = m_dependency.getServiceReference();
-        if (ref != null) {
-            // Immediate return.
-            return invokeOperation(ref, method, args); // Invoke the method on the service object.
-        } else {
-            // Begin to wait ...
-            long enter = System.currentTimeMillis();
-            boolean exhausted = false;
-            synchronized (this) {
-                while (m_dependency.getServiceReference() == null && !exhausted) {
-                    try {
-                        wait(1);
-                    } catch (InterruptedException e) {
-                        // We was interrupted ....
-                    } finally {
-                        long end = System.currentTimeMillis();
-                        exhausted = (end - enter) > m_dependency.getTimeout();
-                    }
-                }
-            }
-            // Check
-            if (exhausted) {
-                Object oto = m_dependency.onTimeout(); // Throws the RuntimeException
-                if (oto == null) { // If null, return null
-                    throw new NullPointerException("No service object available"); // throws an NPE in this case.
-                } else {
-                    // invoke the method on the returned object.
-                    return invokeOperation(oto, method, args);
-                }
-            } else {
-                ref = m_dependency.getServiceReference();
-                return invokeOperation(ref, method, args); // Invoke the method on the service object.
-            }
-        }
-    }
-
-    /**
-     * Helper method invoking the given method, with the given
-     * argument on the given object.
-     * @param svc the service object
-     * @param method the method object
-     * @param args the arguments
-     * @return the invocation result
-     * @throws Exception occurs when an issue happen during method invocation.
-     */
-    private Object invokeOperation(Object svc, Method method, Object[] args) 
-        throws Exception {
-        return method.invoke(svc, args);
-    }
-    
-    /**
-     * Helper method invoking the given method, with the given
-     * argument on the given service reference. This methods gets 
-     * the service object and then invokes the method.
-     * @param ref the service reference
-     * @param method the method object
-     * @param args the arguments
-     * @return the invocation result
-     * @throws Exception occurs when an issue happen during method invocation.
-     */
-    private Object invokeOperation(ServiceReference ref, Method method, Object[] args) 
-        throws Exception {
-        Object svc = m_dependency.getService(ref);
-        return method.invoke(svc, args);
-    }
-
-}
diff --git a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java
new file mode 100644
index 0000000..70184c9
--- /dev/null
+++ b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/ServiceUsage.java
@@ -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();

+    }   

+

+}

diff --git a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
index f0f270b..0689505 100644
--- a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
+++ b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalDependency.java
@@ -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,36 +278,81 @@
      */
     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]);
-                    }
-                    return svc;
+                    usage.m_object = getService(refs[0]);
                 }
-            } else {
-                return 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();
+                    }
+                }
+            }
+            // 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 {
+               // If not exhausted, ref is not null.
+                return getService(ref);
+            }
+        }
+    }
 
     /**
      * Start method. Initializes the nullable object.
@@ -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);
+            }
+        }
+    }  
     
 
 }
diff --git a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java
index a65c616..c980101 100644
--- a/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java
+++ b/ipojo/handler/temporal/src/main/java/org/apache/felix/ipojo/handler/temporal/TemporalHandler.java
@@ -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);
         }        
     }
diff --git a/ipojo/pom.xml b/ipojo/pom.xml
index 254e46c..45e20e8 100644
--- a/ipojo/pom.xml
+++ b/ipojo/pom.xml
@@ -43,7 +43,7 @@
 		<module>handler/temporal</module>
 		<module>handler/eventadmin</module>
 		<module>handler/whiteboard</module>
-		<module>junit4osgi</module>
+		
 	</modules>
 		
 	
diff --git a/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java b/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java
index 6adb197..bbd6a5c 100644
--- a/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java
+++ b/ipojo/tests/handler/temporal/src/main/java/org/apache/felix/ipojo/test/scenarios/temporal/DelayTest.java
@@ -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);