You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by ri...@apache.org on 2005/10/12 23:38:26 UTC

svn commit: r315054 - in /beehive/trunk/netui: src/compiler-core/org/apache/beehive/netui/compiler/model/ src/pageflow/org/apache/beehive/netui/pageflow/ src/pageflow/org/apache/beehive/netui/pageflow/config/ src/pageflow/org/apache/beehive/netui/pagef...

Author: rich
Date: Wed Oct 12 14:37:36 2005
New Revision: 315054

URL: http://svn.apache.org/viewcvs?rev=315054&view=rev
Log:
- Fixed a case similar to http://issues.apache.org/jira/browse/BEEHIVE-960, where loading a JAR resource through an URL could cause Tomcat 5.5.x redeploy issues because of file-locking on Windows.  For the original bug, I entered http://issues.apache.org/bugzilla/show_bug.cgi?id=37034 on Commons Digester (and provided a patch), which would provide a workaround for the issue (a JDK bug, really).

- Removed a duplicated mechanism for creating form bean classes.

- Fixed up the Reloadable Classes not-yet-feature.  It's still disabled by default -- you can't try it unless you read the code.  :)

tests: bvt in netui (WinXP)
BB: same (linux)


Modified:
    beehive/trunk/netui/src/compiler-core/org/apache/beehive/netui/compiler/model/FormBeanModel.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/AutoRegisterActionServlet.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/PageFlowRequestProcessor.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/config/PageFlowActionFormBean.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/ReloadableClassHandler.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/StorageHandler.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DefaultReloadableClassHandler.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DeferredSessionStorageHandler.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/SimpleSessionStorageHandler.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/AnnotationAttribute.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotation.java
    beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotations.java
    beehive/trunk/netui/src/util/org/apache/beehive/netui/util/internal/BouncyClassLoader.java
    beehive/trunk/netui/test/ant/build.xml
    beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionMethodOverload/expectedOutput/struts-config-PF_ActionMethodOverload.expected
    beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionUseFormBean/expectedOutput/struts-config-PF_ActionUseFormBean.expected
    beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionWithForm/expectedOutput/struts-config-PF_ActionWithForm.expected
    beehive/trunk/netui/test/src/compilerTests/testsuite/PF_CatchExceptionHandler/expectedOutput/struts-config-PF_CatchExceptionHandler.expected
    beehive/trunk/netui/test/src/compilerTests/testsuite/PF_DeprecatedExceptionHandler/expectedOutput/struts-config-PF_DeprecatedExceptionHandler.expected
    beehive/trunk/netui/test/src/compilerTests/testsuite/simpleActionReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleActionReadOnlyUseFormBeanWarning.expected
    beehive/trunk/netui/test/src/compilerTests/testsuite/simpleReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleReadOnlyUseFormBeanWarning.expected

Modified: beehive/trunk/netui/src/compiler-core/org/apache/beehive/netui/compiler/model/FormBeanModel.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/compiler-core/org/apache/beehive/netui/compiler/model/FormBeanModel.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/compiler-core/org/apache/beehive/netui/compiler/model/FormBeanModel.java (original)
+++ beehive/trunk/netui/src/compiler-core/org/apache/beehive/netui/compiler/model/FormBeanModel.java Wed Oct 12 14:37:36 2005
@@ -124,6 +124,7 @@
         setElementAttribute(element, "id", _id);
         setElementAttribute(element, "className", getClassName());
         setElementAttribute(element, "dynamic", _dynamic);
