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/12 06:21:17 UTC
svn commit: r922146 - in /tapestry/tapestry5/trunk/tapestry-ioc/src:
main/java/org/apache/tapestry5/ioc/internal/ test/java/com/
test/java/com/example/ test/java/org/apache/tapestry5/ioc/ test/resources/
Author: hlship
Date: Fri Mar 12 05:21:16 2010
New Revision: 922146
URL: http://svn.apache.org/viewvc?rev=922146&view=rev
Log:
TAP5-1013: Add unit tests for service implementation reloading
Added:
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadModule.java (with props)
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadableService.java (with props)
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java (with props)
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/resources/log4j.properties
Modified: 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=922146&r1=922145&r2=922146&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreator.java Fri Mar 12 05:21:16 2010
@@ -144,7 +144,7 @@ public class ReloadableObjectCreator imp
private Class reloadImplementationClass()
{
if (logger.isDebugEnabled())
- logger.debug("%s class %s.", firstTime ? "Loading" : "Reloading", implementationClassName);
+ logger.debug(String.format("%s class %s.", firstTime ? "Loading" : "Reloading", implementationClassName));
ClassLoader reloadingClassLoader = new ReloadingClassLoader(baseClassLoader);
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=922146&r1=922145&r2=922146&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 Fri Mar 12 05:21:16 2010
@@ -178,13 +178,18 @@ public class ServiceBinderImpl implement
return new ReloadableObjectCreatorSource(classFactory, bindMethod, serviceInterface, serviceImplementation);
}
+ @SuppressWarnings("unchecked")
public <T> ServiceBindingOptions bind(Class<T> serviceClass)
{
if (serviceClass.isInterface())
{
try
{
- Class<T> implementationClass = (Class<T>) Class.forName(serviceClass.getName() + "Impl");
+ String expectedImplName = serviceClass.getName() + "Impl";
+
+ ClassLoader classLoader = classFactory.getClassLoader();
+
+ Class<T> implementationClass = (Class<T>) classLoader.loadClass(expectedImplName);
if (!implementationClass.isInterface() && serviceClass.isAssignableFrom(implementationClass)) { return bind(
serviceClass, implementationClass); }
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadModule.java?rev=922146&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadModule.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadModule.java Fri Mar 12 05:21:16 2010
@@ -0,0 +1,26 @@
+// 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 com.example;
+
+import org.apache.tapestry5.ioc.ServiceBinder;
+
+public class ReloadModule
+{
+ public static void bind(ServiceBinder binder)
+ {
+ // We'll use Javassist to create an implementation at runtime, then change that implementation.
+ binder.bind(ReloadableService.class);
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadModule.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadableService.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadableService.java?rev=922146&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadableService.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadableService.java Fri Mar 12 05:21:16 2010
@@ -0,0 +1,20 @@
+// 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 com.example;
+
+public interface ReloadableService
+{
+ String getStatus();
+}
Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/com/example/ReloadableService.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: 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=922146&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java Fri Mar 12 05:21:16 2010
@@ -0,0 +1,185 @@
+// 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;
+
+import java.io.File;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtMethod;
+
+import org.apache.tapestry5.ioc.test.TestBase;
+import org.apache.tapestry5.services.UpdateListenerHub;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.example.ReloadModule;
+import com.example.ReloadableService;
+
+/**
+ * Test the ability to perform live class reloading of a service implementation.
+ */
+public class ReloadTest extends TestBase
+{
+ private static final String PACKAGE = "com.example";
+
+ private static final String CLASS = PACKAGE + ".ReloadableServiceImpl";
+
+ private File classesDir;
+
+ private ClassLoader classLoader;
+
+ @BeforeClass
+ public void setup() throws Exception
+ {
+ String uid = Long.toHexString(System.currentTimeMillis());
+
+ classesDir = new File(System.getProperty("java.io.tmpdir"), uid);
+
+ // URLClassLoader REQUIRES that File URLs end with a slash! That's a half hour of my life gone!
+
+ URL classesURL = new URL("file:" + classesDir.getCanonicalPath() + "/");
+
+ System.out.println("Reload classes dir: " + classesURL);
+
+ classLoader = new URLClassLoader(new URL[]
+ { classesURL }, Thread.currentThread().getContextClassLoader());
+ }
+
+ @Test
+ public void reload_a_service_implementation() throws Exception
+ {
+ // First, create the initial implementation
+
+ createImplementationClass("initial");
+
+ Registry registry = createRegistry();
+
+ ReloadableService reloadable = registry.getService(ReloadableService.class);
+
+ fireUpdateCheck(registry);
+
+ assertEquals(reloadable.getStatus(), "initial");
+
+ fireUpdateCheck(registry);
+
+ // Sleep long enough that the Java millisecond clock advances.
+
+ Thread.currentThread().sleep(1500);
+
+ createImplementationClass("updated");
+
+ // Doesn't take effect until after the update check
+
+ assertEquals(reloadable.getStatus(), "initial");
+
+ fireUpdateCheck(registry);
+
+ assertEquals(reloadable.getStatus(), "updated");
+ }
+
+ private void fireUpdateCheck(Registry registry)
+ {
+ registry.getService(UpdateListenerHub.class).fireCheckForUpdates();
+ }
+
+ private Registry createRegistry()
+ {
+ RegistryBuilder builder = new RegistryBuilder(classLoader);
+
+ builder.add(ReloadModule.class);
+
+ return builder.build();
+ }
+
+ @Test
+ public void invalid_service_implementation() throws Exception
+ {
+ createImplementationClass("initial");
+
+ Registry registry = createRegistry();
+
+ ReloadableService reloadable = registry.getService(ReloadableService.class);
+
+ createInvalidImplentationClass();
+
+ Thread.currentThread().sleep(1500);
+
+ fireUpdateCheck(registry);
+
+ try
+ {
+ reloadable.getStatus();
+
+ unreachable();
+ }
+ catch (Exception ex)
+ {
+ assertEquals(ex.getMessage(),
+ "Service implementation class com.example.ReloadableServiceImpl does not have a suitable public constructor.");
+ }
+ }
+
+ private void createImplementationClass(String status) throws Exception
+ {
+ ClassPool pool = new ClassPool(null);
+
+ pool.appendSystemPath();
+
+ CtClass ctClass = pool.makeClass(CLASS);
+
+ ctClass.addInterface(pool.get(ReloadableService.class.getName()));
+
+ CtMethod method = new CtMethod(pool.get("java.lang.String"), "getStatus", null, ctClass);
+
+ method.setBody(String.format("return \"%s\";", status));
+
+ ctClass.addMethod(method);
+
+ ctClass.writeFile(classesDir.getAbsolutePath());
+ }
+
+ private void createInvalidImplentationClass() throws Exception
+ {
+ ClassPool pool = new ClassPool(null);
+
+ pool.appendSystemPath();
+
+ CtClass ctClass = pool.makeClass(CLASS);
+
+ ctClass.addInterface(pool.get(ReloadableService.class.getName()));
+
+ CtMethod method = new CtMethod(pool.get("java.lang.String"), "getStatus", null, ctClass);
+
+ method.setBody("return \"unreachable\";");
+
+ ctClass.addMethod(method);
+
+ CtConstructor constructor = new CtConstructor(new CtClass[0], ctClass);
+
+ constructor.setBody("return $0;");
+
+ constructor.setModifiers(Modifier.PROTECTED);
+
+ ctClass.addConstructor(constructor);
+
+ ctClass.writeFile(classesDir.getAbsolutePath());
+
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/ReloadTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/resources/log4j.properties?rev=922146&r1=922145&r2=922146&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/resources/log4j.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/resources/log4j.properties Fri Mar 12 05:21:16 2010
@@ -1,4 +1,4 @@
-# Copyright 2005, 2006, 2009 The Apache Software Foundation
+# Copyright 2005, 2006, 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.
@@ -28,5 +28,6 @@ log4j.category.tapestry.ioc.ClassFactory
log4j.category.org.apache.tapestry5.ioc.FredModule=debug
log4j.category.org.apache.tapestry5.ioc.AdviceDemoModule.Greeter=debug
+log4j.category.com.example=debug