You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/03/25 20:34:34 UTC

svn commit: r927558 - in /tapestry/tapestry5/trunk/tapestry-ioc/src: main/java/org/apache/tapestry5/ioc/ main/java/org/apache/tapestry5/ioc/internal/ main/java/org/apache/tapestry5/ioc/internal/util/ test/java/org/apache/tapestry5/ioc/

Author: hlship
Date: Thu Mar 25 19:34:34 2010
New Revision: 927558

URL: http://svn.apache.org/viewvc?rev=927558&view=rev
Log:
TAP5-1079: Change ObjectLocator.proxy() to create a reloadable proxy, when possible

Added:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java   (with props)
Modified:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CountingGreeterImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java?rev=927558&r1=927557&r2=927558&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java Thu Mar 25 19:34:34 2010
@@ -4,7 +4,7 @@
 // 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
+// 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,
@@ -18,8 +18,7 @@ import org.apache.tapestry5.ioc.annotati
 import org.apache.tapestry5.ioc.services.MasterObjectProvider;
 
 /**
- * Defines an object which can provide access to services defined within a
- * {@link org.apache.tapestry5.ioc.Registry}, or
+ * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
  * to objects or object instances available by other means. Services are accessed via service id, or
  * (when appropriate)
  * by just service interface. The Registry itself implements this interface, as does
@@ -27,7 +26,6 @@ import org.apache.tapestry5.ioc.services
  */
 public interface ObjectLocator
 {
-
     /**
      * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
      * implements the same
@@ -67,8 +65,7 @@ public interface ObjectLocator
     <T> T getService(Class<T> serviceInterface);
 
     /**
-     * Obtains an object indirectly, using the
-     * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
+     * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
      * 
      * @param objectType
      *            the type of object to be returned
@@ -88,8 +85,7 @@ public interface ObjectLocator
     /**
      * Autobuilds a class by finding the public constructor with the most parameters. Services and
      * resources will be
-     * injected into the parameters of the constructor and private field marked with the
-     * {@link Inject} annotation.
+     * injected into the parameters of the constructor and private field marked with the {@link Inject} annotation.
      * 
      * @param <T>
      * @param clazz
@@ -104,9 +100,8 @@ public interface ObjectLocator
     /**
      * Autobuilds a class by finding the public constructor with the most parameters. Services and
      * resources will be
-     * injected into the parameters of the constructor and private field marked with the
-     * {@link Inject} annotation. This version tracks the operation using
-     * {@link OperationTracker#invoke(String, Invokable)}.
+     * injected into the parameters of the constructor and private field marked with the {@link Inject} annotation. This
+     * version tracks the operation using {@link OperationTracker#invoke(String, Invokable)}.
      * 
      * @param <T>
      * @param description
@@ -123,12 +118,14 @@ public interface ObjectLocator
 
     /**
      * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
-     * just-in-time (that is, first
-     * method invocation). In a limited number of cases, it is necessary to use such a proxy to
-     * prevent service
-     * construction cycles, particularly when contributing (directly or indirectly) to the
+     * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
+     * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
      * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
      * of autobuilding).
+     * <p>
+     * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
+     * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
+     * (with dependencies).
      * 
      * @param <T>
      * @param interfaceClass

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java?rev=927558&r1=927557&r2=927558&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java Thu Mar 25 19:34:34 2010
@@ -14,21 +14,37 @@
 
 package org.apache.tapestry5.ioc.internal;
 
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.tapestry5.ioc.*;
 import org.apache.tapestry5.ioc.annotations.Local;
-import org.apache.tapestry5.ioc.def.*;
+import org.apache.tapestry5.ioc.def.ContributionDef;
+import org.apache.tapestry5.ioc.def.ContributionDef2;
+import org.apache.tapestry5.ioc.def.DecoratorDef;
+import org.apache.tapestry5.ioc.def.ModuleDef;
+import org.apache.tapestry5.ioc.def.ServiceDef;
+import org.apache.tapestry5.ioc.def.ServiceDef2;
 import org.apache.tapestry5.ioc.internal.services.PerthreadManagerImpl;
 import org.apache.tapestry5.ioc.internal.services.RegistryShutdownHubImpl;
-import org.apache.tapestry5.ioc.internal.util.*;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.Defense;
+import org.apache.tapestry5.ioc.internal.util.InjectionResources;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.MapInjectionResources;
+import org.apache.tapestry5.ioc.internal.util.OneShotLock;
+import org.apache.tapestry5.ioc.internal.util.Orderer;
 import org.apache.tapestry5.ioc.services.*;
 import org.apache.tapestry5.ioc.util.AvailableValues;
 import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.services.UpdateListenerHub;
 import org.slf4j.Logger;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.*;
-
 public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyProvider
 {
     private static final String SYMBOL_SOURCE_SERVICE_ID = "SymbolSource";
@@ -958,6 +974,14 @@ public class RegistryImpl implements Reg
         // TODO: Check really an interface
         // TODO: Check impl class extends interfaceClass and is concrete
 
+        if (InternalUtils.isLocalFile(implementationClass))
+            return createReloadingProxy(interfaceClass, implementationClass);
+
+        return createNonReloadingProxy(interfaceClass, implementationClass);
+    }
+
+    private <T> T createNonReloadingProxy(Class<T> interfaceClass, final Class<? extends T> implementationClass)
+    {
         final ObjectCreator autobuildCreator = new ObjectCreator()
         {
             public Object createObject()
@@ -983,6 +1007,17 @@ public class RegistryImpl implements Reg
                 implementationClass.getName(), interfaceClass.getName()));
     }
 
+    private <T> T createReloadingProxy(Class<T> interfaceClass, final Class<? extends T> implementationClass)
+    {
+        ReloadableObjectCreator creator = new ReloadableObjectCreator(implementationClass.getClassLoader(),
+                implementationClass.getName(), loggerSource.getLogger(implementationClass), this);
+
+        getService(UpdateListenerHub.class).addUpdateListener(creator);
+
+        return classFactory.createProxy(interfaceClass, creator, String.format("<Autoreload proxy %s(%s)>",
+                implementationClass.getName(), interfaceClass.getName()));
+    }
+
     public Object provideServiceProxy(String serviceId)
     {
         return getService(serviceId, Object.class);

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java?rev=927558&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java Thu Mar 25 19:34:34 2010
@@ -0,0 +1,41 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.internal;
+
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.slf4j.Logger;
+
+/**
+ * Reloadable object creator for non-service objects.
+ */
+public class ReloadableObjectCreator extends AbstractReloadableObjectCreator
+{
+    private final ObjectLocator locator;
+
+    public ReloadableObjectCreator(ClassLoader baseClassLoader, String implementationClassName, Logger logger,
+            ObjectLocator locator)
+    {
+        super(baseClassLoader, implementationClassName, logger);
+
+        this.locator = locator;
+    }
+
+    @Override
+    protected Object createInstance(Class clazz)
+    {
+        return locator.autobuild(clazz);
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java?rev=927558&r1=927557&r2=927558&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java Thu Mar 25 19:34:34 2010
@@ -1,4 +1,4 @@
-// Copyright 2007, 2008, 2009 The Apache Software Foundation
+// Copyright 2007, 2008, 2009, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -25,13 +25,11 @@ import org.apache.tapestry5.ioc.internal
 import org.apache.tapestry5.ioc.internal.util.Defense;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.internal.util.OneShotLock;
-import org.apache.tapestry5.ioc.services.ClassFabUtils;
 import org.apache.tapestry5.ioc.services.ClassFactory;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
-import java.net.URL;
 import java.util.Arrays;
 import java.util.Set;
 
@@ -124,7 +122,7 @@ public class ServiceBinderImpl implement
 
     private ObjectCreatorSource createObjectCreatorSourceFromImplementationClass()
     {
-        if (!preventReloading && isProxiable() && reloadableScope() && isLocalFile(serviceImplementation))
+        if (!preventReloading && isProxiable() && reloadableScope() && InternalUtils.isLocalFile(serviceImplementation))
             return createReloadableConstructorBasedObjectCreatorSource();
 
         return createStandardConstructorBasedObjectCreatorSource();
@@ -140,20 +138,6 @@ public class ServiceBinderImpl implement
         return scope.equalsIgnoreCase(ScopeConstants.DEFAULT);
     }
 
-    /**
-     * Determines if the indicated class is stored as a locally accessible file
-     * (and not, typically, as a file inside a JAR). This is related to automatic
-     * reloading of services.
-     */
-    private boolean isLocalFile(Class clazz)
-    {
-        String path = ClassFabUtils.getPathForClass(clazz);
-
-        URL classFileURL = clazz.getClassLoader().getResource(path);
-
-        return classFileURL != null && classFileURL.getProtocol().equals("file");
-    }
-
     private ObjectCreatorSource createStandardConstructorBasedObjectCreatorSource()
     {
         final Constructor constructor = InternalUtils.findAutobuildConstructor(serviceImplementation);

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java?rev=927558&r1=927557&r2=927558&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java Thu Mar 25 19:34:34 2010
@@ -28,6 +28,7 @@ import java.lang.reflect.InvocationTarge
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
+import java.net.URL;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -56,15 +57,15 @@ import org.apache.tapestry5.ioc.services
 public class InternalUtils
 {
     /**
-     * Leading punctiation on member names that is stripped off to form a property name or new member name.
+     * Leading punctuation on member names that is stripped off to form a property name or new member name.
      */
     private static final String NAME_PREFIX = "_$";
 
     /**
      * Pattern used to eliminate leading and trailing underscores and dollar signs.
      */
-    private static final Pattern NAME_PATTERN = Pattern.compile(
-            "^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$", Pattern.CASE_INSENSITIVE);
+    private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+            Pattern.CASE_INSENSITIVE);
 
     /**
      * Converts a method to a user presentable string using a {@link ClassFactory} to obtain a {@link Location} (where
@@ -137,8 +138,7 @@ public class InternalUtils
         Matcher matcher = NAME_PATTERN.matcher(memberName);
 
         if (!matcher.matches())
-            throw new IllegalArgumentException(String.format(
-                    "Input '%s' is not a valid Java identifier.", memberName));
+            throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
 
         return matcher.group(1);
     }
@@ -180,8 +180,7 @@ public class InternalUtils
      *            to match
      * @return the annotation instance, if found, or null otherwise
      */
-    public static <T extends Annotation> T findAnnotation(Annotation[] annotations,
-            Class<T> annotationClass)
+    public static <T extends Annotation> T findAnnotation(Annotation[] annotations, Class<T> annotationClass)
     {
         for (Annotation a : annotations)
         {
@@ -192,8 +191,8 @@ public class InternalUtils
         return null;
     }
 
-    private static Object calculateInjection(Class injectionType, Type genericType,
-            final Annotation[] annotations, ObjectLocator locator, InjectionResources resources)
+    private static Object calculateInjection(Class injectionType, Type genericType, final Annotation[] annotations,
+            ObjectLocator locator, InjectionResources resources)
     {
         AnnotationProvider provider = new AnnotationProvider()
         {
@@ -236,21 +235,21 @@ public class InternalUtils
             InjectionResources resources, OperationTracker tracker)
     {
 
-        return calculateParameters(locator, resources, method.getParameterTypes(), method
-                .getGenericParameterTypes(), method.getParameterAnnotations(), tracker);
+        return calculateParameters(locator, resources, method.getParameterTypes(), method.getGenericParameterTypes(),
+                method.getParameterAnnotations(), tracker);
     }
 
-    public static Object[] calculateParametersForConstructor(Constructor constructor,
-            ObjectLocator locator, InjectionResources resources, OperationTracker tracker)
+    public static Object[] calculateParametersForConstructor(Constructor constructor, ObjectLocator locator,
+            InjectionResources resources, OperationTracker tracker)
     {
 
         return calculateParameters(locator, resources, constructor.getParameterTypes(), constructor
                 .getGenericParameterTypes(), constructor.getParameterAnnotations(), tracker);
     }
 
-    public static Object[] calculateParameters(final ObjectLocator locator,
-            final InjectionResources resources, Class[] parameterTypes, final Type[] genericTypes,
-            Annotation[][] parameterAnnotations, OperationTracker tracker)
+    public static Object[] calculateParameters(final ObjectLocator locator, final InjectionResources resources,
+            Class[] parameterTypes, final Type[] genericTypes, Annotation[][] parameterAnnotations,
+            OperationTracker tracker)
     {
         int parameterCount = parameterTypes.length;
 
@@ -262,9 +261,8 @@ public class InternalUtils
             final Type genericType = genericTypes[i];
             final Annotation[] annotations = parameterAnnotations[i];
 
-            String description = String.format(
-                    "Determining injection value for parameter #%d (%s)", i + 1, ClassFabUtils
-                            .toJavaClassName(type));
+            String description = String.format("Determining injection value for parameter #%d (%s)", i + 1,
+                    ClassFabUtils.toJavaClassName(type));
 
             final Invokable<Object> operation = new Invokable<Object>()
             {
@@ -317,8 +315,7 @@ public class InternalUtils
                     }
                 };
 
-                String description = String.format(
-                        "Calculating injection value for field '%s' (%s)", f.getName(),
+                String description = String.format("Calculating injection value for field '%s' (%s)", f.getName(),
                         ClassFabUtils.toJavaClassName(f.getType()));
 
                 tracker.run(description, new Runnable()
@@ -345,8 +342,7 @@ public class InternalUtils
                             Object value = resources.findResource(fieldType, f.getGenericType());
 
                             if (value == null)
-                                throw new RuntimeException(UtilMessages.injectResourceFailure(f
-                                        .getName(), fieldType));
+                                throw new RuntimeException(UtilMessages.injectResourceFailure(f.getName(), fieldType));
 
                             inject(object, f, value);
 
@@ -381,8 +377,8 @@ public class InternalUtils
 
                     try
                     {
-                        Object[] parameters = InternalUtils.calculateParametersForMethod(m,
-                                locator, injectionResources, tracker);
+                        Object[] parameters = InternalUtils.calculateParametersForMethod(m, locator,
+                                injectionResources, tracker);
 
                         m.invoke(object, parameters);
                     }
@@ -396,8 +392,8 @@ public class InternalUtils
                     }
 
                     if (fail != null)
-                        throw new RuntimeException(String.format(
-                                "Exception invoking method %s: %s", m, toMessage(fail)), fail);
+                        throw new RuntimeException(String
+                                .format("Exception invoking method %s: %s", m, toMessage(fail)), fail);
                 }
             });
         }
@@ -416,8 +412,8 @@ public class InternalUtils
         }
         catch (Exception ex)
         {
-            throw new RuntimeException(String.format("Unable to set field '%s' of %s to %s: %s",
-                    field.getName(), target, value, toMessage(ex)));
+            throw new RuntimeException(String.format("Unable to set field '%s' of %s to %s: %s", field.getName(),
+                    target, value, toMessage(ex)));
         }
     }
 
@@ -917,8 +913,8 @@ public class InternalUtils
     }
 
     /** @since 5.2.0 */