+        setElementAttribute(element, "className", CUSTOM_ACTION_FORM_BEAN_CLASSNAME);
         
         if ( _actualType != null && ! _actualType.equals(element.getAttribute("type")) )
         {

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/AutoRegisterActionServlet.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/AutoRegisterActionServlet.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/AutoRegisterActionServlet.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/AutoRegisterActionServlet.java Wed Oct 12 14:37:36 2005
@@ -24,6 +24,8 @@
 import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper;
 import org.apache.beehive.netui.pageflow.internal.AdapterManager;
 import org.apache.beehive.netui.pageflow.config.PageFlowControllerConfig;
+import org.apache.beehive.netui.pageflow.handler.Handlers;
+import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler;
 import org.apache.beehive.netui.util.Bundle;
 import org.apache.beehive.netui.util.internal.DiscoveryUtils;
 import org.apache.beehive.netui.util.config.ConfigUtil;
@@ -58,6 +60,7 @@
 import java.io.ObjectOutputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -86,6 +89,7 @@
     private transient Digester _cachedConfigDigester = null;
     private Map _configParams = null;
     private ModuleConfigLocator[] _moduleConfigLocators = null;
+    private ReloadableClassHandler _rch;
     
     private static final Logger _log = Logger.getInstance( AutoRegisterActionServlet.class );
 
@@ -95,6 +99,7 @@
     public void init()
         throws ServletException
     {
+        _rch = Handlers.get(getServletContext()).getReloadableClassHandler();
         super.init();
         setupModuleConfigLocators();
     }
@@ -388,21 +393,30 @@
                 //
                 if ( url != null )
                 {
-                    InputSource is = new InputSource( url.toExternalForm() );
-                    input = getConfigResourceAsStream( path );
-                    is.setByteStream( input );
+                    URLConnection conn = url.openConnection();
+                    conn.setUseCaches(false);
+                    InputStream in = conn.getInputStream();
                     
-                    // also, we're not letting it fail here either.
-                    try
-                    {
-                        digester.parse( is );
-                        getServletContext().setAttribute( Globals.MODULE_KEY + prefix, moduleConfig );
-                    }
-                    catch ( Exception e )
-                    {
-                        _log.error( Bundle.getString( "PageFlow_Struts_ModuleParseError", path ), e );
+                    try {
+                        InputSource is = new InputSource(in);
+                        is.setSystemId(url.toString());
+                        input = getConfigResourceAsStream( path );
+                        is.setByteStream( input );
+                        
+                        // also, we're not letting it fail here either.
+                        try
+                        {
+                            digester.parse( is );
+                            getServletContext().setAttribute( Globals.MODULE_KEY + prefix, moduleConfig );
+                        }
+                        catch ( Exception e )
+                        {
+                            _log.error( Bundle.getString( "PageFlow_Struts_ModuleParseError", path ), e );
+                        }
+                        input.close();
+                    } finally {
+                        in.close();
                     }
-                    input.close();
                 }
                 else
                 {
@@ -501,7 +515,7 @@
         URL resource = getServletContext().getResource( path );
         if ( resource != null ) return resource;
         if ( path.startsWith( "/" ) ) path = path.substring( 1 );
-        return Thread.currentThread().getContextClassLoader().getResource( path );
+        return _rch.getResource( path );
     }
 
     /**
@@ -516,7 +530,7 @@
         InputStream stream = getServletContext().getResourceAsStream( path );
         if ( stream != null ) return stream;
         if ( path.startsWith( "/" ) ) path = path.substring( 1 );
-        return Thread.currentThread().getContextClassLoader().getResourceAsStream( path );
+        return _rch.getResourceAsStream( path );
     }
     
     /**
@@ -913,6 +927,7 @@
         {
             String modulePrefix = ( String ) ii.next();
             servletContext.removeAttribute( Globals.MODULE_KEY + modulePrefix );
+            servletContext.removeAttribute( Globals.REQUEST_PROCESSOR_KEY + modulePrefix );
         }
         
         _registeredModules.clear();

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/PageFlowRequestProcessor.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/PageFlowRequestProcessor.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/PageFlowRequestProcessor.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/PageFlowRequestProcessor.java Wed Oct 12 14:37:36 2005
@@ -151,64 +151,6 @@
         return super.processActionCreate( request, response, actionMapping );
     }
 
-    /**
-     * Same as code in RequestUtils.createActionForm(), but doesn't try to get the form bean out of
-     * the request/session (i.e., always creates a new one).
-     */
-    private ActionForm createActionForm( ActionMapping mapping, HttpServletRequest request )
-    {
-        String name = mapping.getName();
-
-        assert name != null : mapping.getPath();
-        if ( name == null ) return null;
-
-        FormBeanConfig config = moduleConfig.findFormBeanConfig( name );
-        ActionForm instance;
-
-        //
-        // Create the form bean.  There's special handling for dyna-form-beans.
-        //
-        if ( config.getDynamic() )
-        {
-            try
-            {
-                DynaActionFormClass dynaClass = DynaActionFormClass.createDynaActionFormClass( config );
-                instance = ( ActionForm ) dynaClass.newInstance();
-                ( ( DynaActionForm ) instance ).initialize( mapping );
-
-                if ( _log.isDebugEnabled() )
-                {
-                    _log.debug( " Creating new DynaActionForm instance " + "of type '" + config.getType() + '\'' );
-                }
-            }
-            catch ( Exception e )
-            {
-                _log.error( servlet.getInternal().getMessage( "formBean", config.getType() ), e );
-                return null;
-            }
-        }
-        else
-        {
-            try
-            {
-                instance = ( ActionForm ) InternalUtils.newReloadableInstance( config.getType(), getServletContext() );
-
-                if ( _log.isDebugEnabled() )
-                {
-                    _log.debug( " Creating new ActionForm instance " + "of type '" + config.getType() + '\'' );
-                }
-            }
-            catch ( Exception e )
-            {
-                _log.error( servlet.getInternal().getMessage( "formBean", config.getType() ), e );
-                return null;
-            }
-        }
-
-        instance.setServlet( servlet );
-        return instance;
-    }
-
     private Field getPageFlowScopedFormMember( ActionMapping mapping, HttpServletRequest request )
     {
         if ( mapping instanceof PageFlowActionMapping )
@@ -303,7 +245,7 @@
 
                 if ( form == null ) // the pageflow hasn't filled the value yet
                 {
-                    form = createActionForm( mapping, request );
+                    form = InternalUtils.createActionForm( mapping, moduleConfig, servlet, getServletContext() );
                     form.reset( mapping, request );
                     formMemberField.set( fc, InternalUtils.unwrapFormBean( form ) );
                 }

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/config/PageFlowActionFormBean.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/config/PageFlowActionFormBean.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/config/PageFlowActionFormBean.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/config/PageFlowActionFormBean.java Wed Oct 12 14:37:36 2005
@@ -19,6 +19,12 @@
 
 import org.apache.struts.config.FormBeanConfig;
 import org.apache.struts.action.ActionFormBean;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.validator.BeanValidatorForm;
+import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler;
+import org.apache.beehive.netui.pageflow.handler.Handlers;
+import org.apache.beehive.netui.util.logging.Logger;
 
 
 /**
@@ -26,6 +32,8 @@
  */
 public class PageFlowActionFormBean extends ActionFormBean
 {
+    private static final Logger _log = Logger.getInstance(PageFlowActionFormBean.class);
+    
     private String _actualType;  // applicable for non-ActionForm-derived form types
 
 
@@ -34,8 +42,54 @@
         return _actualType;
     }
 
-    public void setActualType( String actualType )
+    public void setActualType(String actualType)
     {
         _actualType = actualType;
+    }
+
+    /**
+     * <p>
+     * Create and return an <code>ActionForm</code> instance appropriate
+     * to the information in this <code>FormBeanConfig</code>.
+     * </p>
+     * <p>
+     * This is different than the base implementation in that it uses our ReloadableClassHandler
+     * to load the form bean class.
+     * </p>
+     *
+     * @param servlet The action servlet
+     * @return ActionForm instance
+     * @exception IllegalAccessException if the Class or the appropriate
+     *  constructor is not accessible
+     * @exception InstantiationException if this Class represents an abstract
+     *  class, an array class, a primitive type, or void; or if instantiation
+     *  fails for some other reason
+     */
+    public ActionForm createActionForm(ActionServlet servlet)
+        throws IllegalAccessException, InstantiationException {
+
+
+        // Create a new form bean instance
+        if (getDynamic()) {
+            return super.createActionForm(servlet);
+        }
+
+        try {
+            ReloadableClassHandler rch = Handlers.get(servlet.getServletContext()).getReloadableClassHandler();
+            Object obj = rch.newInstance(getType());
+
+            ActionForm form = null;
+            if (obj instanceof ActionForm) {
+                form = (ActionForm)obj;
+            } else  {
+                form = new BeanValidatorForm(obj);
+            }
+
+            form.setServlet(servlet);
+            return form;
+        } catch (ClassNotFoundException e) {
+            _log.error("Could not find form bean class " + getType(), e);
+            return null;
+        }
     }
 }

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/ReloadableClassHandler.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/ReloadableClassHandler.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/ReloadableClassHandler.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/ReloadableClassHandler.java Wed Oct 12 14:37:36 2005
@@ -19,6 +19,9 @@
 
 import org.apache.beehive.netui.pageflow.RequestContext;
 
+import java.net.URL;
+import java.io.InputStream;
+
 
 /**
  * Handler for loading and reloading classes.
@@ -33,10 +36,14 @@
         throws ClassNotFoundException;
 
     Class loadCachedClass( String className );
-    
+
     void reloadClasses( RequestContext context );
 
     ClassLoader getClassLoader();
 
     boolean isReloadEnabled();
+
+    URL getResource(String name);
+
+    InputStream getResourceAsStream(String name);
 }

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/StorageHandler.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/StorageHandler.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/StorageHandler.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/handler/StorageHandler.java Wed Oct 12 14:37:36 2005
@@ -19,9 +19,11 @@
 
 import org.apache.beehive.netui.pageflow.RequestContext;
 
+import java.util.Enumeration;
+
 /**
  * Handler for storing Page Flow objects.
- */ 
+ */
 public interface StorageHandler
         extends Handler
 {
@@ -31,35 +33,35 @@
      * @param context the current RequestContext.
      * @param attributeName the name of the attribute to set.
      * @param value the attribute value.
-     */ 
+     */
     public void setAttribute( RequestContext context, String attributeName, Object value );
-    
+
     /**
      * Remove a named attribute.
      * 
      * @param context the current RequestContext.
      * @param attributeName the name of the attribute to remove.
-     */ 
+     */
     public void removeAttribute( RequestContext context, String attributeName );
-    
+
     /**
      * Get a named attribute.
      * 
      * @param context the current RequestContext.
      * @param attributeName the name of the attribute to get.
      * @return the attribute, or <code>null</code> if there is no such named attribute.
-     */ 
+     */
     public Object getAttribute( RequestContext context, String attributeName );
-    
+
     /**
      * Ensure that the given named attribute is replicated in a cluster for session failover, if appropriate.
      * 
      * @param context the current request context.
      * @param attributeName the name of the attribute for which failover should be ensured.
      * @param value the value of the attribute for which failover should be ensured.
-     */ 
+     */
     public void ensureFailover( RequestContext context, String attributeName, Object value );
-    
+
     /**
      * Tell whether a given binding event should be allowed to occur.  This is mainly useful in cases when this
      * handler writes data to some underlying storage (like the <code>HttpSession</code>) at some time other than
@@ -68,13 +70,28 @@
      * 
      * @param event the binding event, e.g., <code>javax.servlet.http.HttpSessionBindingEvent</code>
      * @return <code>true</code> if the event should be processed.
-     */ 
+     */
     public boolean allowBindingEvent( Object event );
-    
+
     /**
      * Apply any deferred changes, at the end of a chain of requests.
      * 
      * @param context the current request context.
-     */ 
+     */
     public void applyChanges( RequestContext context );
+
+    /**
+     * Drop any deferred changes, so they will not be applied at the end of the chain of requests.
+     * 
+     * @param context the current request context.
+     */
+    public void dropChanges( RequestContext context );
+
+    /**
+     * Get all attribute names.
+     * 
+     * @param context the current request context.
+     * @return an Enumeration over all the attribute names;
+     */
+    public Enumeration getAttributeNames( RequestContext context );
 }

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DefaultReloadableClassHandler.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DefaultReloadableClassHandler.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DefaultReloadableClassHandler.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DefaultReloadableClassHandler.java Wed Oct 12 14:37:36 2005
@@ -20,7 +20,11 @@
 import org.apache.beehive.netui.pageflow.AutoRegisterActionServlet;
 import org.apache.beehive.netui.pageflow.ServletContainerAdapter;
 import org.apache.beehive.netui.pageflow.RequestContext;
+import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
 import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler;
+import org.apache.beehive.netui.pageflow.handler.HandlerConfig;
+import org.apache.beehive.netui.pageflow.handler.Handler;
+import org.apache.beehive.netui.pageflow.handler.Handlers;
 import org.apache.beehive.netui.util.internal.BouncyClassLoader;
 import org.apache.beehive.netui.util.internal.cache.ClassLevelCache;
 import org.apache.beehive.netui.util.logging.Logger;
@@ -28,48 +32,105 @@
 
 import javax.servlet.http.HttpSession;
 import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
 import java.util.Enumeration;
 import java.util.Map;
+import java.util.ArrayList;
+import java.util.Iterator;
+
 import org.apache.beehive.netui.util.internal.concurrent.InternalConcurrentHashMap;
 import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
 
 import org.apache.struts.action.ActionServlet;
 
 
+/**
+ * Handler that can load classes through a classloader that gets dropped/refreshed when time stamps on binary files
+ * change.
+ */
 public class DefaultReloadableClassHandler
         extends DefaultHandler
     implements ReloadableClassHandler
 {
     private static final Logger _log = Logger.getInstance( DefaultReloadableClassHandler.class );
+    private static final boolean _enabled = System.getProperty("pageflow.bouncy") != null; 
     
-    private BouncyClassLoader _pageFlowClassLoader = null;
+    private transient BouncyClassLoader _pageFlowClassLoader = null;
     
     public DefaultReloadableClassHandler( ServletContext servletContext )
     {
         init( null, null, servletContext );
+
+    }
+
+    public void init(HandlerConfig handlerConfig, Handler previousHandler, ServletContext servletContext)
+    {
+        super.init(handlerConfig, previousHandler, servletContext);
+        
+        // This feature is in prototype mode, and only enabled through a System property for now.
+        if (_enabled) {
+            _log.info("Reloadable classes are enabled.");
+            createClassLoader(servletContext);
+        }
+    }
+
+    public void reinit(ServletContext servletContext) {
+        super.reinit(servletContext);
+
+        if (_enabled && _pageFlowClassLoader == null) {
+            createClassLoader(servletContext);
+        }
+    }
+
+    private void createClassLoader(ServletContext servletContext) 
+    {
+        ServletContainerAdapter servletContainerAdapter = AdapterManager.getServletContainerAdapter( servletContext );
+        
+        if (servletContainerAdapter.isInProductionMode()) {
+            _log.info("In production mode; reloadable classes disabled.");
+            return;
+        }
+        
+        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+        File[] classDirs = null;
         
-        // This feature is disabled for now.
-        if ( false )
+        // TODO: make this configurable in netui-config.xml.  You should be able to specify absolute files
+        // and also context-relative paths.
         {
-            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
-            ServletContainerAdapter servletContainerAdapter = AdapterManager.getServletContainerAdapter( servletContext );
-            File[] classDirs = null;
+            ArrayList classDirsList = new ArrayList();
             
-            // TODO: make this configurable in netui-config.xml.  You should be able to specify absolute files
-            // and also context-relative paths.
-            {
-                String path = servletContext.getRealPath( "/WEB-INF/classes" );
-                
-                if ( path != null )
-                {
-                    File file = new File( path );
-                    if ( file.isDirectory() ) classDirs = new File[]{ file };
+            String path = servletContext.getRealPath( "/WEB-INF/reloadableClasses" );
+            if ( path != null ) {
+                File file = new File( path );
+                if ( file.isDirectory() ) {
+                    classDirsList.add(file);
                 }
             }
             
-            if ( classDirs != null && ! servletContainerAdapter.isInProductionMode() )
-            {
-                _pageFlowClassLoader = new BouncyClassLoader( classDirs, contextClassLoader );
+            path = servletContext.getRealPath( "/WEB-INF/classes" );
+            if ( path != null ) {
+                File file = new File( path );
+                if ( file.isDirectory() ) {
+                    classDirsList.add(file);
+                }
+            }
+            
+            if (! classDirsList.isEmpty()) {
+                classDirs = (File[]) classDirsList.toArray(new File[classDirsList.size()]);
+            }
+        }
+        
+        if ( classDirs != null )
+        {
+            _pageFlowClassLoader = new BouncyClassLoader( classDirs, contextClassLoader );
+            
+            // TODO: remove the following println when this feature is done.
+            System.out.println("*** Bouncy Page Flow enabled, using classloader " + _pageFlowClassLoader);
+        
+            if (_log.isInfoEnabled()) {
+                _log.info("Reloadable Page Flow classes enabled, using classloader " + _pageFlowClassLoader);
             }
         }
     }
@@ -118,12 +179,31 @@
                 return _pageFlowClassLoader.loadClass( className );
             }
         }
-        else
-        {
-            return DiscoveryUtils.getClassLoader().loadClass( className );
+        
+        return DiscoveryUtils.getClassLoader().loadClass( className );
+    }
+
+    public URL getResource(String name)
+    {
+        if (_pageFlowClassLoader != null) {
+            synchronized (this) {
+                return _pageFlowClassLoader.getResource(name);
+            }
         }
+        
+        return DiscoveryUtils.getClassLoader().getResource(name);
     }
-    
+
+    public InputStream getResourceAsStream(String name) {
+        if (_pageFlowClassLoader != null) {
+            synchronized (this) {
+                return _pageFlowClassLoader.getResourceAsStream(name);
+            }
+        }
+        
+        return DiscoveryUtils.getClassLoader().getResourceAsStream(name);
+    }
+
     public void reloadClasses( RequestContext context )
     {
         if ( _pageFlowClassLoader == null )
@@ -135,56 +215,85 @@
         {
             if ( _pageFlowClassLoader.isStale() )
             {
-                _log.debug( "Classes modified; bouncing classloader." );
+                // TODO: remove the following println when this feature is done.
+                System.out.println("*** Classes/resources modified; bouncing classloader.");
+        
+                _log.info( "Classes/resources modified; bouncing classloader." );
                 
-                //
-                // First go through the session and remove any attributes whose classes were loaded by the stale
-                // classloader.
-                //
-                HttpSession session = InternalUtils.getHttpSession( context.getRequest(), false );
-                
-                if ( session != null )
-                {
-                    for ( Enumeration e = session.getAttributeNames(); e.hasMoreElements(); )
-                    {
-                        String attrName = ( String ) e.nextElement();
-                        Object attr = session.getAttribute( attrName );
-                        if ( attr.getClass().getClassLoader() == _pageFlowClassLoader )
-                        {
-                            if ( _log.isDebugEnabled() )
-                            {
-                                _log.debug( "Removing session attribute " + attrName + " (" + attr
-                                             + ") because its ClassLoader is being bounced." );
-                            }
-                            
-                            session.removeAttribute( attrName );
-                        }
-                    }
-                }
+                // First go through the session and request and remove any attributes whose classes were loaded by the
+                // stale classloader.
+                ServletRequest request = context.getRequest();
+                removeSessionAttributes(request);
+                removeRequestAttributes(request);
+                removeRequestAttributes(ScopedServletUtils.getOuterServletRequest(request));
+                
+                // Remove any deferred storage attributes.
+                Handlers.get(getServletContext()).getStorageHandler().dropChanges(context);
                 
-                //
                 // Clear all caches of methods, etc.
-                //
                 ClassLevelCache.clearAll();
                 
-                //
                 // Clear out all registered modules from the ActionServlet.
-                //
-                ActionServlet actionServlet = InternalUtils.getActionServlet( getServletContext() );
+                ActionServlet actionServlet = InternalUtils.getActionServlet(getServletContext());
                 
-                if ( actionServlet instanceof AutoRegisterActionServlet )
-                {
-                    ( ( AutoRegisterActionServlet ) actionServlet ).clearRegisteredModules();
+                if (actionServlet instanceof AutoRegisterActionServlet) {
+                    ((AutoRegisterActionServlet) actionServlet).clearRegisteredModules();
                 }
                 
-                //
                 // Bounce the classloader.
-                //
                 init( getConfig(), getPreviousHandler(), getServletContext() );
             }
         }
     }
     
+    private void removeSessionAttributes(ServletRequest request)
+    {
+        HttpSession session = InternalUtils.getHttpSession(request, false);
+
+        if (session != null) {
+            ArrayList attrsToRemove = new ArrayList();
+
+            for (Enumeration e = session.getAttributeNames(); e.hasMoreElements();) {
+                String attrName = (String) e.nextElement();
+                Object attr = session.getAttribute(attrName);
+                if (attr.getClass().getClassLoader() == _pageFlowClassLoader) {
+                    attrsToRemove.add(attrName);
+                }
+            }
+
+            for (Iterator i = attrsToRemove.iterator(); i.hasNext();) {
+                String attrName = (String) i.next();
+                if (_log.isDebugEnabled()) {
+                    _log.debug("Removing session attribute " + attrName + " because its ClassLoader is being bounced.");
+                }
+
+                session.removeAttribute(attrName);
+            }
+        }
+    }
+    
+    private void removeRequestAttributes(ServletRequest request)
+    {
+        ArrayList attrsToRemove = new ArrayList();
+
+        for (Enumeration e = request.getAttributeNames(); e.hasMoreElements();) {
+            String attrName = (String) e.nextElement();
+            Object attr = request.getAttribute(attrName);
+            if (attr.getClass().getClassLoader() == _pageFlowClassLoader) {
+                attrsToRemove.add(attrName);
+            }
+        }
+
+        for (Iterator i = attrsToRemove.iterator(); i.hasNext();) {
+            String attrName = (String) i.next();
+            if (_log.isDebugEnabled()) {
+                _log.debug("Removing request attribute " + attrName + " because its ClassLoader is being bounced.");
+            }
+
+            request.removeAttribute(attrName);
+        }
+    }
+    
     public ClassLoader getClassLoader()
     {
         if ( _pageFlowClassLoader != null )
@@ -200,7 +309,7 @@
     
     public boolean isReloadEnabled()
     {
-        return _pageFlowClassLoader != null;
+        return _enabled;
     }
     
     public ReloadableClassHandler getRegisteredReloadableClassHandler()

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DeferredSessionStorageHandler.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DeferredSessionStorageHandler.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DeferredSessionStorageHandler.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/DeferredSessionStorageHandler.java Wed Oct 12 14:37:36 2005
@@ -21,6 +21,7 @@
 import org.apache.beehive.netui.pageflow.RequestContext;
 import org.apache.beehive.netui.pageflow.ServletContainerAdapter;
 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
+import org.apache.beehive.netui.util.logging.Logger;
 
 import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
@@ -32,6 +33,9 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Enumeration;
+import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * This alternate session storage handler does not write any attribute into the session until the very end of a chain
@@ -39,14 +43,16 @@
  * concurrent forwarded requests, each of which is modifying the same data, in a more reasonable way.  Basically,
  * each request works in its own snapshot of the session, and the last one to commit is the one whose snapshot wins.
  * This is a better alternative thatn allowing them to interfere with each other in the middle of the request chain.
- */ 
+ */
 public class DeferredSessionStorageHandler
         extends DefaultHandler
         implements StorageHandler
 {
+    private static final Logger _log = Logger.getInstance(DeferredSessionStorageHandler.class);
+    
     private static final String CHANGELIST_ATTR = InternalConstants.ATTR_PREFIX + "changedAttrs";
     private static final String FAILOVER_MAP_ATTR = InternalConstants.ATTR_PREFIX + "failoverAttrs";
-    
+
     private static ThreadLocal _isCommittingChanges =
             new ThreadLocal()
             {
@@ -55,12 +61,12 @@
                     return Boolean.FALSE;
                 }
             };
-    
+
     public DeferredSessionStorageHandler( ServletContext servletContext )
     {
         init( null, null, servletContext );
     }
-    
+
     private static final class SessionBindingEvent
         extends HttpSessionBindingEvent
     {
@@ -74,19 +80,23 @@
             super( httpSession, attrName, attrVal );
         }
     }
-    
+
     public void setAttribute( RequestContext context, String attrName, Object value )
     {
+        if (_log.isTraceEnabled()) {
+            _log.trace("setAttribute: " + attrName + "=" + value);
+        }
+        
         HttpServletRequest request = ScopedServletUtils.getOuterRequest( ( HttpServletRequest ) context.getRequest() );
         Object currentValue = request.getAttribute( attrName );
-        
+
         //
         // Note that we unconditionally get/create the session.  We want to make sure that the session exists when
         // we set an attribute, since we will *not* create it in applyChanges, to prevent recreation of an
         // intentionally-invalidated session.
         //
         HttpSession session = request.getSession();
-        
+
         //
         // Emulate a setAttribute on the session: if the value is an HttpSessionBindingListener, invoke its
         // valueUnbound().  Note that we don't currently care about calling valueBound().
@@ -96,19 +106,23 @@
             HttpSessionBindingEvent event = new SessionBindingEvent( session, attrName, currentValue );
             ( ( HttpSessionBindingListener ) currentValue ).valueUnbound( event );
         }
-        
+
         request.setAttribute( attrName, value );
         getChangedAttributesList( request, true, false ).add( attrName );
-        
+
         HashMap failoverAttrs = getFailoverAttributesMap( request, false, false );
         if ( failoverAttrs != null ) failoverAttrs.remove( attrName );
     }
-    
+
     public void removeAttribute( RequestContext context, String attrName )
     {
+        if (_log.isTraceEnabled()) {
+            _log.trace("removeAttribute: " + attrName);
+        }
+        
         HttpServletRequest request = ScopedServletUtils.getOuterRequest( ( HttpServletRequest ) context.getRequest() );
         Object currentValue = request.getAttribute( attrName );
-        
+
         //
         // Emulate a removeAttribute on the session: if the value is an HttpSessionBindingListener, invoke its
         // valueUnbound().
@@ -118,54 +132,59 @@
             HttpSessionBindingEvent event = new SessionBindingEvent( request.getSession(), attrName, currentValue );
             ( ( HttpSessionBindingListener ) currentValue ).valueUnbound( event );
         }
-        
+
         request.removeAttribute( attrName );
         getChangedAttributesList( request, true, false ).add( attrName );
-        
+
         HashMap failoverAttrs = getFailoverAttributesMap( request, false, false );
         if ( failoverAttrs != null ) failoverAttrs.remove( attrName );
     }
-    
+
     public Object getAttribute( RequestContext context, String attributeName )
     {
+        if (_log.isTraceEnabled()) {
+            _log.trace("getAttribute: " + attributeName);
+        }
+        
         HttpServletRequest request = ScopedServletUtils.getOuterRequest( ( HttpServletRequest ) context.getRequest() );
         Object val = request.getAttribute( attributeName );
         if ( val != null ) return val;
-        //
+
         // If the attribute isn't present in the request and is in the list of changed attrs, then it was removed.
         // Don't fall back to the session attribute in that case.
-        //
         HashSet changedAttrs = getChangedAttributesList( request, false, false );
         if ( changedAttrs != null && changedAttrs.contains( attributeName ) ) return null;
-        
-        
-        //
+
+
         // Get the attribute out of the session, and put it into the request.  Until applyChanges is called, this is
         // the value we'll use.
-        //
         HttpSession session = request.getSession( false );
         if ( session != null )
         {
             val = session.getAttribute( attributeName );
             if ( val != null ) request.setAttribute( attributeName, val );
         }
-        
+
         return val;
     }
-    
+
     public void applyChanges( RequestContext context )
     {
         HttpServletRequest request = ScopedServletUtils.getOuterRequest( ( HttpServletRequest ) context.getRequest() );
         HttpSession session = request.getSession( false );
+
+        if (_log.isDebugEnabled()) {
+            _log.debug("Applying changes for request " + request.getRequestURI());
+        }
         
         //
         // If the session doesn't exist, we don't want to recreate it.  It has most likely been intentionally
         // invalidated, since we did ensure its existance in getAttribute.
         //
         if ( session == null ) return;
-        
+
         HashSet changedAttrs = getChangedAttributesList( request, false, true );
-        
+
         if ( changedAttrs != null )
         {
             //
@@ -176,22 +195,22 @@
             {
                 String attrName = ( String ) i.next();
                 Object val = request.getAttribute( attrName );
-                
+
                 if ( val != null )
                 {
-                    //
                     // Write it to the session, but only if the current value isn't already this value.
-                    //
                     Object currentValue = session.getAttribute( attrName );
-                    
+
                     if ( currentValue != val )
                     {
-                        //
+                        if (_log.isTraceEnabled()) {
+                            _log.trace("Committing attribute " + attrName + " to the session.");
+                        }
+                        
                         // This ThreadLocal value allows others (e.g., an HttpSessionBindingListener like
                         // PageFlowManagedObject) that we're in the middle of committing changes to the session.
-                        //
                         _isCommittingChanges.set( Boolean.TRUE );
-                        
+
                         try
                         {
                             session.setAttribute( attrName, val );
@@ -200,18 +219,22 @@
                         {
                             _isCommittingChanges.set( Boolean.FALSE );
                         }
-                        
+
                         request.removeAttribute( attrName );
                     }
                 }
                 else
                 {
+                    if (_log.isTraceEnabled()) {
+                        _log.trace("Removing attribute " + attrName + " from the session.");
+                    }
+                        
                     //
                     // This ThreadLocal value allows others (e.g., an HttpSessionBindingListener like
                     // PageFlowManagedObject) that we're in the middle of committing changes to the session.
                     //
                     _isCommittingChanges.set( Boolean.TRUE );
-                    
+
                     try
                     {
                         session.removeAttribute( attrName );
@@ -223,58 +246,102 @@
                 }
             }
         }
-        
-        
+
+
         //
         // Now go through the attributes we need to ensure-failover on.
         //
         HashMap failoverAttrs = getFailoverAttributesMap( request, false, true );
-        
+
         if ( failoverAttrs != null )
         {
             ServletContainerAdapter sa = AdapterManager.getServletContainerAdapter( getServletContext() );
-            
+
             for ( Iterator i = failoverAttrs.entrySet().iterator(); i.hasNext(); )
             {
                 Map.Entry entry = ( Map.Entry ) i.next();
+                if (_log.isTraceEnabled()) {
+                    _log.trace("Ensure failover for attribute " + entry.getKey());
+                }
                 sa.ensureFailover( ( String ) entry.getKey(), entry.getValue(), request );
             }
         }
     }
-    
+
+    public void dropChanges(RequestContext context)
+    {
+        HttpServletRequest request = ScopedServletUtils.getOuterRequest( ( HttpServletRequest ) context.getRequest() );
+        if (_log.isDebugEnabled()) {
+            _log.debug("Dropping changes for request " + request.getRequestURI());
+        }
+        getChangedAttributesList( request, false, true );
+        getFailoverAttributesMap( request, false, true );
+    }
+
+    public Enumeration getAttributeNames(RequestContext context) {
+        HttpServletRequest request = ScopedServletUtils.getOuterRequest( ( HttpServletRequest ) context.getRequest() );
+        HttpSession session = request.getSession( false );
+        ArrayList attrNames = new ArrayList();
+
+        // Start with the attribute names that are in the session.
+        if (session != null) {
+            for (Enumeration e = session.getAttributeNames(); e.hasMoreElements(); ) {
+                attrNames.add((String) e.nextElement());
+            }
+        }
+
+        // Add or remove as necessary, based on the list of changed attributes.
+        HashSet changedAttrs = getChangedAttributesList( request, false, false );
+        if (changedAttrs != null) {
+            for (Iterator i = changedAttrs.iterator(); i.hasNext(); ) {
+                String attrName = (String) i.next();
+
+                if (request.getAttribute(attrName) != null) {
+                    attrNames.add(attrName);
+                } else {
+                    // If the attribute isn't present in the request and is in the session, then it's scheduled for
+                    // removal.
+                    attrNames.remove(attrName);
+                }
+            }
+        }
+
+        return Collections.enumeration(attrNames);
+    }
+
     public void ensureFailover( RequestContext context, String attributeName, Object value )
     {
         HttpServletRequest request = ScopedServletUtils.getOuterRequest( ( HttpServletRequest ) context.getRequest() );
         getFailoverAttributesMap( request, true, false ).put( attributeName, value );
     }
-    
+
     private static HashSet getChangedAttributesList( ServletRequest request, boolean create, boolean remove )
     {
         HashSet set = ( HashSet ) request.getAttribute( CHANGELIST_ATTR );
-        
+
         if ( set == null && create )
         {
             set = new HashSet();
             request.setAttribute( CHANGELIST_ATTR, set );
         }
-        
+
         if ( set!= null && remove ) request.removeAttribute( CHANGELIST_ATTR );
-        
+
         return set;
     }
-    
+
     private static HashMap getFailoverAttributesMap( ServletRequest request, boolean create, boolean remove )
     {
         HashMap map = ( HashMap ) request.getAttribute( FAILOVER_MAP_ATTR );
-        
+
         if ( map == null && create )
         {
             map = new HashMap();
             request.setAttribute( FAILOVER_MAP_ATTR, map );
         }
-        
+
         if ( map != null && remove ) request.removeAttribute( FAILOVER_MAP_ATTR );
-        
+
         return map;
     }
 

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/SimpleSessionStorageHandler.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/SimpleSessionStorageHandler.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/SimpleSessionStorageHandler.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/SimpleSessionStorageHandler.java Wed Oct 12 14:37:36 2005
@@ -23,13 +23,15 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 import javax.servlet.ServletContext;
+import java.util.Enumeration;
+import java.util.Collections;
 
 /**
  * This storage handler simply puts/gets attributes in the session.  It does not do anything to support multiple
  * concurrent forwarded requests that are simultaneously modifying session data.
  * 
  * @see DeferredSessionStorageHandler
- */ 
+ */
 public class SimpleSessionStorageHandler
         extends DefaultHandler
         implements StorageHandler
@@ -38,10 +40,10 @@
     {
         init( null, null, servletContext );
     }
-    
+
     public void setAttribute( RequestContext context, String attributeName, Object value )
     {
-        ( ( HttpServletRequest ) context.getRequest() ).getSession().setAttribute( attributeName, value ); 
+        ( ( HttpServletRequest ) context.getRequest() ).getSession().setAttribute( attributeName, value );
     }
 
     public void removeAttribute( RequestContext context, String attributeName )
@@ -69,5 +71,19 @@
 
     public void applyChanges(RequestContext context)
     {
+    }
+    
+    public void dropChanges(RequestContext context)
+    {
+    }
+
+    public Enumeration getAttributeNames(RequestContext context)
+    {
+        HttpSession session = ((HttpServletRequest) context.getRequest()).getSession(false);
+        if (session != null) {
+            return session.getAttributeNames();
+        } else {
+            return Collections.enumeration(Collections.emptyList());
+        }
     }
 }

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/AnnotationAttribute.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/AnnotationAttribute.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/AnnotationAttribute.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/AnnotationAttribute.java Wed Oct 12 14:37:36 2005
@@ -17,10 +17,13 @@
  */
 package org.apache.beehive.netui.pageflow.internal.annotationreader;
 
+import java.io.Serializable;
+
 /**
  *
  */
 public class AnnotationAttribute
+    implements Serializable
 {
     private String _attributeName;
     private String _stringValue;

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotation.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotation.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotation.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotation.java Wed Oct 12 14:37:36 2005
@@ -17,10 +17,13 @@
  */
 package org.apache.beehive.netui.pageflow.internal.annotationreader;
 
+import java.io.Serializable;
+
 /**
  *
  */
 public class ProcessedAnnotation
+        implements Serializable
 {
 
     private String _annotationName;

Modified: beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotations.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotations.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotations.java (original)
+++ beehive/trunk/netui/src/pageflow/org/apache/beehive/netui/pageflow/internal/annotationreader/ProcessedAnnotations.java Wed Oct 12 14:37:36 2005
@@ -18,11 +18,13 @@
 package org.apache.beehive.netui.pageflow.internal.annotationreader;
 
 import java.util.Map;
+import java.io.Serializable;
 
 /**
  *
  */
 public class ProcessedAnnotations
+        implements Serializable
 {
 
     private String _typeName;

Modified: beehive/trunk/netui/src/util/org/apache/beehive/netui/util/internal/BouncyClassLoader.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/util/org/apache/beehive/netui/util/internal/BouncyClassLoader.java?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/src/util/org/apache/beehive/netui/util/internal/BouncyClassLoader.java (original)
+++ beehive/trunk/netui/src/util/org/apache/beehive/netui/util/internal/BouncyClassLoader.java Wed Oct 12 14:37:36 2005
@@ -17,18 +17,18 @@
  */
 package org.apache.beehive.netui.util.internal;
 
-import java.net.URLClassLoader;
 import java.net.URL;
+import java.net.MalformedURLException;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.FileNotFoundException;
 import java.io.BufferedInputStream;
 import java.io.IOException;
+
 import org.apache.beehive.netui.util.internal.concurrent.InternalConcurrentHashMap;
 import java.util.Map;
 import java.util.Iterator;
-import java.lang.reflect.Method;
 import java.security.SecureClassLoader;
 
 import org.apache.beehive.netui.util.logging.Logger;
@@ -36,7 +36,7 @@
 
 /**
  * ClassLoader that takes precendence over its parent for loading classes, and which is aware of timestamps on its
- * binaries (and thus knows when it needs to be bounced.
+ * binaries (and thus knows when it needs to be bounced).
  */
 public class BouncyClassLoader
         extends SecureClassLoader
@@ -68,14 +68,44 @@
             {
                 _timestamps.put( file, new Long( file.lastModified() ) );
                 byte[] bytes = getBytes( file );
+                
+                if (_log.isDebugEnabled()) {
+                    _log.debug("Loading class " + name + " from file " + file);
+                }
                 if ( bytes != null ) return super.defineClass( name, bytes, 0, bytes.length );
             }
         }
         
         return super.loadClass( name );
     }
-    
-    byte[] getBytes( File file )
+
+    public URL getResource(String name)
+    {
+        for ( int i = 0; i < _classDirs.length; ++i )
+        {
+            File file = new File( _classDirs[i].getPath(), name );
+            
+            if ( file.exists() )
+            {
+                _timestamps.put( file, new Long( file.lastModified() ) );
+                
+                try {
+                    if (_log.isDebugEnabled()) {
+                        _log.debug("Loading resource " + name + " from file " + file);
+                    }
+                    return file.toURL();
+                } catch (MalformedURLException e) {
+                    // Shouldn't happen if the file exists.
+                    e.printStackTrace();
+                    assert false : "malformed URL for file " + file.getPath();
+                }
+            }
+        }
+        
+        return super.getResource(name);
+    }
+
+    private byte[] getBytes( File file )
     {
         try
         {
@@ -115,7 +145,12 @@
         for ( Iterator i = _timestamps.entrySet().iterator(); i.hasNext(); )
         {
             Map.Entry entry = ( Map.Entry ) i.next();
-            if ( ( ( File ) entry.getKey() ).lastModified() > ( ( Long ) entry.getValue() ).longValue() ) return true;
+            if ( ( ( File ) entry.getKey() ).lastModified() > ( ( Long ) entry.getValue() ).longValue() ) {
+                if (_log.isDebugEnabled()) {
+                    _log.debug("Detected modified class/resource in " + entry.getKey());
+                }
+                return true;
+            }
         }
         
         return false;

Modified: beehive/trunk/netui/test/ant/build.xml
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/ant/build.xml?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/test/ant/build.xml (original)
+++ beehive/trunk/netui/test/ant/build.xml Wed Oct 12 14:37:36 2005
@@ -63,7 +63,7 @@
         </ant>
     </target>
 
-    <target name="compiler.bvt">
+    <target name="compiler.bvt" description="Runs the Compiler BVT suite">
         <ant antfile="junitCore.xml" target="run.compiler.tests" inheritAll="false">
             <property name="testout.dir" location="${compiler.testResults.dir}"/>
             <property name="formatter.type" value="xml"/>

Modified: beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionMethodOverload/expectedOutput/struts-config-PF_ActionMethodOverload.expected
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionMethodOverload/expectedOutput/struts-config-PF_ActionMethodOverload.expected?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionMethodOverload/expectedOutput/struts-config-PF_ActionMethodOverload.expected (original)
+++ beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionMethodOverload/expectedOutput/struts-config-PF_ActionMethodOverload.expected Wed Oct 12 14:37:36 2005
@@ -3,7 +3,7 @@
 <struts-config>
   <!-- Generated from /WEB-INF/.tmpbeansrc/PF_ActionMethodOverload/Controller.java on Tue Aug 09 16:45:48 MDT 2005 -->
   <form-beans>
-    <form-bean name="tempForm" type="PF_ActionMethodOverload.Controller$TempForm"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="tempForm" type="PF_ActionMethodOverload.Controller$TempForm"/>
   </form-beans>
   <global-exceptions/>
   <global-forwards>

Modified: beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionUseFormBean/expectedOutput/struts-config-PF_ActionUseFormBean.expected
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionUseFormBean/expectedOutput/struts-config-PF_ActionUseFormBean.expected?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionUseFormBean/expectedOutput/struts-config-PF_ActionUseFormBean.expected (original)
+++ beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionUseFormBean/expectedOutput/struts-config-PF_ActionUseFormBean.expected Wed Oct 12 14:37:36 2005
@@ -3,8 +3,8 @@
 <struts-config>
   <!-- Generated from /WEB-INF/.tmpbeansrc/PF_ActionUseFormBean/Controller.java on Tue Aug 09 16:45:55 MDT 2005 -->
   <form-beans>
-    <form-bean name="formOne_nonFlowScoped" type="PF_ActionUseFormBean.Controller$FormOne"/>
-    <form-bean name="formOne" type="PF_ActionUseFormBean.Controller$FormOne"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="formOne_nonFlowScoped" type="PF_ActionUseFormBean.Controller$FormOne"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="formOne" type="PF_ActionUseFormBean.Controller$FormOne"/>
   </form-beans>
   <global-exceptions/>
   <global-forwards>

Modified: beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionWithForm/expectedOutput/struts-config-PF_ActionWithForm.expected
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionWithForm/expectedOutput/struts-config-PF_ActionWithForm.expected?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionWithForm/expectedOutput/struts-config-PF_ActionWithForm.expected (original)
+++ beehive/trunk/netui/test/src/compilerTests/testsuite/PF_ActionWithForm/expectedOutput/struts-config-PF_ActionWithForm.expected Wed Oct 12 14:37:36 2005
@@ -3,7 +3,7 @@
 <struts-config>
   <!-- Generated from /WEB-INF/.tmpbeansrc/PF_ActionWithForm/Controller.java on Tue Aug 09 16:45:58 MDT 2005 -->
   <form-beans>
-    <form-bean name="tempForm" type="PF_ActionWithForm.Controller$TempForm"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="tempForm" type="PF_ActionWithForm.Controller$TempForm"/>
   </form-beans>
   <global-exceptions/>
   <global-forwards>

Modified: beehive/trunk/netui/test/src/compilerTests/testsuite/PF_CatchExceptionHandler/expectedOutput/struts-config-PF_CatchExceptionHandler.expected
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/src/compilerTests/testsuite/PF_CatchExceptionHandler/expectedOutput/struts-config-PF_CatchExceptionHandler.expected?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/test/src/compilerTests/testsuite/PF_CatchExceptionHandler/expectedOutput/struts-config-PF_CatchExceptionHandler.expected (original)
+++ beehive/trunk/netui/test/src/compilerTests/testsuite/PF_CatchExceptionHandler/expectedOutput/struts-config-PF_CatchExceptionHandler.expected Wed Oct 12 14:37:36 2005
@@ -3,7 +3,7 @@
 <struts-config>
   <!-- Generated from /WEB-INF/.tmpbeansrc/PF_CatchExceptionHandler/Controller.java on Tue Aug 09 16:46:02 MDT 2005 -->
   <form-beans>
-    <form-bean name="formOne" type="PF_CatchExceptionHandler.Controller$FormOne"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="formOne" type="PF_CatchExceptionHandler.Controller$FormOne"/>
   </form-beans>
   <global-exceptions>
     <exception className="org.apache.beehive.netui.pageflow.config.PageFlowExceptionConfig" handler="exceptionHandler" key="java.lang.Throwable" type="java.lang.Throwable">

Modified: beehive/trunk/netui/test/src/compilerTests/testsuite/PF_DeprecatedExceptionHandler/expectedOutput/struts-config-PF_DeprecatedExceptionHandler.expected
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/src/compilerTests/testsuite/PF_DeprecatedExceptionHandler/expectedOutput/struts-config-PF_DeprecatedExceptionHandler.expected?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/test/src/compilerTests/testsuite/PF_DeprecatedExceptionHandler/expectedOutput/struts-config-PF_DeprecatedExceptionHandler.expected (original)
+++ beehive/trunk/netui/test/src/compilerTests/testsuite/PF_DeprecatedExceptionHandler/expectedOutput/struts-config-PF_DeprecatedExceptionHandler.expected Wed Oct 12 14:37:36 2005
@@ -3,7 +3,7 @@
 <struts-config>
   <!-- Generated from /WEB-INF/.tmpbeansrc/PF_DeprecatedExceptionHandler/Controller.java on Tue Aug 09 16:46:04 MDT 2005 -->
   <form-beans>
-    <form-bean name="formOne" type="PF_DeprecatedExceptionHandler.Controller$FormOne"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="formOne" type="PF_DeprecatedExceptionHandler.Controller$FormOne"/>
   </form-beans>
   <global-exceptions>
     <exception className="org.apache.beehive.netui.pageflow.config.PageFlowExceptionConfig" handler="exceptionHandler" key="java.lang.Throwable" type="java.lang.Throwable">

Modified: beehive/trunk/netui/test/src/compilerTests/testsuite/simpleActionReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleActionReadOnlyUseFormBeanWarning.expected
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/src/compilerTests/testsuite/simpleActionReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleActionReadOnlyUseFormBeanWarning.expected?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/test/src/compilerTests/testsuite/simpleActionReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleActionReadOnlyUseFormBeanWarning.expected (original)
+++ beehive/trunk/netui/test/src/compilerTests/testsuite/simpleActionReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleActionReadOnlyUseFormBeanWarning.expected Wed Oct 12 14:37:36 2005
@@ -3,7 +3,7 @@
 <struts-config>
   <!-- Generated from /WEB-INF/.tmpbeansrc/simpleActionReadOnlyUseFormBeanWarning/Warning.java on Tue Aug 09 16:47:19 MDT 2005 -->
   <form-beans>
-    <form-bean name="newFormBean" type="simpleActionReadOnlyUseFormBeanWarning.Warning$NewFormBean"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="newFormBean" type="simpleActionReadOnlyUseFormBeanWarning.Warning$NewFormBean"/>
   </form-beans>
   <global-exceptions/>
   <global-forwards>

Modified: beehive/trunk/netui/test/src/compilerTests/testsuite/simpleReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleReadOnlyUseFormBeanWarning.expected
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/src/compilerTests/testsuite/simpleReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleReadOnlyUseFormBeanWarning.expected?rev=315054&r1=315053&r2=315054&view=diff
==============================================================================
--- beehive/trunk/netui/test/src/compilerTests/testsuite/simpleReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleReadOnlyUseFormBeanWarning.expected (original)
+++ beehive/trunk/netui/test/src/compilerTests/testsuite/simpleReadOnlyUseFormBeanWarning/expectedOutput/struts-config-simpleReadOnlyUseFormBeanWarning.expected Wed Oct 12 14:37:36 2005
@@ -3,8 +3,8 @@
 <struts-config>
   <!-- Generated from /WEB-INF/.tmpbeansrc/simpleReadOnlyUseFormBeanWarning/readOnlyController.java on Tue Aug 09 16:47:30 MDT 2005 -->
   <form-beans>
-    <form-bean name="simpleBean_nonFlowScoped" type="simpleReadOnlyUseFormBeanWarning.readOnlyController$SimpleBean"/>
-    <form-bean name="simpleBean" type="simpleReadOnlyUseFormBeanWarning.readOnlyController$SimpleBean"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="simpleBean_nonFlowScoped" type="simpleReadOnlyUseFormBeanWarning.readOnlyController$SimpleBean"/>
+    <form-bean className="org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean" name="simpleBean" type="simpleReadOnlyUseFormBeanWarning.readOnlyController$SimpleBean"/>
   </form-beans>
   <global-exceptions/>
   <global-forwards>