You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/08/08 05:19:09 UTC

svn commit: r683820 - /incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/

Author: ajaquith
Date: Thu Aug  7 20:19:09 2008
New Revision: 683820

URL: http://svn.apache.org/viewvc?rev=683820&view=rev
Log:
Beginning of Stripes JSP-tier refactoring.

Added:
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractUserProfileActionBean.java
Modified:
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractActionBean.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/EditActionBean.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerInfo.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/LoginActionBean.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/MessageActionBean.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/UserProfileActionBean.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/ViewActionBean.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiActionBeanFactory.java
    incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiInterceptor.java

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractActionBean.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractActionBean.java Thu Aug  7 20:19:09 2008
@@ -13,16 +13,18 @@
 import com.ecyrd.jspwiki.preferences.Preferences;
 
 /**
- * <p>Abstract ActionBean superclass for all wiki actions, such as page actions ({@link com.ecyrd.jspwiki.WikiContext} and subclasses),
- * group actions (e.g., {@link ViewGroupActionBean}), user actions (e.g., {@link UserPreferencesActionBean}) and others.</p>
- * 
+ * <p>
+ * Abstract ActionBean superclass for all wiki actions, such as page actions ({@link com.ecyrd.jspwiki.WikiContext}
+ * and subclasses), group actions (e.g., {@link ViewGroupActionBean}), user
+ * actions (e.g., {@link UserPreferencesActionBean}) and others.
+ * </p>
  * 
  * @author Andrew Jaquith
  */
 public abstract class AbstractActionBean implements WikiActionBean
 {
-    protected  Map<String,Object> m_variableMap = new HashMap<String,Object>();
-    
+    protected Map<String, Object> m_variableMap = new HashMap<String, Object>();
+
     private WikiActionBeanContext m_actionBeanContext = null;
 
     /**
@@ -31,9 +33,9 @@
     private String m_skin = null;
 
     private String m_template = null;
-    
+
     private static final String DEFAULT_TEMPLATE = "default";
-    
+
     /**
      * Creates a new instance of this class, without a WikiEngine, Request or
      * WikiPage.
@@ -44,18 +46,9 @@
     }
 
     /**
-     * Returns the content template for this ActionBean.
-     * TODO: make final at some point
-     */
-    public String getContentTemplate()
-    {
-        return this.getClass().getAnnotation(WikiRequestContext.class).value();
-    }
-
-    /**
      * Returns the Stripes ActionBeanContext associated this WikiContext. This
-     * method may return <code>null</code>, and callers should check for
-     * this condition.
+     * method may return <code>null</code>, and callers should check for this
+     * condition.
      * 
      * @throws IllegalStateException
      */
@@ -73,7 +66,7 @@
      */
     public Principal getCurrentUser()
     {
-        if ( getWikiSession() == null )
+        if( getWikiSession() == null )
         {
             // This shouldn't happen, really...
             return WikiPrincipal.GUEST;
@@ -93,29 +86,32 @@
     }
 
     /**
-     * Returns the request context for this ActionBean by looking up the 
-     * value of the annotation {@link WikiRequestContext} associated with the current event handler
-     * method for this ActionBean. The current event handler is obtained from {@link WikiActionBeanContext#getEventName()}.
-     * Note that if this ActionBean does not have a a current event handler assigned, or if the event handler method
-     * does not contain the WikiRequestContext annotation, this method will return {@link ecyrd.jspwiki.WikiContext#NONE}.
+     * Returns the request context for this ActionBean by looking up the value
+     * of the annotation {@link WikiRequestContext} associated with the current
+     * event handler method for this ActionBean. The current event handler is
+     * obtained from {@link WikiActionBeanContext#getEventName()}. Note that if
+     * this ActionBean does not have a a current event handler assigned, or if
+     * the event handler method does not contain the WikiRequestContext
+     * annotation, this method will return
+     * {@link ecyrd.jspwiki.WikiContext#NONE}.
      */
     public String getRequestContext()
     {
         WikiActionBeanContext wac = getContext();
-        if ( wac == null )
+        if( wac == null )
         {
             return "none";
         }
 
         String eventName = wac.getEventName();
-        if ( eventName == null )
+        if( eventName == null )
         {
             return "none";
         }
-        
+
         return HandlerInfo.getHandlerInfo( this.getClass(), eventName ).getRequestContext();
     }
-    
+
     /**
      * Returns the "skin" to be used for this ActionBean.
      * 
@@ -146,15 +142,15 @@
      */
     public String getTemplate()
     {
-        if ( m_skin != null ) 
+        if( m_skin != null )
         {
             return m_skin;
         }
-        else if ( m_template != null )
+        else if( m_template != null )
         {
             return m_template;
         }
-        else if ( getEngine() != null ) 
+        else if( getEngine() != null )
         {
             return getEngine().getTemplateDir();
         }
@@ -173,10 +169,10 @@
     }
 
     /**
-     *  Gets a previously set variable.
-     *
-     *  @param key The variable name.
-     *  @return The variable contents.
+     * Gets a previously set variable.
+     * 
+     * @param key The variable name.
+     * @return The variable contents.
      */
     public Object getVariable( String key )
     {
@@ -184,12 +180,12 @@
     }
 
     /**
-     *  Sets a variable.  The variable is valid while the WikiContext is valid,
-     *  i.e. while page processing continues.  The variable data is discarded
-     *  once the page processing is finished.
-     *
-     *  @param key The variable name.
-     *  @param data The variable value.
+     * Sets a variable. The variable is valid while the WikiContext is valid,
+     * i.e. while page processing continues. The variable data is discarded once
+     * the page processing is finished.
+     * 
+     * @param key The variable name.
+     * @param data The variable value.
      */
     public void setVariable( String key, Object data )
     {
@@ -200,7 +196,7 @@
      * Sets the Stripes ActionBeanContext associated with this WikiContext. It
      * will also update the cached HttpRequest.
      */
-    public void setContext(ActionBeanContext context)
+    public void setContext( ActionBeanContext context )
     {
         m_actionBeanContext = ((WikiActionBeanContext) context);
     }
@@ -210,10 +206,9 @@
      * the template returned by {@link #getTemplate()}. Normally, this method
      * is invoked by Stripes when binding request parameters to the ActionBean.
      * 
-     * @param skin
-     *            the skin to use
+     * @param skin the skin to use
      */
-    public void setSkin(String skin)
+    public void setSkin( String skin )
     {
         m_skin = skin;
     }
@@ -223,21 +218,22 @@
      * 
      * @since 2.1.15.
      */
-    public void setTemplate(String dir)
+    public void setTemplate( String dir )
     {
         m_template = dir;
     }
-    
+
     /**
-     *  Locates the i18n ResourceBundle given.  This method interprets
-     *  the request locale, and uses that to figure out which language the
-     *  user wants.
-     *  @see com.ecyrd.jspwiki.i18n.InternationalizationManager
-     *  @param bundle The name of the bundle you are looking for.
-     *  @return A resource bundle object
-     *  @throws MissingResourceException If the bundle cannot be found
+     * Locates the i18n ResourceBundle given. This method interprets the request
+     * locale, and uses that to figure out which language the user wants.
+     * 
+     * @see com.ecyrd.jspwiki.i18n.InternationalizationManager
+     * @param bundle The name of the bundle you are looking for.
+     * @return A resource bundle object
+     * @throws MissingResourceException If the bundle cannot be found
      */
-    // FIXME: This method should really cache the ResourceBundles or something...
+    // FIXME: This method should really cache the ResourceBundles or
+    // something...
     public ResourceBundle getBundle( String bundle ) throws MissingResourceException
     {
         Locale loc = Preferences.getLocale( this );
@@ -246,23 +242,26 @@
         {
             loc = m_actionBeanContext.getRequest().getLocale();
         }
-        ResourceBundle b = getEngine().getInternationalizationManager().getBundle(bundle, loc);
-                
+        ResourceBundle b = getEngine().getInternationalizationManager().getBundle( bundle, loc );
+
         return b;
     }
-    
-    // ------------------------------------ Deprecated methods we are reluctantly pulling up from WikiContext
-    
-    /**
-     *  If the request did originate from a HTTP request,
-     *  then the HTTP request can be fetched here.  However, it the request
-     *  did NOT originate from a HTTP request, then this method will
-     *  return null, and YOU SHOULD CHECK FOR IT!
-     *
-     *  @return Null, if no HTTP request was done.
-     *  @deprecated use the method {@link #getContext()} to obtain the ActionBeanContext,
-     *  and call {@link com.ecyrd.jspwiki.action.WikiActionBeanContext#getRequest()} method.
-     *  @since 2.0.13.
+
+    // ------------------------------------ Deprecated methods we are
+    // reluctantly pulling up from WikiContext
+
+    /**
+     * If the request did originate from a HTTP request, then the HTTP request
+     * can be fetched here. However, it the request did NOT originate from a
+     * HTTP request, then this method will return null, and YOU SHOULD CHECK FOR
+     * IT!
+     * 
+     * @return Null, if no HTTP request was done.
+     * @deprecated use the method {@link #getContext()} to obtain the
+     *             ActionBeanContext, and call
+     *             {@link com.ecyrd.jspwiki.action.WikiActionBeanContext#getRequest()}
+     *             method.
+     * @since 2.0.13.
      */
     public HttpServletRequest getHttpRequest()
     {
@@ -270,15 +269,14 @@
     }
 
     /**
-     *  This method will safely return any HTTP parameters that 
-     *  might have been defined.  You should use this method instead
-     *  of peeking directly into the result of getHttpRequest(), since
-     *  this method is smart enough to do all of the right things,
-     *  figure out UTF-8 encoded parameters, etc.
-     *
-     *  @since 2.0.13.
-     *  @param paramName Parameter name to look for.
-     *  @return HTTP parameter, or null, if no such parameter existed.
+     * This method will safely return any HTTP parameters that might have been
+     * defined. You should use this method instead of peeking directly into the
+     * result of getHttpRequest(), since this method is smart enough to do all
+     * of the right things, figure out UTF-8 encoded parameters, etc.
+     * 
+     * @since 2.0.13.
+     * @param paramName Parameter name to look for.
+     * @return HTTP parameter, or null, if no such parameter existed.
      */
     public String getHttpParameter( String paramName )
     {
@@ -292,12 +290,6 @@
         return result;
     }
 
-    public String getJSP()
-    {
-        // TODO: should calculate the JSP based on the WikiURLPattern annotation
-        return null;
-    }
-
     /**
      * Sets the request context. See above for the different request contexts
      * (VIEW, EDIT, etc.) This argument must correspond exactly to the value of
@@ -311,14 +303,15 @@
      * documentation for more details.
      * 
      * @param arg The request context (one of the predefined contexts.)
-     * @throws IllegalArgumentException if the supplied request context does not correspond
-     * to a {@linkplain com.ecyrd.jspwiki.action.WikiRequestContext}
-     * annotation, or the automatically request context name
+     * @throws IllegalArgumentException if the supplied request context does not
+     *             correspond to a
+     *             {@linkplain com.ecyrd.jspwiki.action.WikiRequestContext}
+     *             annotation, or the automatically request context name
      */
     public void setRequestContext( String arg )
     {
         HandlerInfo handler = HandlerInfo.getHandlerInfo( this.getClass(), arg );
-        if ( getContext() == null )
+        if( getContext() == null )
         {
             throw new IllegalStateException( "WikiActionBean did not set a WikiActionBeanContext!" );
         }

Added: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractUserProfileActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractUserProfileActionBean.java?rev=683820&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractUserProfileActionBean.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AbstractUserProfileActionBean.java Thu Aug  7 20:19:09 2008
@@ -0,0 +1,181 @@
+package com.ecyrd.jspwiki.action;
+
+import net.sourceforge.stripes.action.Before;
+import net.sourceforge.stripes.action.HandlesEvent;
+import net.sourceforge.stripes.action.Resolution;
+import net.sourceforge.stripes.controller.LifecycleStage;
+import net.sourceforge.stripes.validation.*;
+
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.WikiSession;
+import com.ecyrd.jspwiki.auth.AuthenticationManager;
+import com.ecyrd.jspwiki.auth.NoSuchPrincipalException;
+import com.ecyrd.jspwiki.auth.UserManager;
+import com.ecyrd.jspwiki.auth.permissions.WikiPermission;
+import com.ecyrd.jspwiki.auth.user.UserDatabase;
+import com.ecyrd.jspwiki.auth.user.UserProfile;
+
+/**
+ * <p>
+ * Abstract WikiActionBean that provides the scaffolding needed to create and
+ * validate a user profile. Subclasses {@link LoginActionBean} and
+ * {@link UserProfileActionBean} rely on the fields and event handlers in this
+ * class. This abstract class contains no handler methods; subclasses must
+ * implement them.
+ * </p>
+ * 
+ * @author Andrew Jaquith
+ */
+public abstract class AbstractUserProfileActionBean extends AbstractActionBean
+{
+    protected UserProfile m_profile = null;
+
+    protected String m_passwordAgain = null;
+
+    public String getPasswordAgain()
+    {
+        return m_passwordAgain;
+    }
+
+    public UserProfile getProfile()
+    {
+        return m_profile;
+    }
+
+    /**
+     * Pre-action that loads the UserProfile before user-supplied parameters are
+     * bound to the ActionBean.
+     * 
+     * @return <code>null</code>, always
+     */
+    @Before( stages = LifecycleStage.BindingAndValidation )
+    public Resolution initUserProfile()
+    {
+        // Retrieve the user profile
+        WikiEngine engine = getEngine();
+        WikiSession session = getWikiSession();
+        UserManager manager = engine.getUserManager();
+        m_profile = manager.getUserProfile( session );
+
+        // Null out the password, so that we don't re-encrypt it by accident
+        m_profile.setPassword( null );
+        return null;
+    }
+
+    public void setPasswordAgain( String password )
+    {
+        m_passwordAgain = password;
+    }
+
+    @ValidateNestedProperties( { @Validate( field = "loginName", required = true, maxlength = 100 ),
+                                @Validate( field = "fullname", required = true, maxlength = 100 ),
+                                @Validate( field = "password", required = false, minlength = 8, maxlength = 100 ),
+                                @Validate( field = "email", required = false, converter = EmailTypeConverter.class ) } )
+    public void setProfile( UserProfile profile )
+    {
+        m_profile = profile;
+    }
+
+    /**
+     * Abstract "save profile" methods that subclasses must implement.
+     * @return
+     */
+    @HandlesEvent( "saveProfile" )
+    @HandlerPermission( permissionClass = WikiPermission.class, target = "${engine.applicationName}", actions = WikiPermission.EDIT_PROFILE_ACTION )
+    public abstract Resolution save();
+    
+    /**
+     * After all fields validate correctly, this method verifies that the user
+     * has the correct permissions to save the UserProfile, and checks that the
+     * supplied full name or login name don't collide with those used by
+     * somebody else.
+     * 
+     * @param errors the current validation errors for this ActionBean
+     */
+    @ValidationMethod( on="saveProfile",  when = ValidationState.NO_ERRORS )
+    public void validateNoCollision( ValidationErrors errors )
+    {
+        WikiEngine engine = getEngine();
+        WikiSession session = getWikiSession();
+        UserManager manager = getEngine().getUserManager();
+        UserDatabase database = manager.getUserDatabase();
+
+        // Locate the old user profile
+        UserProfile oldProfile = manager.getUserProfile( session );
+
+        // If container authenticated, override the login name and password
+        // The login name should always be the one provided by the container
+        AuthenticationManager authMgr = engine.getAuthenticationManager();
+        if( authMgr.isContainerAuthenticated() )
+        {
+            m_profile.setLoginName( oldProfile.getLoginName() );
+            m_profile.setPassword( null );
+        }
+
+        // User profiles that may already have fullname or loginname
+        UserProfile otherProfile;
+        try
+        {
+            otherProfile = database.findByLoginName( m_profile.getLoginName() );
+            if( otherProfile != null && !otherProfile.equals( oldProfile ) )
+            {
+                errors.add( "profile.loginName", new LocalizableError( "nameCollision" ) );
+            }
+        }
+        catch( NoSuchPrincipalException e )
+        {
+        }
+        try
+        {
+            otherProfile = database.findByFullName( m_profile.getFullname() );
+            if( otherProfile != null && !otherProfile.equals( oldProfile ) )
+            {
+                errors.add( "profile.fullname", new LocalizableError( "nameCollision" ) );
+            }
+        }
+        catch( NoSuchPrincipalException e )
+        {
+        }
+    }
+
+    /**
+     * After all fields validate correctly, this method validates that the user
+     * account is not spam.
+     * 
+     * @param errors the current validation errors for this ActionBean
+     */
+    @ValidationMethod( on="saveProfile", when = ValidationState.NO_ERRORS )
+    public void validateNotSpam( ValidationErrors errors )
+    {
+        // TODO: code this up!
+    }
+
+    /**
+     * If the user profile is new, this method verifies that the user has
+     * supplied matching passwords.
+     * 
+     * @param errors the current validation errors for this ActionBean
+     */
+    @ValidationMethod( on="saveProfile", when = ValidationState.ALWAYS )
+    public void validatePasswords( ValidationErrors errors )
+    {
+        // All new profiles must have a supplied password
+        if( m_profile.isNew() )
+        {
+            if( m_profile.getPassword() == null )
+            {
+                errors.add( "profile.password", new ScopedLocalizableError( "validation.required", "valueNotPresent" ) );
+            }
+        }
+
+        // If a password was supplied, the same value must also have been passed
+        // to passwordAgain
+        if( m_profile.getPassword() != null )
+        {
+            if( !m_profile.getPassword().equals( m_passwordAgain ) )
+            {
+                errors.add( "profile.password", new ScopedLocalizableError( "validation.required", "noPasswordMatch" ) );
+            }
+        }
+    }
+}

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/EditActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/EditActionBean.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/EditActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/EditActionBean.java Thu Aug  7 20:19:09 2008
@@ -10,7 +10,7 @@
 {
     @DefaultHandler
     @HandlesEvent("edit")
-    @HandlerPermission(permissionClass=PagePermission.class, target="${page.name}", actions=PagePermission.EDIT_ACTION)
+    @HandlerPermission(permissionClass=PagePermission.class, target="${page.qualifiedName}", actions=PagePermission.EDIT_ACTION)
     @WikiRequestContext("edit")
     public Resolution edit()
     {
@@ -23,7 +23,7 @@
      * @return a forward resolution back to the preview page.
      */
     @HandlesEvent( "preview" )
-    @HandlerPermission( permissionClass = PagePermission.class, target = "${page.name}", actions = PagePermission.VIEW_ACTION )
+    @HandlerPermission( permissionClass = PagePermission.class, target = "${page.qualifiedName}", actions = PagePermission.VIEW_ACTION )
     @WikiRequestContext( "preview" )
     public Resolution preview()
     {
@@ -37,7 +37,7 @@
      */
     @WikiRequestContext("diff")
     @HandlesEvent("diff")
-    @HandlerPermission(permissionClass=PagePermission.class, target="${page.name}", actions=PagePermission.VIEW_ACTION)
+    @HandlerPermission(permissionClass=PagePermission.class, target="${page.qualifiedName}", actions=PagePermission.VIEW_ACTION)
     public Resolution diff()
     {
         return new ForwardResolution( "/Diff.jsp" );

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerInfo.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerInfo.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerInfo.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerInfo.java Thu Aug  7 20:19:09 2008
@@ -323,6 +323,8 @@
      * Returns the Permission required to execute the method in the context of the supplied
      * WikiActionBean, based on its {@link HandlerPermission} annotation.
      * Any EL expressions found in the annotated target or actions are evaluated.
+     * Note that this method returns <code>null</code> if no Permission is required
+     * to execute this method, and <em>callers should check for nulls</code>.
      * 
      * @param actionBean the ActionBean that will be used as the base for any EL
      *            expressions
@@ -332,6 +334,11 @@
      */
     public Permission getPermission( WikiActionBean actionBean ) throws ELException
     {
+        if ( m_permissionClass == null )
+        {
+            return null;
+        }
+        
         // Get the target class, target and actions
         boolean hasOneParameter = m_permissionActions == null;
         String target = m_permissionTarget;

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/LoginActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/LoginActionBean.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/LoginActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/LoginActionBean.java Thu Aug  7 20:19:09 2008
@@ -1,29 +1,271 @@
 package com.ecyrd.jspwiki.action;
 
-import net.sourceforge.stripes.action.DefaultHandler;
-import net.sourceforge.stripes.action.HandlesEvent;
-import net.sourceforge.stripes.action.Resolution;
-import net.sourceforge.stripes.action.UrlBinding;
+import java.security.Principal;
+import java.util.ResourceBundle;
 
+import javax.servlet.http.HttpSession;
+
+import net.sourceforge.stripes.action.*;
+import net.sourceforge.stripes.util.UrlBuilder;
+import net.sourceforge.stripes.validation.LocalizableError;
+import net.sourceforge.stripes.validation.SimpleError;
+import net.sourceforge.stripes.validation.ValidationErrors;
+
+import org.apache.log4j.Logger;
+
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.WikiSession;
+import com.ecyrd.jspwiki.auth.WikiSecurityException;
+import com.ecyrd.jspwiki.auth.login.CookieAssertionLoginModule;
+import com.ecyrd.jspwiki.auth.login.CookieAuthenticationLoginModule;
 import com.ecyrd.jspwiki.auth.permissions.WikiPermission;
+import com.ecyrd.jspwiki.workflow.DecisionRequiredException;
 
-@UrlBinding("/Login.jsp")
-public class LoginActionBean extends AbstractActionBean
+@UrlBinding( "/Login.jsp" )
+public class LoginActionBean extends AbstractUserProfileActionBean
 {
-    @DefaultHandler
-    @HandlesEvent("login")
-    @HandlerPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.LOGIN_ACTION)
-    @WikiRequestContext("login")
+    private String m_redirect = null;
+
+    private String m_username = null;
+
+    private boolean m_remember = false;
+
+    private String m_password;
+
+    private static final Logger log = Logger.getLogger( LoginActionBean.class );
+
+    public String getJ_userName()
+    {
+        return m_username;
+    }
+
+    public String getJ_password()
+    {
+        return m_password;
+    }
+
+    public void setJ_username( String username )
+    {
+        m_username = username;
+    }
+
+    public void setJ_password( String password )
+    {
+        m_password = password;
+    }
+
+    public void setJ_remember( boolean remember )
+    {
+        m_remember = remember;
+    }
+
+    public boolean getJ_remember()
+    {
+        return m_remember;
+    }
+
+    public String getRedirect()
+    {
+        return m_redirect;
+    }
+
+    @HandlesEvent( "login" )
+    @HandlerPermission( permissionClass = WikiPermission.class, target = "${engine.applicationName}", actions = WikiPermission.LOGIN_ACTION )
     public Resolution login()
     {
-        return null;
+        WikiSession wikiSession = this.getWikiSession();
+
+        // If user got here and is already authenticated, it means
+        // they just aren't allowed access to what they asked for.
+        // Weepy tears and hankies all 'round.
+        if( getWikiSession().isAuthenticated() )
+        {
+            ResourceBundle rb = getBundle( "CoreResources" );
+            String message = rb.getString( "login.error.noaccess" );
+            getContext().getValidationErrors().addGlobalError( new SimpleError( message ) );
+            return new RedirectResolution( MessageActionBean.class ).flash( this );
+        }
+
+        log.debug( "Attempting to authenticate user " + m_username );
+
+        // Log the user in!
+        Resolution r = null;
+        ValidationErrors errors = getContext().getValidationErrors();
+        try
+        {
+            if( getEngine().getAuthenticationManager().login( wikiSession, m_username, m_password ) )
+            {
+                // Set cookies as needed and redirect
+                log.info( "Successfully authenticated user " + m_username + " (custom auth)" );
+                r = redirectToOriginalPage();
+            }
+            else
+            {
+                log.info( "Failed to authenticate user " + m_username );
+                errors.addGlobalError( new SimpleError( "login.error.password" ) );
+
+            }
+        }
+        catch( WikiSecurityException e )
+        {
+            errors.addGlobalError( new SimpleError( "login.error", e.getMessage() ) );
+        }
+
+        // Any errors?
+        if( !errors.isEmpty() )
+        {
+            UrlBuilder builder = new UrlBuilder( getContext().getLocale(), LoginActionBean.class, false );
+            builder.addParameter( "tab", "logincontent" );
+            r = new RedirectResolution( builder.toString() );
+        }
+
+        return r;
     }
 
-    @HandlesEvent("logout")
-    @HandlerPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.LOGIN_ACTION)
-    @WikiRequestContext("logout")
+    @HandlesEvent( "logout" )
+    @HandlerPermission( permissionClass = WikiPermission.class, target = "${engine.applicationName}", actions = WikiPermission.LOGIN_ACTION )
+    @WikiRequestContext( "logout" )
     public Resolution logout()
     {
         return null;
     }
+
+    public void setRedirect( String redirect )
+    {
+        m_redirect = redirect;
+        setVariable( "redirect", redirect );
+    }
+
+    /**
+     * Attempts to save the user profile, after all other validation routines
+     * have executed. If the save executes without error, this method will
+     * return <code>null</code>. Otherwise, any error conditions will return
+     * a non-null Resolution. For example, if an approval is required to save
+     * the profile, a RedirectResolution redirecting the user to the
+     * <code>ApprovalRequiredForUserProfiles</code> will be returned. Other
+     * validation errors will cause redirection back to the profile tab.
+     * 
+     * @return
+     */
+    @HandlesEvent( "saveProfile" )
+    @HandlerPermission( permissionClass = WikiPermission.class, target = "${engine.applicationName}", actions = WikiPermission.EDIT_PROFILE_ACTION )
+    public Resolution save()
+    {
+        WikiActionBeanContext context = getContext();
+        Resolution r = null;
+        try
+        {
+            // Save the profile
+            WikiEngine engine = getEngine();
+            engine.getUserManager().setUserProfile( getWikiSession(), m_profile );
+            CookieAssertionLoginModule.setUserCookie( context.getResponse(), m_profile.getFullname() );
+        }
+
+        // Not so fast my friend! Approvals are required...
+        catch( DecisionRequiredException e )
+        {
+            UrlBuilder builder = new UrlBuilder( this.getContext().getLocale(), ViewActionBean.class, false );
+            builder.addParameter( "page", "ApprovalRequiredForUserProfiles" );
+            r = new RedirectResolution( builder.toString() );
+        }
+
+        // Any other errors are either UI or config problems, so let the user
+        // know about them
+        catch( Exception e )
+        {
+            ValidationErrors errors = context.getValidationErrors();
+            errors.addGlobalError( new LocalizableError( "saveError", e.getMessage() ) );
+            UrlBuilder builder = new UrlBuilder( this.getContext().getLocale(), LoginActionBean.class, false );
+            builder.addParameter( "tab", "profile" );
+            r = new RedirectResolution( builder.toString() );
+        }
+
+        // Set cookies as needed and redirect
+        r = redirectToOriginalPage();
+
+        return r;
+    }
+
+    /**
+     * Executes after a successful profile creation or login
+     */
+    private Resolution redirectToOriginalPage()
+    {
+        // Set user cookie
+        Principal principal = getWikiSession().getUserPrincipal();
+        CookieAssertionLoginModule.setUserCookie( getContext().getResponse(), principal.getName() );
+
+        // Set "remember me?" cookie
+        if( m_remember )
+        {
+            CookieAuthenticationLoginModule.setLoginCookie( getEngine(), getContext().getResponse(), principal.getName() );
+        }
+
+        Resolution r = null;
+        if( m_redirect != null )
+        {
+            UrlBuilder builder = new UrlBuilder( this.getContext().getLocale(), ViewActionBean.class, false );
+            builder.addParameter( "page", m_redirect );
+            r = new RedirectResolution( builder.toString() );
+        }
+        return r;
+    }
+
+    /**
+     * Default handler that executes when the login page is viewed. It checks to
+     * see if the user is already authenticated, and if so, sents a "forbidden"
+     * message.
+     * 
+     * @return the resolution
+     */
+    @DefaultHandler
+    @HandlesEvent( "view" )
+    @HandlerPermission( permissionClass = WikiPermission.class, target = "${engine.applicationName}", actions = WikiPermission.LOGIN_ACTION )
+    @WikiRequestContext( "login" )
+    public Resolution view()
+    {
+        Resolution r = null;
+
+        if( getWikiSession().isAuthenticated() )
+        {
+            // Set cookies as needed and redirect
+            r = redirectToOriginalPage();
+            if( r == null )
+            {
+                r = new RedirectResolution( ViewActionBean.class );
+            }
+        }
+
+        if( getEngine().getAuthenticationManager().isContainerAuthenticated() )
+        {
+            //
+            // Have we already been submitted? If yes, then we can assume that
+            // we have been logged in before.
+            //
+            
+            HttpSession session = getContext().getRequest().getSession();
+            Object seen = session.getAttribute( "_redirect" );
+            if( seen != null )
+            {
+                ResourceBundle rb = getBundle( "CoreResources" );
+                String message = rb.getString( "login.error.noaccess" );
+                getContext().getValidationErrors().addGlobalError( new SimpleError( message ) );
+                return new RedirectResolution( MessageActionBean.class ).flash( this );
+            }
+            session.setAttribute( "_redirect", "I love Outi" ); // Just any
+                                                                // marker will
+                                                                // do
+
+            // If using container auth, the container will have automatically
+            // attempted to log in the user before Login.jsp was loaded.
+            // Thus, if we got here, the container must have authenticated
+            // the user already. All we do is simply record that fact.
+            // Nice and easy.
+
+            Principal user = getWikiSession().getLoginPrincipal();
+            log.info( "Successfully authenticated user " + user.getName() + " (container auth)" );
+        }
+
+        return r;
+    }
 }

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/MessageActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/MessageActionBean.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/MessageActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/MessageActionBean.java Thu Aug  7 20:19:09 2008
@@ -2,18 +2,32 @@
 
 import net.sourceforge.stripes.action.*;
 
-@UrlBinding("/Message.jsp")
+@UrlBinding( "/Message.jsp" )
 public class MessageActionBean extends AbstractActionBean
 {
+    private String m_message = null;
+
     /**
      * Default event that forwards control to /Message.jsp.
+     * 
      * @return the forward resolution
      */
     @DefaultHandler
-    @HandlesEvent("message")
-    @WikiRequestContext("message")
-    public Resolution view() {
+    @HandlesEvent( "message" )
+    @WikiRequestContext( "message" )
+    public Resolution view()
+    {
         return new ForwardResolution( "/Message.jsp" );
     }
 
+    public String getMessage()
+    {
+        return m_message;
+    }
+
+    public void setMessage( String message )
+    {
+        m_message = message;
+    }
+
 }

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/UserProfileActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/UserProfileActionBean.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/UserProfileActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/UserProfileActionBean.java Thu Aug  7 20:19:09 2008
@@ -1,214 +1,78 @@
 package com.ecyrd.jspwiki.action;
 
 import net.sourceforge.stripes.action.*;
-import net.sourceforge.stripes.controller.LifecycleStage;
-import net.sourceforge.stripes.validation.*;
+import net.sourceforge.stripes.util.UrlBuilder;
+import net.sourceforge.stripes.validation.LocalizableError;
+import net.sourceforge.stripes.validation.ValidationErrors;
 
 import com.ecyrd.jspwiki.WikiEngine;
-import com.ecyrd.jspwiki.WikiSession;
-import com.ecyrd.jspwiki.auth.AuthenticationManager;
-import com.ecyrd.jspwiki.auth.NoSuchPrincipalException;
-import com.ecyrd.jspwiki.auth.UserManager;
 import com.ecyrd.jspwiki.auth.login.CookieAssertionLoginModule;
 import com.ecyrd.jspwiki.auth.permissions.WikiPermission;
-import com.ecyrd.jspwiki.auth.user.UserDatabase;
-import com.ecyrd.jspwiki.auth.user.UserProfile;
+import com.ecyrd.jspwiki.workflow.DecisionRequiredException;
 
 /**
  * @author Andrew Jaquith
  */
-@UrlBinding("/UserProfile.jsp")
-public class UserProfileActionBean extends AbstractActionBean
+@UrlBinding( "/UserProfile.jsp" )
+public class UserProfileActionBean extends AbstractUserProfileActionBean
 {
-    private UserProfile m_profile = null;
-    private String m_passwordAgain = null;
-
-    public String getPasswordAgain()
-    {
-        return m_passwordAgain;
-    }
-    
-    public UserProfile getProfile() 
-    {
-        return m_profile;
-    }
-    
-    /**
-     * Before user-supplied parameters are bound to the ActionBean, this method loads the
-     * UserProfile.
-     * @return <code>null</code>, always
-     */
-    @Before(stages=LifecycleStage.BindingAndValidation)
-    public Resolution init()
-    {
-        // Retrieve the user profile
-        WikiEngine engine = getEngine();
-        WikiSession session = getWikiSession();
-        UserManager manager = engine.getUserManager();
-        m_profile = manager.getUserProfile(session);
-        
-        // Null out the password, so that we don't re-encrypt it by accident
-        m_profile.setPassword( null );
-        return null;
-    }
 
     /**
-     * Saves the user profile to the wiki's UserDatabase.
-     * 
-     * @return a {@link net.sourceforge.stripes.action.ForwardResolution} back
-     *         to itself if the save activity returned errors, or
-     *         <code>null</code> otherwise
+     * Attempts to save the user profile, after all other validation routines have executed.
+     * If the save executes without error, this method will return <code>null</code>.
+     * Otherwise, any error conditions will return a non-null Resolution.
+     * For example, if an approval is required to save the profile, a RedirectResolution
+     * redirecting the user to the <code>ApprovalRequiredForUserProfiles</code>
+     * will be returned. Other validation errors will cause redirection back to the profile tab.
+     * @return
      */
-    @HandlesEvent("save")
-    @HandlerPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.EDIT_PROFILE_ACTION)
+    @HandlesEvent( "saveProfile" )
+    @HandlerPermission( permissionClass = WikiPermission.class, target = "${engine.applicationName}", actions = WikiPermission.EDIT_PROFILE_ACTION )
     public Resolution save()
     {
-        Resolution r = null;
         WikiActionBeanContext context = getContext();
+        Resolution r = null;
         try
         {
             // Save the profile
             WikiEngine engine = getEngine();
             engine.getUserManager().setUserProfile( getWikiSession(), m_profile);
             CookieAssertionLoginModule.setUserCookie(context.getResponse(), m_profile.getFullname());
-            r = new RedirectResolution("/");
         }
+        
+        // Not so fast my friend! Approvals are required...
+        catch( DecisionRequiredException e )
+        {
+            UrlBuilder builder = new UrlBuilder( this.getContext().getLocale(), ViewActionBean.class, false );
+            builder.addParameter( "page", "ApprovalRequiredForUserProfiles" );
+            r = new RedirectResolution( builder.toString() );
+        }
+        
+        // Any other errors are either UI or config problems, so let the user know about them
         catch (Exception e)
         {
             ValidationErrors errors = context.getValidationErrors();
             errors.addGlobalError( new LocalizableError( "saveError", e.getMessage() ) );
-            r = new ForwardResolution(UserProfileActionBean.class);
-        }
-        return r;
-    }
-
-    /**
-     * <p>
-     * Default handler method that views the user's profile. This method 
-     * loads the current user's UserProfile and sets the
-     * ActionBean's e-mail and fullName properties. It will override
-     * user-supplied values that should not change, namely the
-     * <code>loginName</code> and <code>password</code> fields
-     * if AuthenticationManager is using container-managed authentication
-     * and accounts aren't shared with JSPWiki. It will also
-     * set the <code>e-mail</code> field if a value was not supplied by the
-     * user as a request parameter. If a profile does not already exist, 
-     * this method does nothing, with
-     * the caveat that if the user is authenticated via the container, the
-     * container identifer (the value returned by the <code>getRemoteUser</code>
-     * or the <code>getUserPrincipal</code>).
-     * </p>
-     */
-
-    public void setPasswordAgain(String password)
-    {
-        m_passwordAgain = password;
-    }
-    
-    @ValidateNestedProperties( {
-                               @Validate(field="loginName", required=true, maxlength=100), 
-                               @Validate(field="fullname", required=true, maxlength=100),
-                               @Validate(field="password", required = false, minlength = 8, maxlength = 100),
-                               @Validate(field="email", required = false, converter = EmailTypeConverter.class) } )
-    public void setProfile(UserProfile profile)
-    {
-        m_profile = profile;
-    }
-    
-    /**
-     * If the user profile is new, this method verifies that the user
-     * has supplied matching passwords.
-     * @param errors
-     *            the current validation errors for this ActionBean
-     */
-    @ValidationMethod(when = ValidationState.ALWAYS)
-    public void validatePasswords(ValidationErrors errors)
-    {
-        // All new profiles must have a supplied password
-        if ( m_profile.isNew() )
-        {
-            if ( m_profile.getPassword() == null )
-            {
-                errors.add( "profile.password", new ScopedLocalizableError( "validation.required", "valueNotPresent" ) );
-            }
+            UrlBuilder builder = new UrlBuilder( this.getContext().getLocale(), UserProfileActionBean.class, false );
+            builder.addParameter( "tab", "profile" );
+            r = new RedirectResolution( builder.toString() );
         }
         
-        // If a password was supplied, the same value must also have been passed to passwordAgain
-        if ( m_profile.getPassword() != null )
-        {
-            if ( !m_profile.getPassword().equals( m_passwordAgain ) )
-            {
-                errors.add( "profile.password", new ScopedLocalizableError( "validation.required", "noPasswordMatch" ) );
-            }
-        }
+        // The save executed correctly and without errors, so return nothing
+        return r;
     }
 
-
-    /**
-     * After all fields validate correctly, this method verifies that the user
-     * has the correct permissions to save the UserProfile, and checks that the
-     * supplied full name or login name don't collide with those used by
-     * somebody else.
-     * 
-     * @param errors
-     *            the current validation errors for this ActionBean
-     */
-    @ValidationMethod(when = ValidationState.NO_ERRORS)
-    public void validateNoCollision(ValidationErrors errors)
-    {
-        WikiEngine engine = getEngine();
-        WikiSession session = getWikiSession();
-        UserManager manager = getEngine().getUserManager();
-        UserDatabase database = manager.getUserDatabase();
-
-        // Locate the old user profile
-        UserProfile oldProfile = manager.getUserProfile( session );
-
-        // If container authenticated, override the login name and password
-        // The login name should always be the one provided by the container
-        AuthenticationManager authMgr = engine.getAuthenticationManager();
-        if ( authMgr.isContainerAuthenticated() )
-        {
-            m_profile.setLoginName( oldProfile.getLoginName() );
-            m_profile.setPassword( null );
-        }
-        
-        // User profiles that may already have fullname or loginname
-        UserProfile otherProfile;
-        try
-        {
-            otherProfile = database.findByLoginName( m_profile.getLoginName() );
-            if ( otherProfile != null && !otherProfile.equals( oldProfile ) )
-            {
-                errors.add("profile.loginName", new LocalizableError( "nameCollision" ) );
-            }
-        }
-        catch (NoSuchPrincipalException e)
-        {
-        }
-        try
-        {
-            otherProfile = database.findByFullName( m_profile.getFullname() );
-            if (otherProfile != null && !otherProfile.equals(oldProfile))
-            {
-                errors.add("profile.fullname", new LocalizableError( "nameCollision" ) );
-            }
-        }
-        catch (NoSuchPrincipalException e)
-        {
-        }
-    }
-    
     /**
      * Default handler that forwards the user back to itself.
+     * 
      * @return the resolution
      */
-    @HandlesEvent("view")
+    @HandlesEvent( "view" )
     @DefaultHandler
-    @WikiRequestContext("profile")
+    @WikiRequestContext( "profile" )
     public Resolution view()
     {
-        return new ForwardResolution(ViewActionBean.class);
+        return new ForwardResolution( ViewActionBean.class );
     }
-    
+
 }

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/ViewActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/ViewActionBean.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/ViewActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/ViewActionBean.java Thu Aug  7 20:19:09 2008
@@ -134,7 +134,7 @@
      */
     @DefaultHandler
     @HandlesEvent("view")
-    @HandlerPermission(permissionClass=PagePermission.class, target="${page.name}", actions=PagePermission.VIEW_ACTION)
+    @HandlerPermission(permissionClass=PagePermission.class, target="${page.qualifiedName}", actions=PagePermission.VIEW_ACTION)
     @WikiRequestContext("view")
     public Resolution view()
     {

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiActionBeanFactory.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiActionBeanFactory.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiActionBeanFactory.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiActionBeanFactory.java Thu Aug  7 20:19:09 2008
@@ -9,7 +9,6 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.servlet.jsp.PageContext;
 
 import net.sourceforge.stripes.action.RedirectResolution;
 import net.sourceforge.stripes.mock.MockHttpServletRequest;
@@ -20,6 +19,7 @@
 import org.apache.log4j.Logger;
 
 import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.auth.SessionMonitor;
 import com.ecyrd.jspwiki.parser.MarkupParser;
 import com.ecyrd.jspwiki.providers.ProviderException;
 import com.ecyrd.jspwiki.tags.WikiTagBase;
@@ -65,6 +65,24 @@
  */
 public final class WikiActionBeanFactory
 {
+    /**
+     * The PageContext attribute name of the WikiActionBean stored by
+     * WikiInterceptor.
+     */
+    public static final String ATTR_ACTIONBEAN = "wikiActionBean";
+
+    /**
+     * The PageContext attribute name of the WikiEngine stored by
+     * WikiInterceptor.
+     */
+    public static final String ATTR_WIKIENGINE = "wikiEngine";
+
+    /**
+     * The PageContext attribute name of the WikiSession stored by
+     * WikiInterceptor.
+     */
+    public static final String ATTR_WIKISESSION = "wikiSession";
+    
     private static final Logger log = Logger.getLogger( WikiActionBeanFactory.class );
 
     private static final long serialVersionUID = 1L;
@@ -586,13 +604,13 @@
      */
     public static WikiActionBean findActionBean( ServletRequest request )
     {
-        return (WikiActionBean) request.getAttribute( WikiInterceptor.ATTR_ACTIONBEAN );
+        return (WikiActionBean) request.getAttribute( ATTR_ACTIONBEAN );
     }
 
     /**
      * <p>
      * Saves the supplied WikiActionBean and its associated WikiPage as
-     * PageContext attributes, in request scope. The action bean is saved as an
+     * in request scope. The action bean is saved as an
      * attribute named {@link WikiInterceptor#ATTR_ACTIONBEAN}. If the action
      * bean was also a WikiContext instance, it is saved as an attribute named
      * {@link com.ecyrd.jspwiki.tags.WikiTagBase#ATTR_CONTEXT}. Among other
@@ -609,14 +627,22 @@
      * and that page will be used.
      * </p>
      * 
-     * @param pageContext the page context
+     * @param request the HTTP request
      * @param actionBean the WikiActionBean to save
      */
-    public static void saveActionBean( PageContext pageContext, WikiActionBean actionBean )
+    public static void saveActionBean( HttpServletRequest request, WikiActionBean actionBean )
     {
-        // Stash the WikiActionBean
+        // Stash WikiEngine as a request attribute (can be
+        // used later as ${wikiEngine} in EL markup)
         WikiEngine engine = actionBean.getEngine();
-        pageContext.setAttribute( WikiInterceptor.ATTR_ACTIONBEAN, actionBean, PageContext.REQUEST_SCOPE );
+        request.setAttribute( ATTR_WIKIENGINE, engine );
+        
+        // Stash the WikiSession as a request attribute
+        WikiSession wikiSession = SessionMonitor.getInstance( engine ).find( request.getSession() );
+        request.setAttribute( ATTR_WIKISESSION, wikiSession );
+        
+        // Stash the WikiActionBean
+        request.setAttribute( ATTR_ACTIONBEAN, actionBean );
 
         // Stash it again as a WikiContext (or synthesize a fake one)
         WikiContext wikiContext;
@@ -640,12 +666,11 @@
         }
         else
         {
-            HttpServletRequest request = actionBean.getContext().getRequest();
             HttpServletResponse response = actionBean.getContext().getResponse();
             page = engine.getPage( engine.getFrontPage() );
             wikiContext = engine.getWikiActionBeanFactory().newViewActionBean( request, response, page );
         }
-        pageContext.setAttribute( WikiTagBase.ATTR_CONTEXT, actionBean, PageContext.REQUEST_SCOPE );
+        request.setAttribute( WikiTagBase.ATTR_CONTEXT, wikiContext );
 
         // Debug messages
         if( log.isDebugEnabled() )

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiInterceptor.java?rev=683820&r1=683819&r2=683820&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiInterceptor.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/WikiInterceptor.java Thu Aug  7 20:19:09 2008
@@ -9,24 +9,30 @@
 
 import net.sourceforge.stripes.action.RedirectResolution;
 import net.sourceforge.stripes.action.Resolution;
-import net.sourceforge.stripes.controller.*;
+import net.sourceforge.stripes.controller.ExecutionContext;
+import net.sourceforge.stripes.controller.Interceptor;
+import net.sourceforge.stripes.controller.Intercepts;
+import net.sourceforge.stripes.controller.LifecycleStage;
 
 import org.apache.log4j.Logger;
 
 import com.ecyrd.jspwiki.WikiEngine;
 import com.ecyrd.jspwiki.WikiSession;
 import com.ecyrd.jspwiki.auth.AuthorizationManager;
-import com.ecyrd.jspwiki.auth.SessionMonitor;
 
 /**
  * <p>
  * Stripes {@link net.sourceforge.stripes.controller.Interceptor} that
  * instantiates the correct WikiContext associated with JSPs, checks for access,
- * and redirects users if necessary. The interceptor executes after the second
- * lifecycle stage, <em>aka</em>
- * {@link net.sourceforge.stripes.controller.LifecycleStage#HandlerResolution},
+ * and redirects users if necessary. The interceptor executes twice: the first
+ * time is after the first lifecycle state, <em>aka</em>
+ * {@link  net.sourceforge.stripes.controller.LifecycleStage#ActionBeanResolution}
+ * but before the second stage.
+ * {@link net.sourceforge.stripes.controller.LifecycleStage#HandlerResolution}.
+ * The second time the interceptor executes is after the second lifecycle stage,
  * but before the third stage,
  * {@link net.sourceforge.stripes.controller.LifecycleStage#BindingAndValidation}.
+ * See the
  * </p>
  * <p>
  * WikiInterceptor assumes primary responsibility for making JSPWiki objects
@@ -47,8 +53,8 @@
  * <p>
  * After the intercept method fires, calling classes can obtain the saved
  * WikiActionBean by calling
- * {@link WikiActionBeanFactory#findActionBean(javax.servlet.ServletRequest)}. This is
- * the recommended method that  JSP scriptlet code should use.
+ * {@link WikiActionBeanFactory#findActionBean(javax.servlet.ServletRequest)}.
+ * This is the recommended method that JSP scriptlet code should use.
  * </p>
  * <p>
  * Because these objects are saved as attributes, they are available to JSPs as
@@ -59,28 +65,78 @@
  * 
  * @author Andrew Jaquith
  */
-@Intercepts( { LifecycleStage.HandlerResolution } )
+@Intercepts( { LifecycleStage.ActionBeanResolution, LifecycleStage.BindingAndValidation } )
 public class WikiInterceptor implements Interceptor
 {
-    /**
-     * The PageContext attribute name of the WikiActionBean stored by
-     * WikiInterceptor.
-     */
-    public static final String ATTR_ACTIONBEAN = "wikiActionBean";
+    private static final Logger log = Logger.getLogger( WikiInterceptor.class );
 
     /**
-     * The PageContext attribute name of the WikiEngine stored by
-     * WikiInterceptor.
+     * Intercepts the Stripes lifecycle stages and dispatches execution to
+     * delegate methods {@link #interceptActionBeanResolution(ExecutionContext)}
+     * and {@link #interceptBindingAndValidation(ExecutionContext)}, whichever
+     * is appropriate.
+     * 
+     * @param context the current execution context
+     * @return a Resolution if the
+     *         {@link net.sourceforge.stripes.controller.LifecycleStage#HandlerResolution}
+     *         lifecycle stage's normal execution returns one; <code>null</code>
+     *         otherwise
+     * @throws Exception if the underlying lifcycle stage's execution throws an
+     *             Exception
      */
-    public static final String ATTR_WIKIENGINE = "wikiEngine";
+    public Resolution intercept( ExecutionContext context ) throws Exception
+    {
+        if( LifecycleStage.ActionBeanResolution.equals( context.getLifecycleStage() ) )
+        {
+            return interceptActionBeanResolution( context );
+        }
+        else if( LifecycleStage.BindingAndValidation.equals( context.getLifecycleStage() ) )
+        {
+            return interceptBindingAndValidation( context );
+        }
+        return null;
+    }
 
     /**
-     * The PageContext attribute name of the WikiSession stored by
-     * WikiInterceptor.
+     * After the Stripes
+     * {@link net.sourceforge.stripes.controller.LifecycleStage#ActionBeanResolution}
+     * executes, this method injects the current WikiEngine, WikiSession and
+     * WikiActionBean into request scope, and returns <code>null</code>.
+     * After the objects are injected, downstream classes like WikiTagBase can
+     * use them. The attribute can also be accessed as variables using the JSP
+     * Expression Language (example: <code>${wikiPage}</code>).
+     * 
+     * @param context the execution context
+     * @return a Resolution if the
+     *         {@link net.sourceforge.stripes.controller.LifecycleStage#ActionBeanResolution}
+     *         lifecycle stage's normal execution returns one; <code>null</code>
+     *         otherwise
+     * @throws Exception if the underlying lifcycle stage's execution throws an
+     *             Exception
      */
-    public static final String ATTR_WIKISESSION = "wikiSession";
+    protected Resolution interceptActionBeanResolution( ExecutionContext context ) throws Exception
+    {
+        // Did the handler resolution stage return a Resolution? If so, bail.
+        Resolution r = context.proceed();
+        if( r != null )
+        {
+            return r;
+        }
 
-    private static final Logger log = Logger.getLogger( WikiInterceptor.class );
+        WikiActionBean actionBean = (WikiActionBean) context.getActionBean();
+        WikiActionBeanContext beanContext = actionBean.getContext();
+        HttpServletRequest httpRequest = beanContext.getRequest();
+
+        // Stash the WikiActionBean and WikiPage in the request
+        WikiActionBeanFactory.saveActionBean( httpRequest, actionBean );
+
+        if( log.isDebugEnabled() )
+        {
+            log.debug( "WikiInterceptor resolved ActionBean: " + actionBean );
+        }
+
+        return null;
+    }
 
     /**
      * <p>
@@ -102,23 +158,16 @@
      * returns <code>false</code> -- this method returns a RedirectResolution
      * to the login page, with all current parameters appended.
      * </p>
-     * <p>
-     * If access is allowed, this method injects the WikiEngine, WikiSession,
-     * resolved WikiActionBean and WikiPage as request-scoped PageContext
-     * attributes, and returns a <code>null</code>. After the objects are
-     * injected, downstream classes like WikiTagBase can use them. The attribute
-     * can also be accessed as variables using the JSP Expression Language
-     * (example: <code>${wikiPage}</code>).
      * 
-     * @param context the current execution context
+     * @param context the execution context
      * @return a Resolution if the
-     *         {@link net.sourceforge.stripes.controller.LifecycleStage#HandlerResolution}
+     *         {@link net.sourceforge.stripes.controller.LifecycleStage#BindingAndValidation}
      *         lifecycle stage's normal execution returns one; <code>null</code>
      *         otherwise
      * @throws Exception if the underlying lifcycle stage's execution throws an
      *             Exception
      */
-    public Resolution intercept( ExecutionContext context ) throws Exception
+    protected Resolution interceptBindingAndValidation( ExecutionContext context ) throws Exception
     {
         // Did the handler resolution stage return a Resolution? If so, bail.
         Resolution r = context.proceed();
@@ -129,7 +178,6 @@
 
         // Get the resolved ActionBean and event handler method
         WikiActionBean actionBean = (WikiActionBean) context.getActionBean();
-        WikiActionBeanContext beanContext = actionBean.getContext();
         Method handler = context.getHandler();
 
         // Does the event handler have a required permission?
@@ -156,43 +204,12 @@
             ((RedirectResolution) r).includeRequestParameters( true );
             if( log.isDebugEnabled() )
             {
-                log.debug( "WikiInterceptor rejected access to ActionBean=" + actionBean.getClass().getCanonicalName() + ", method=" + handler.getName() );
+                log.debug( "WikiInterceptor rejected access to ActionBean=" + actionBean.getClass().getCanonicalName()
+                           + ", method=" + handler.getName() );
             }
             return r;
         }
 
-        if( log.isDebugEnabled() )
-        {
-            log.debug( "WikiInterceptor resolved ActionBean: " + actionBean );
-        }
-
-        // If not already set, inject WikiEngine as a request attribute (can be
-        // used later as ${wikiEngine} in EL markup)
-        WikiEngine engine = beanContext.getWikiEngine();
-        HttpServletRequest httpRequest = beanContext.getRequest();
-        httpRequest.setAttribute( ATTR_WIKIENGINE, engine );
-
-        // If not already set, Inject the WikiSession as a request attribute
-        WikiSession wikiSession = SessionMonitor.getInstance( engine ).find( httpRequest.getSession() );
-        httpRequest.setAttribute( ATTR_WIKISESSION, wikiSession );
-
-        // Stash the WikiActionBean and WikiPage in the PageContext
-        // Note: it probably seems a bit tricky that we're grabbing the
-        // PageContext from Stripes. We happen
-        // to know, thanks to the glories of open source code, that Stripes
-        // calls DispatcherHelper's
-        // setPageContext() method immediately before executing the
-        // BindingAndValidation stage,
-        // in *both* the <stripes:useActionBean> case and the StripesFilter
-        // case.
-        // So, the PageContext safe to grab, and boy are we glad that we can!
-        PageContext pageContext = DispatcherHelper.getPageContext();
-        if( pageContext != null )
-        {
-            // Save ActionBean to the current context
-            WikiActionBeanFactory.saveActionBean( pageContext, actionBean );
-        }
-
         return null;
     }