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