Author: hlship
Date: Sun Nov 26 10:25:21 2006
New Revision: 479391
URL: http://svn.apache.org/viewvc?view=rev&rev=479391
Log:
Add a base package, under the root package, for base classes.
Ensure that even component classes that contain errors will be reloaded once
changed.
Added:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
- copied, changed from r479384,
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/AbstractField.java
Removed:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/AbstractField.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
Copied:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
(from r479384,
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/AbstractField.java)
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java?view=diff&rev=479391&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/AbstractField.java&r1=479384&p2=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java&r2=479391
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/AbstractField.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
Sun Nov 26 10:25:21 2006
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.corelib.components;
+package org.apache.tapestry.corelib.base;
import java.io.Serializable;
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java?view=diff&rev=479391&r1=479390&r2=479391
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java
Sun Nov 26 10:25:21 2006
@@ -18,6 +18,7 @@
import org.apache.tapestry.annotations.AfterRender;
import org.apache.tapestry.annotations.BeginRender;
import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.corelib.base.AbstractField;
import org.apache.tapestry.services.WebRequest;
/** A Checkbox coponent is simply a <input type="checkbox">. */
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java?view=diff&rev=479391&r1=479390&r2=479391
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextArea.java
Sun Nov 26 10:25:21 2006
@@ -19,6 +19,7 @@
import org.apache.tapestry.annotations.BeforeRenderBody;
import org.apache.tapestry.annotations.BeginRender;
import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.corelib.base.AbstractField;
import org.apache.tapestry.services.WebRequest;
/**
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java?view=diff&rev=479391&r1=479390&r2=479391
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/TextField.java
Sun Nov 26 10:25:21 2006
@@ -18,6 +18,7 @@
import org.apache.tapestry.annotations.AfterRender;
import org.apache.tapestry.annotations.BeginRender;
import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.corelib.base.AbstractField;
import org.apache.tapestry.services.WebRequest;
/**
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java?view=diff&rev=479391&r1=479390&r2=479391
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentClassResolverImpl.java
Sun Nov 26 10:25:21 2006
@@ -88,6 +88,7 @@
_componentInstantiatorSource.addPackage(rootPackage + ".pages");
_componentInstantiatorSource.addPackage(rootPackage + ".components");
_componentInstantiatorSource.addPackage(rootPackage + ".mixins");
+ _componentInstantiatorSource.addPackage(rootPackage + ".base");
}
/** When the class loader is invalidated, clear any cached page names or
component types. */
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java?view=diff&rev=479391&r1=479390&r2=479391
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImpl.java
Sun Nov 26 10:25:21 2006
@@ -12,258 +12,269 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package org.apache.tapestry.internal.services;
-
+package org.apache.tapestry.internal.services;
+
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
-
-import java.net.URL;
-import java.util.Map;
-import java.util.Set;
-
-import javassist.CannotCompileException;
-import javassist.ClassPath;
-import javassist.ClassPool;
-import javassist.CtClass;
-import javassist.Loader;
-import javassist.LoaderClassPath;
-import javassist.NotFoundException;
-import javassist.Translator;
-
-import org.apache.commons.logging.Log;
-import org.apache.tapestry.events.UpdateListener;
-import org.apache.tapestry.internal.event.InvalidationEventHubImpl;
-import org.apache.tapestry.internal.util.URLChangeTracker;
+
+import java.net.URL;
+import java.util.Map;
+import java.util.Set;
+
+import javassist.CannotCompileException;
+import javassist.ClassPath;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.Loader;
+import javassist.LoaderClassPath;
+import javassist.NotFoundException;
+import javassist.Translator;
+
+import org.apache.commons.logging.Log;
+import org.apache.tapestry.events.UpdateListener;
+import org.apache.tapestry.internal.event.InvalidationEventHubImpl;
+import org.apache.tapestry.internal.util.URLChangeTracker;
import org.apache.tapestry.ioc.internal.util.Defense;
-
-/**
- * A wrapper around a Javassist class loader that allows certain classes to be
modified as they are
- * loaded.
- */
-public final class ComponentInstantiatorSourceImpl extends
InvalidationEventHubImpl implements
- Translator, ComponentInstantiatorSource, UpdateListener
-{
- private final Set<String> _controlledPackageNames = newSet();
-
- private final URLChangeTracker _changeTracker = new URLChangeTracker();
-
- private final ClassLoader _parent;
-
- private ClassPool _classPool;
-
- private Loader _loader;
-
- private final ComponentClassTransformer _transformer;
-
- private final Log _log;
-
- /** Map from class name to Instantiator. */
- private final Map<String, Instantiator> _instantiatorMap = newMap();
-
- private class PackageAwareLoader extends Loader
- {
- public PackageAwareLoader(ClassLoader parent, ClassPool classPool)
- {
- super(parent, classPool);
- }
-
- @Override
- protected Class findClass(String className) throws
ClassNotFoundException
- {
- if (inControlledPackage(className))
- return super.findClass(className);
-
- // Returning null forces delegation to the parent class loader.
-
- return null;
- }
-
- }
-
- public ComponentInstantiatorSourceImpl(ClassLoader parent,
- ComponentClassTransformer transformer, Log log)
- {
- _parent = parent;
- _transformer = transformer;
- _log = log;
-
- initializeService();
- }
-
- /** @return the class loader used when loading enhanced/modified classes */
- public ClassLoader getClassLoader()
- {
- return _loader;
- }
-
- public synchronized void checkForUpdates()
- {
- if (!_changeTracker.containsChanges())
- return;
-
- _changeTracker.clear();
- _instantiatorMap.clear();
-
- // Release the existing class pool, loader and so forth.
- // Create a new one.
-
- initializeService();
-
- // Tell everyone that the world has changed and they should discard
- // their cache.
-
- fireInvalidationEvent();
- }
-
- /**
- * Invoked at object creation, or when there are updates to class files
(i.e., invalidation), to
- * create a new set of Javassist class pools and loaders.
- */
- private void initializeService()
- {
- _classPool = new ClassPool();
-
- ClassPath path = new LoaderClassPath(_parent);
-
- _classPool.appendClassPath(path);
-
- _loader = new PackageAwareLoader(_parent, _classPool);
-
- try
- {
- _loader.addTranslator(_classPool, this);
- }
- catch (Exception ex)
- {
- throw new RuntimeException(ex);
- }
- }
-
- // This is called from well within a synchronized block.
- public void onLoad(ClassPool pool, String classname) throws
NotFoundException,
- CannotCompileException
- {
- _log.debug("BEGIN onLoad " + classname);
-
- // This is our chance to make changes to the CtClass before it is
loaded into memory.
-
- String diag = "FAIL";
-
- try
- {
- CtClass ctClass = pool.get(classname);
-
- // Force the creation of the super-class before the target class.
-
- forceSuperclassTransform(ctClass);
-
- // Do the transformations here
-
- _transformer.transformComponentClass(ctClass, _loader);
-
- diag = "END";
- }
- catch (ClassNotFoundException ex)
- {
- throw new CannotCompileException(ex);
- }
- finally
- {
- _log.debug(String.format("%5s onLoad %s", diag, classname));
- }
-
- String path = classname.replace('.', '/') + ".class";
-
- URL url = _loader.getResource(path);
-
- _changeTracker.add(url);
- }
-
- private void forceSuperclassTransform(CtClass ctClass) throws
NotFoundException,
- ClassNotFoundException
- {
- CtClass superClass = ctClass.getSuperclass();
-
- findClass(superClass.getName());
- }
-
- /** Does nothing. */
- public void start(ClassPool pool) throws NotFoundException,
CannotCompileException
- {
- }
-
- public synchronized Instantiator findInstantiator(String classname)
- {
- Instantiator result = _instantiatorMap.get(classname);
-
- if (result == null)
- {
- Class instanceClass = findClass(classname);
-
- result = _transformer.createInstantiator(instanceClass);
-
- _instantiatorMap.put(classname, result);
- }
-
- return result;
- }
-
- private Class findClass(String classname)
- {
- try
- {
- return _loader.loadClass(classname);
- }
- catch (ClassNotFoundException ex)
- {
- throw new RuntimeException(ex);
- }
- }
-
- /**
- * Returns true if the package for the class name is in a package that is
controlled by the
- * enhancer. Controlled packages are identified by [EMAIL PROTECTED]
#addPackage(String)}.
- */
-
- boolean inControlledPackage(String classname)
- {
- String packageName = stripTail(classname);
-
- while (packageName != null)
- {
- if (_controlledPackageNames.contains(packageName))
- return true;
-
- packageName = stripTail(packageName);
- }
-
- return false;
- }
-
- private String stripTail(String input)
- {
- int lastdot = input.lastIndexOf('.');
-
- if (lastdot < 0)
- return null;
-
- return input.substring(0, lastdot);
- }
-
- // synchronized may be overkill, but that's ok.
- public synchronized void addPackage(String packageName)
- {
- Defense.notBlank(packageName, "packageName");
-
- // TODO: Should we check that packages are not nested?
-
- _controlledPackageNames.add(packageName);
- }
-
- public boolean exists(String className)
- {
- String path = className.replace(".", "/") + ".class";
-
- return _parent.getResource(path) != null;
- }
-}
+
+/**
+ * A wrapper around a Javassist class loader that allows certain classes to be
modified as they are
+ * loaded.
+ */
+public final class ComponentInstantiatorSourceImpl extends
InvalidationEventHubImpl implements
+ Translator, ComponentInstantiatorSource, UpdateListener
+{
+ private final Set<String> _controlledPackageNames = newSet();
+
+ private final URLChangeTracker _changeTracker = new URLChangeTracker();
+
+ private final ClassLoader _parent;
+
+ private ClassPool _classPool;
+
+ private Loader _loader;
+
+ private final ComponentClassTransformer _transformer;
+
+ private final Log _log;
+
+ /** Map from class name to Instantiator. */
+ private final Map<String, Instantiator> _instantiatorMap = newMap();
+
+ private class PackageAwareLoader extends Loader
+ {
+ public PackageAwareLoader(ClassLoader parent, ClassPool classPool)
+ {
+ super(parent, classPool);
+ }
+
+ @Override
+ protected Class findClass(String className) throws
ClassNotFoundException
+ {
+ if (inControlledPackage(className))
+ return super.findClass(className);
+
+ // Returning null forces delegation to the parent class loader.
+
+ return null;
+ }
+
+ }
+
+ public ComponentInstantiatorSourceImpl(ClassLoader parent,
+ ComponentClassTransformer transformer, Log log)
+ {
+ _parent = parent;
+ _transformer = transformer;
+ _log = log;
+
+ initializeService();
+ }
+
+ /** @return the class loader used when loading enhanced/modified classes */
+ public ClassLoader getClassLoader()
+ {
+ return _loader;
+ }
+
+ public synchronized void checkForUpdates()
+ {
+ if (!_changeTracker.containsChanges())
+ return;
+
+ _changeTracker.clear();
+ _instantiatorMap.clear();
+
+ // Release the existing class pool, loader and so forth.
+ // Create a new one.
+
+ initializeService();
+
+ // Tell everyone that the world has changed and they should discard
+ // their cache.
+
+ fireInvalidationEvent();
+ }
+
+ /**
+ * Invoked at object creation, or when there are updates to class files
(i.e., invalidation), to
+ * create a new set of Javassist class pools and loaders.
+ */
+ private void initializeService()
+ {
+ _classPool = new ClassPool();
+
+ ClassPath path = new LoaderClassPath(_parent);
+
+ _classPool.appendClassPath(path);
+
+ _loader = new PackageAwareLoader(_parent, _classPool);
+
+ try
+ {
+ _loader.addTranslator(_classPool, this);
+ }
+ catch (Exception ex)
+ {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // This is called from well within a synchronized block.
+ public void onLoad(ClassPool pool, String classname) throws
NotFoundException,
+ CannotCompileException
+ {
+ _log.debug("BEGIN onLoad " + classname);
+
+ // This is our chance to make changes to the CtClass before it is
loaded into memory.
+
+ String diag = "FAIL";
+
+ // If we are loading a class, it is because it is in a controlled
package. There may be
+ // errors in the class that keep it from loading. By adding it to the
change tracker
+ // early, we ensure that when the class is fixed, the change is picked
up. Originally,
+ // this code was at the end of the method, and classes that contained
errors would not be
+ // reloaded even after the code was fixed.
+
+ addClassFileToChangeTracker(classname);
+
+ try
+ {
+ CtClass ctClass = pool.get(classname);
+
+ // Force the creation of the super-class before the target class.
+
+ forceSuperclassTransform(ctClass);
+
+ // Do the transformations here
+
+ _transformer.transformComponentClass(ctClass, _loader);
+
+ diag = "END";
+ }
+ catch (ClassNotFoundException ex)
+ {
+ throw new CannotCompileException(ex);
+ }
+ finally
+ {
+ _log.debug(String.format("%5s onLoad %s", diag, classname));
+ }
+ }
+
+ private void addClassFileToChangeTracker(String classname)
+ {
+ String path = classname.replace('.', '/') + ".class";
+
+ URL url = _loader.getResource(path);
+
+ _changeTracker.add(url);
+ }
+
+ private void forceSuperclassTransform(CtClass ctClass) throws
NotFoundException,
+ ClassNotFoundException
+ {
+ CtClass superClass = ctClass.getSuperclass();
+
+ findClass(superClass.getName());
+ }
+
+ /** Does nothing. */
+ public void start(ClassPool pool) throws NotFoundException,
CannotCompileException
+ {
+ }
+
+ public synchronized Instantiator findInstantiator(String classname)
+ {
+ Instantiator result = _instantiatorMap.get(classname);
+
+ if (result == null)
+ {
+ Class instanceClass = findClass(classname);
+
+ result = _transformer.createInstantiator(instanceClass);
+
+ _instantiatorMap.put(classname, result);
+ }
+
+ return result;
+ }
+
+ private Class findClass(String classname)
+ {
+ try
+ {
+ return _loader.loadClass(classname);
+ }
+ catch (ClassNotFoundException ex)
+ {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * Returns true if the package for the class name is in a package that is
controlled by the
+ * enhancer. Controlled packages are identified by [EMAIL PROTECTED]
#addPackage(String)}.
+ */
+
+ boolean inControlledPackage(String classname)
+ {
+ String packageName = stripTail(classname);
+
+ while (packageName != null)
+ {
+ if (_controlledPackageNames.contains(packageName))
+ return true;
+
+ packageName = stripTail(packageName);
+ }
+
+ return false;
+ }
+
+ private String stripTail(String input)
+ {
+ int lastdot = input.lastIndexOf('.');
+
+ if (lastdot < 0)
+ return null;
+
+ return input.substring(0, lastdot);
+ }
+
+ // synchronized may be overkill, but that's ok.
+ public synchronized void addPackage(String packageName)
+ {
+ Defense.notBlank(packageName, "packageName");
+
+ // TODO: Should we check that packages are not nested?
+
+ _controlledPackageNames.add(packageName);
+ }
+
+ public boolean exists(String className)
+ {
+ String path = className.replace(".", "/") + ".class";
+
+ return _parent.getResource(path) != null;
+ }
+}
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt?view=diff&rev=479391&r1=479390&r2=479391
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/component-classes.apt
Sun Nov 26 10:25:21 2006
@@ -4,6 +4,12 @@
Component Classes
+ Component classes in Tapestry 5 are much easier than in Tapestry 4. There
are no base classes to extend from, the classes are concrete (not abstract),
and there's no XML file. There is still
+ a bit of configuration in the form of Java annotations, but
+ those now go directly onto fields of your class, rather than on abstract
getters and setters (the case in Tapestry 4).
+
+ Classes for pages, for components and for component mixins are all created
in an identical way.
+
* Component Class Basics
Creating page and component classes in Tapestry 5 is a breeze.
@@ -50,6 +56,29 @@
In another departure from Tapestry 4, these methods are not necessarily
public; they
can have any visibility you like.
+
+Component Packages
+
+ Component classes must exist within an appropriate package (this is
necessary for runtime code transformation
+ and class reloading to operate).
+
+ These packages exist under the application's root package.
+
+ For pages, place classes in <root>.<<pages>>. Page names are mapped to
classes within this package.
+
+ For components, place classes in <root>.<<components>>. Component types are
mapped to classes within this package.
+
+ For mixins, place classes in <root>.<<mixins>>. Mixin types are mapped to
classes within this package.
+
+ In addition, it is common for an application to have base classes, often
<abstract> base classes, that should not be directly referenced. These
+ should not go in the <<pages>>, <<components>> or <<mixins>> packages,
because they then look like valid pages, components or mixins. Instead,
+ use the <root>.<<base>> package to store such base classes.
+
+Sub-Folders / Sub-Packages
+
+ Classes do not have to go directly inside the package (pages, components,
mixins, etc.). It is valid to create a sub-package
+ to store some of the classes. The sub-package name becomes part of the page
name or component type. Thus you might define a page component
+ <<<com.example.myapp.pages.admin.CreateUser>>> and the logical page name
(which often shows up inside URLs) will be <<admin/CreateUser>>.
Pages vs. Components
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java?view=diff&rev=479391&r1=479390&r2=479391
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
Sun Nov 26 10:25:21 2006
@@ -401,6 +401,7 @@
source.addPackage(packageName + ".pages");
source.addPackage(packageName + ".components");
source.addPackage(packageName + ".mixins");
+ source.addPackage(packageName + ".base");
}
/**