-    public static <T extends Comparable<T>> List<T> matchAndSort(
-            Collection<? extends T> collection, Predicate<T> predicate)
+    public static <T extends Comparable<T>> List<T> matchAndSort(Collection<? extends T> collection,
+            Predicate<T> predicate)
     {
         Defense.notNull(predicate, "predicate");
 
@@ -934,18 +930,15 @@ public class InternalUtils
 
         return result;
     }
-    
 
-    
     /**
-     * 
      * @since 5.2.0
      */
     public static ContributionDef2 toContributionDef2(final ContributionDef contribution)
     {
-        if(contribution instanceof ContributionDef2)
+        if (contribution instanceof ContributionDef2)
             return (ContributionDef2) contribution;
-        
+
         return new ContributionDef2()
         {
 
@@ -981,7 +974,23 @@ public class InternalUtils
             {
                 return contribution.getServiceId();
             }
-            
+
         };
     }
+
+    /**
+     * Determines if the indicated class is stored as a locally accessible file
+     * (and not, typically, as a file inside a JAR). This is related to automatic
+     * reloading of services.
+     * 
+     * @since 5.2.0
+     */
+    public static boolean isLocalFile(Class clazz)
+    {
+        String path = ClassFabUtils.getPathForClass(clazz);
+
+        URL classFileURL = clazz.getClassLoader().getResource(path);
+
+        return classFileURL != null && classFileURL.getProtocol().equals("file");
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CountingGreeterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CountingGreeterImpl.java?rev=927558&r1=927557&r2=927558&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CountingGreeterImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/CountingGreeterImpl.java Thu Mar 25 19:34:34 2010
@@ -1,10 +1,10 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2010 The Apache Software Foundation
 //
 // Licensed 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
+// 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,
@@ -16,11 +16,9 @@ package org.apache.tapestry5.ioc;
 
 public class CountingGreeterImpl implements Greeter
 {
-    public static int instantiationCount;
-
     public CountingGreeterImpl()
     {
-        instantiationCount++;
+        IntegrationTest.countingGreeterInstantiationCount++;
     }
 
     public String getGreeting()

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java?rev=927558&r1=927557&r2=927558&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java Thu Mar 25 19:34:34 2010
@@ -47,6 +47,8 @@ import org.testng.annotations.Test;
  */
 public class IntegrationTest extends IOCInternalTestCase
 {
+    public static int countingGreeterInstantiationCount;
+
     private Registry buildRegistry()
     {
         return buildRegistry(FredModule.class, BarneyModule.class);
@@ -868,16 +870,15 @@ public class IntegrationTest extends IOC
     {
         Registry r = buildRegistry();
 
-        CountingGreeterImpl.instantiationCount = 0;
+        IntegrationTest.countingGreeterInstantiationCount = 0;
 
         Greeter g = r.proxy(Greeter.class, CountingGreeterImpl.class);
 
-        assertEquals(CountingGreeterImpl.instantiationCount, 0);
+        assertEquals(IntegrationTest.countingGreeterInstantiationCount, 0);
 
-        assertEquals(g.toString(),
-                "<Autobuild proxy org.apache.tapestry5.ioc.CountingGreeterImpl(org.apache.tapestry5.ioc.Greeter)>");
+        assertNotNull(g.toString());
 
-        assertEquals(CountingGreeterImpl.instantiationCount, 0);
+        assertEquals(IntegrationTest.countingGreeterInstantiationCount, 0);
 
         // Show that the class is not instantiated until a method is invoked, and that its
         // only instantiated once.
@@ -885,7 +886,7 @@ public class IntegrationTest extends IOC
         for (int i = 0; i < 5; i++)
         {
             assertEquals(g.getGreeting(), "Hello");
-            assertEquals(CountingGreeterImpl.instantiationCount, 1);
+            assertEquals(IntegrationTest.countingGreeterInstantiationCount, 1);
         }
 
         r.shutdown();

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java?rev=927558&r1=927557&r2=927558&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java Thu Mar 25 19:34:34 2010
@@ -35,6 +35,7 @@ import com.example.ReloadableService;
 /**
  * Test the ability to perform live class reloading of a service implementation.
  */
+@SuppressWarnings("unchecked")
 public class ReloadTest extends TestBase
 {
     private static final String PACKAGE = "com.example";
@@ -92,6 +93,32 @@ public class ReloadTest extends TestBase
         fireUpdateCheck(registry);
 
         assertEquals(reloadable.getStatus(), "updated");
+
+        registry.shutdown();
+    }
+
+    @Test
+    public void reload_a_proxy_object() throws Exception
+    {
+        createImplementationClass("initial proxy");
+
+        Registry registry = createRegistry();
+
+        Class<ReloadableService> clazz = (Class<ReloadableService>) classLoader.loadClass(CLASS);
+
+        ReloadableService reloadable = registry.proxy(ReloadableService.class, clazz);
+
+        assertEquals(reloadable.getStatus(), "initial proxy");
+
+        Thread.currentThread().sleep(1500);
+
+        createImplementationClass("updated proxy");
+
+        fireUpdateCheck(registry);
+
+        assertEquals(reloadable.getStatus(), "updated proxy");
+
+        registry.shutdown();
     }
 
     private void fireUpdateCheck(Registry registry)
@@ -134,6 +161,8 @@ public class ReloadTest extends TestBase
             assertEquals(ex.getMessage(),
                     "Service implementation class com.example.ReloadableServiceImpl does not have a suitable public constructor.");
         }
+
+        registry.shutdown();
     }
 
     private void createImplementationClass(String status) throws Exception