incubator-jspwiki-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ajaqu...@apache.org
Subject svn commit: r682139 [4/6] - in /incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki: ./ action/
Date Sun, 03 Aug 2008 12:12:49 GMT
Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/WikiSession.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/WikiSession.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/WikiSession.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/WikiSession.java Sun Aug  3 05:12:47 2008
@@ -1,21 +1,22 @@
 /*
     JSPWiki - a JSP-based WikiWiki clone.
 
-    Copyright (C) 2001-2005 The JSPWiki Development Group
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU Lesser General Public License as published by
-    the Free Software Foundation; either version 2.1 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Lesser General Public License for more details.
-
-    You should have received a copy of the GNU Lesser General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.  
  */
 package com.ecyrd.jspwiki;
 
@@ -25,9 +26,6 @@
 import java.util.*;
 
 import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
@@ -37,8 +35,6 @@
 import com.ecyrd.jspwiki.auth.authorize.Group;
 import com.ecyrd.jspwiki.auth.authorize.GroupManager;
 import com.ecyrd.jspwiki.auth.authorize.Role;
-import com.ecyrd.jspwiki.auth.login.CookieAssertionLoginModule;
-import com.ecyrd.jspwiki.auth.login.PrincipalWrapper;
 import com.ecyrd.jspwiki.auth.user.UserDatabase;
 import com.ecyrd.jspwiki.auth.user.UserProfile;
 import com.ecyrd.jspwiki.event.WikiEvent;
@@ -110,17 +106,11 @@
 
     private static final String ALL                   = "*";
 
-    private static ThreadLocal<WikiSession> c_guestSession  = new ThreadLocal<WikiSession>();
+    private static ThreadLocal<WikiSession> c_guestSession = new ThreadLocal<WikiSession>();
 
     private final Subject       m_subject             = new Subject();
 
-    private final Map<String,Set<String>> m_messages = new HashMap<String,Set<String>>();
-
-    private String              m_cachedCookieIdentity= null;
-
-    private String              m_cachedRemoteUser    = null;
-
-    private Principal           m_cachedUserPrincipal = null;
+    private final Map<String,Set<String>> m_messages  = new HashMap<String,Set<String>>();
 
     /** The WikiEngine that created this session. */
     private WikiEngine          m_engine              = null;
@@ -142,10 +132,9 @@
      */
     protected final boolean isInGroup( Group group )
     {
-        Principal[] principals = getPrincipals();
-        for ( int i = 0; i < principals.length; i++ )
+        for ( Principal principal : getPrincipals() )
         {
-          if ( isAuthenticated() && group.isMember( principals[i] ) )
+          if ( isAuthenticated() && group.isMember( principal ) )
           {
               return true;
           }
@@ -218,27 +207,13 @@
      */
     public final boolean isAnonymous()
     {
-        Set principals = m_subject.getPrincipals();
+        Set<Principal> principals = m_subject.getPrincipals();
         return principals.contains( Role.ANONYMOUS ) ||
                  principals.contains( WikiPrincipal.GUEST ) ||
                  isIPV4Address( getUserPrincipal().getName() );
     }
 
     /**
-     * Creates and returns a new login context for this wiki session.
-     * This method is called by
-     * {@link com.ecyrd.jspwiki.auth.AuthenticationManager}.
-     * @param application the name of the application
-     * @param handler the callback handler
-     * @return A new login context
-     * @throws LoginException If the login context cannot be created
-     */
-    public final LoginContext getLoginContext( String application, CallbackHandler handler ) throws LoginException
-    {
-        return new LoginContext( application, m_subject, handler );
-    }
-
-    /**
      * <p> Returns the Principal used to log in to an authenticated session. The
      * login principal is determined by examining the Subject's Principal set
      * for PrincipalWrappers or WikiPrincipals with type designator
@@ -252,10 +227,6 @@
      */
     public final Principal getLoginPrincipal()
     {
-        if ( m_loginPrincipal instanceof PrincipalWrapper )
-        {
-            return ((PrincipalWrapper)m_loginPrincipal).getPrincipal();
-        }
         return m_loginPrincipal;
     }
 
@@ -274,10 +245,6 @@
      */
     public final Principal getUserPrincipal()
     {
-        if ( m_loginPrincipal instanceof PrincipalWrapper )
-        {
-            return ((PrincipalWrapper)m_userPrincipal).getPrincipal();
-        }
         return m_userPrincipal;
     }
 
@@ -360,7 +327,7 @@
      * Returns all generic messages associated with this session.
      * The messages stored with the session persist throughout the
      * session unless they have been reset with {@link #clearMessages()}.
-     * @return the current messsages.
+     * @return the current messages.
      */
     public final String[] getMessages()
     {
@@ -371,7 +338,7 @@
      * Returns all messages associated with a session topic.
      * The messages stored with the session persist throughout the
      * session unless they have been reset with {@link #clearMessages(String)}.
-     * @return the current messsages.
+     * @return the current messages.
      * @param topic The topic
      */
     public final String[] getMessages( String topic )
@@ -393,16 +360,16 @@
      */
     public final Principal[] getPrincipals()
     {
-        List<Principal> principals = new ArrayList<Principal>();
+        ArrayList<Principal> principals = new ArrayList<Principal>();
 
         // Take the first non Role as the main Principal
         for( Principal principal : m_subject.getPrincipals() )
         {
-        	if ( AuthenticationManager.isUserPrincipal( principal ) )
+            if ( AuthenticationManager.isUserPrincipal( principal ) )
             {
-            	principals.add( principal );
-			}
-		}
+                principals.add( principal );
+            }
+        }
 
         return principals.toArray( new Principal[principals.size()] );
     }
@@ -507,10 +474,35 @@
                     }
                     case WikiSecurityEvent.LOGIN_INITIATED:
                     {
+                        // Do nothing
+                    }
+                    case WikiSecurityEvent.PRINCIPAL_ADD:
+                    {
+                        WikiSession target = (WikiSession)e.getTarget();
+                        if ( this.equals( target ) && m_status == AUTHENTICATED )
+                        {
+                            Set<Principal> principals = m_subject.getPrincipals();
+                            principals.add( (Principal)e.getPrincipal());
+                        }
+                        break;
+                    }
+                    case WikiSecurityEvent.LOGIN_ANONYMOUS:
+                    {
                         WikiSession target = (WikiSession)e.getTarget();
                         if ( this.equals( target ) )
                         {
-                            updatePrincipals();
+                            m_status = ANONYMOUS;
+                            
+                            // Set the login/user principals and login status
+                            Set<Principal> principals = m_subject.getPrincipals();
+                            m_loginPrincipal = (Principal)e.getPrincipal();
+                            m_userPrincipal = m_loginPrincipal;
+                            
+                            // Add the login principal to the Subject, and set the built-in roles
+                            principals.clear();
+                            principals.add( m_loginPrincipal );
+                            principals.add( Role.ALL );
+                            principals.add( Role.ANONYMOUS );
                         }
                         break;
                     }
@@ -520,6 +512,17 @@
                         if ( this.equals( target ) )
                         {
                             m_status = ASSERTED;
+                            
+                            // Set the login/user principals and login status
+                            Set<Principal> principals = m_subject.getPrincipals();
+                            m_loginPrincipal = (Principal)e.getPrincipal();
+                            m_userPrincipal = m_loginPrincipal;
+                            
+                            // Add the login principal to the Subject, and set the built-in roles
+                            principals.clear();
+                            principals.add( m_loginPrincipal );
+                            principals.add( Role.ALL );
+                            principals.add( Role.ASSERTED );
                         }
                         break;
                     }
@@ -529,9 +532,21 @@
                         if ( this.equals( target ) )
                         {
                             m_status = AUTHENTICATED;
+                            
+                            // Set the login/user principals and login status
+                            Set<Principal> principals = m_subject.getPrincipals();
+                            m_loginPrincipal = (Principal)e.getPrincipal();
+                            m_userPrincipal = m_loginPrincipal;
+                            
+                            // Add the login principal to the Subject, and set the built-in roles
+                            principals.clear();
+                            principals.add( m_loginPrincipal );
+                            principals.add( Role.ALL );
+                            principals.add( Role.AUTHENTICATED );
+                            
+                            // Add the user and group principals
                             injectUserProfilePrincipals();  // Add principals for the user profile
-                            injectRolePrincipals();  // Inject role and group principals
-                            updatePrincipals();
+                            injectGroupPrincipals();  // Inject group principals
                         }
                         break;
                     }
@@ -541,7 +556,7 @@
                         if ( this.equals( source ) )
                         {
                             injectUserProfilePrincipals();  // Add principals for the user profile
-                            updatePrincipals();
+                            injectGroupPrincipals();  // Inject group principals
                         }
                         break;
                     }
@@ -549,7 +564,7 @@
                     {
                         // Refresh user principals based on new user profile
                         WikiSession source = (WikiSession)e.getSource();
-                        if ( this.equals( source ) )
+                        if ( this.equals( source ) && m_status == AUTHENTICATED )
                         {
                             // To prepare for refresh, set the new full name as the primary principal
                             UserProfile[] profiles = (UserProfile[])e.getTarget();
@@ -558,11 +573,19 @@
                             {
                                 throw new IllegalStateException( "User profile FullName cannot be null." );
                             }
-                            m_userPrincipal = new WikiPrincipal( newProfile.getFullname() );
-
-                            // Refresh principals for the user profile
-                            injectUserProfilePrincipals();
-                            updatePrincipals();
+                            
+                            Set<Principal> principals = m_subject.getPrincipals();
+                            m_loginPrincipal = new WikiPrincipal( newProfile.getLoginName() );
+                            
+                            // Add the login principal to the Subject, and set the built-in roles
+                            principals.clear();
+                            principals.add( m_loginPrincipal );
+                            principals.add( Role.ALL );
+                            principals.add( Role.AUTHENTICATED );
+                            
+                            // Add the user and group principals
+                            injectUserProfilePrincipals();  // Add principals for the user profile
+                            injectGroupPrincipals();  // Inject group principals
                         }
                         break;
                     }
@@ -587,116 +610,35 @@
         m_subject.getPrincipals().add( WikiPrincipal.GUEST );
         m_subject.getPrincipals().add( Role.ANONYMOUS );
         m_subject.getPrincipals().add( Role.ALL );
-        m_cachedCookieIdentity = null;
-        m_cachedRemoteUser = null;
-        m_cachedUserPrincipal = null;
     }
 
     /**
-     * Returns whether the HTTP servlet container's authentication status has
-     * changed. Used to detect whether the container has logged in a user since
-     * the last call to this function. This method is stateful. After calling
-     * this function, the cached values are set to those in the current request.
-     * If the servlet request is <code>null</code>, this method always returns
-     * <code>false</code>. Note that once a user authenticates, the container
-     * status for the session will <em>never</em> change again, unless the
-     * session is invalidated by timeout or logout.
-     * @param request the servlet request
-     * @return <code>true</code> if the status has changed, <code>false</code>
-     * otherwise
-     */
-    protected final boolean isContainerStatusChanged( HttpServletRequest request )
-    {
-        if ( request == null || m_status.equals( AUTHENTICATED ) )
-        {
-            return false;
-        }
-
-        String remoteUser = request.getRemoteUser();
-        Principal userPrincipal = request.getUserPrincipal();
-        String cookieIdentity = CookieAssertionLoginModule.getUserCookie( request );
-        boolean changed = false;
-
-        // If request contains non-null remote user, update cached value if changed
-        if ( remoteUser != null && !remoteUser.equals( m_cachedRemoteUser) )
-        {
-            m_cachedRemoteUser = remoteUser;
-            log.info( "Remote user changed to " + remoteUser );
-            changed = true;
-        }
-
-        // If request contains non-null user principal, updated cached value if changed
-        if ( userPrincipal != null && !userPrincipal.equals( m_cachedUserPrincipal ) )
-        {
-            m_cachedUserPrincipal = userPrincipal;
-            log.info( "User principal changed to " + userPrincipal.getName() );
-            changed = true;
-        }
-
-        // If cookie identity changed (to a different value or back to null), update cache
-        if ( ( cookieIdentity != null && !cookieIdentity.equals( m_cachedCookieIdentity ) )
-               || ( cookieIdentity == null && m_cachedCookieIdentity != null ) )
-        {
-            m_cachedCookieIdentity = cookieIdentity;
-            log.info( "Cookie changed to " + cookieIdentity );
-            changed = true;
-        }
-        return changed;
-    }
-
-    /**
-     * Injects GroupPrincipal and Role objects into the user's Principal set
-     * based on the groups and roles the user belongs to.
-     * For Roles, the algorithm first calls the
-     * {@link Authorizer#getRoles()} to obtain the array of
-     * Principals the authorizer knows about. Then, the method
-     * {@link Authorizer#isUserInRole(WikiSession, Principal)} is
-     * called for each Principal. If the user possesses the role,
-     * an equivalent role Principal is injected into the user's
-     * principal set.
-     * Reloads user Principals into the suppplied WikiSession's Subject.
-     * Existing Role principals are preserved; all other Principal
-     * types are flushed and replaced by those returned by
-     * {@link com.ecyrd.jspwiki.auth.user.UserDatabase#getPrincipals(String)}.
-     * This method should generally be called after a user's {@link com.ecyrd.jspwiki.auth.user.UserProfile}
-     * is saved. If the wiki session is null, or there is no matching user profile, the
-     * method returns silently.
-     */
-    protected final void injectRolePrincipals()
-    {
+     * Injects GroupPrincipal objects into the user's Principal set based on the
+     * groups the user belongs to. For Groups, the algorithm first calls the
+     * {@link GroupManager#getRoles()} to obtain the array of GroupPrincipals
+     * the authorizer knows about. Then, the method
+     * {@link GroupManager#isUserInRole(WikiSession, Principal)} is called for
+     * each Principal. If the user is a member of the group, an equivalent
+     * GroupPrincipal is injected into the user's principal set. Existing
+     * GroupPrincipals are flushed and replaced. This method should generally be
+     * called after a user's {@link com.ecyrd.jspwiki.auth.user.UserProfile} is
+     * saved. If the wiki session is null, or there is no matching user profile,
+     * the method returns silently.
+     */
+    protected final void injectGroupPrincipals()
+    {
+        // Flush the existing GroupPrincipals
+        m_subject.getPrincipals().removeAll( m_subject.getPrincipals(GroupPrincipal.class) );
+        
         // Get the GroupManager and test for each Group
         GroupManager manager = m_engine.getGroupManager();
-        Principal[] groups = manager.getRoles();
-        for ( int i = 0; i < groups.length; i++ )
+        for ( Principal group : manager.getRoles() )
         {
-            if ( manager.isUserInRole( this, groups[i] ) )
+            if ( manager.isUserInRole( this, group ) )
             {
-                m_subject.getPrincipals().add( groups[i] );
+                m_subject.getPrincipals().add( group );
             }
         }
-
-        // Get the authorizer's known roles, then test for each
-        try
-        {
-            Authorizer authorizer = m_engine.getAuthorizationManager().getAuthorizer();
-            Principal[] roles = authorizer.getRoles();
-            for ( int i = 0; i < roles.length; i++ )
-            {
-                Principal role = roles[i];
-                if ( authorizer.isUserInRole( this, role ) )
-                {
-                    String roleName = role.getName();
-                    if ( !Role.isReservedName( roleName ) )
-                    {
-                        m_subject.getPrincipals().add( new Role( roleName ) );
-                    }
-                }
-            }
-        }
-        catch ( WikiException e )
-        {
-            log.error( "Could not refresh role principals: " + e.getMessage() );
-        }
     }
 
     /**
@@ -708,17 +650,8 @@
      */
     protected final void injectUserProfilePrincipals()
     {
-        // Copy all Role and GroupPrincipal principals into a temporary cache
-        Set<Principal> oldPrincipals = m_subject.getPrincipals();
-        Set<Principal> newPrincipals = new HashSet<Principal>();
-        for ( Principal principal : oldPrincipals )
-        {
-            if ( AuthenticationManager.isRolePrincipal( principal ) )
-            {
-                newPrincipals.add( principal );
-            }
-        }
-        String searchId = getUserPrincipal().getName();
+        // Search for the user profile
+        String searchId = m_loginPrincipal.getName();
         if ( searchId == null )
         {
             // Oh dear, this wasn't an authenticated user after all
@@ -736,106 +669,28 @@
         {
             UserProfile profile = database.find( searchId );
             Principal[] principals = database.getPrincipals( profile.getLoginName() );
-            for (int i = 0; i < principals.length; i++)
+            for ( Principal principal : principals )
             {
-                Principal principal = principals[i];
-                newPrincipals.add( principal );
-            }
-
-            // Replace the Subject's old Principals with the new ones
-            oldPrincipals.clear();
-            oldPrincipals.addAll( newPrincipals );
-        }
-        catch ( NoSuchPrincipalException e )
-        {
-            // We will get here if the user has a principal but not a profile
-            // For example, it's a container-managed user who hasn't set up a profile yet
-            log.warn("User profile '" + searchId + "' not found. This is normal for container-auth users who haven't set up a profile yet.");
-        }
-    }
-
-    /**
-     * Updates the internally cached principals returned by {@link #getUserPrincipal()} and
-     * {@link #getLoginPrincipal()}. This method is called when the WikiSession receives
-     * the {@link com.ecyrd.jspwiki.event.WikiSecurityEvent#LOGIN_INITIATED} message.
-     */
-    protected final void updatePrincipals()
-    {
-        Set<Principal> principals = m_subject.getPrincipals();
-        m_loginPrincipal = null;
-        m_userPrincipal = null;
-        Principal wikinamePrincipal = null;
-        Principal fullnamePrincipal = null;
-        Principal otherPrincipal = null;
-
-        for( Principal currentPrincipal : principals )
-        {
-            if ( !( currentPrincipal instanceof Role || currentPrincipal instanceof GroupPrincipal ) )
-            {
-                // For login principal, take the first PrincipalWrapper or WikiPrincipal of type LOGIN_NAME
-                // For user principal take the  first WikiPrincipal of type WIKI_NAME
-                if ( currentPrincipal instanceof PrincipalWrapper )
-                {
-                    m_loginPrincipal = currentPrincipal;
-                }
-                else if ( currentPrincipal instanceof WikiPrincipal )
+                // Add the Principal to the Subject
+                m_subject.getPrincipals().add( principal );
+                
+                // Set the user principal if needed; we prefer FullName, but the WikiName will also work
+                boolean isFullNamePrincipal = ( principal instanceof WikiPrincipal && ((WikiPrincipal)principal).getType() == WikiPrincipal.FULL_NAME );
+                if ( isFullNamePrincipal )
                 {
-                    WikiPrincipal wp = (WikiPrincipal) currentPrincipal;
-                    if ( wp.getType().equals( WikiPrincipal.LOGIN_NAME ) )
-                    {
-                        m_loginPrincipal = wp;
-                    }
-                    else if ( wp.getType().equals( WikiPrincipal.WIKI_NAME ) )
-                    {
-                        wikinamePrincipal = currentPrincipal;
-                        m_userPrincipal = wp;
-                    }
-                    else if ( wp.getType().equals( WikiPrincipal.FULL_NAME ) )
-                    {
-                        fullnamePrincipal = currentPrincipal;
-                    }
-                    else
-                    {
-                        otherPrincipal = currentPrincipal;
-                    }
+                   m_userPrincipal = principal; 
                 }
-                else if ( otherPrincipal == null )
+                else if ( !( m_userPrincipal instanceof WikiPrincipal ) )
                 {
-                    otherPrincipal = currentPrincipal;
+                    m_userPrincipal = principal; 
                 }
             }
         }
-        if ( otherPrincipal == null )
-        {
-            otherPrincipal = WikiPrincipal.GUEST;
-        }
-
-        // If no login principal, use wiki name, full name or other principal (in that order)
-        if ( m_loginPrincipal == null )
-        {
-            m_loginPrincipal = wikinamePrincipal;
-            if ( m_loginPrincipal == null )
-            {
-                m_loginPrincipal = fullnamePrincipal;
-                if ( m_loginPrincipal == null )
-                {
-                    m_loginPrincipal = otherPrincipal;
-                }
-            }
-        }
-
-        // If no user principal, use wiki name, full name or login principal (in that order)
-        if ( m_userPrincipal == null )
+        catch ( NoSuchPrincipalException e )
         {
-            m_userPrincipal = wikinamePrincipal;
-            if ( m_userPrincipal == null )
-            {
-                m_userPrincipal = fullnamePrincipal;
-                if ( m_userPrincipal == null )
-                {
-                    m_userPrincipal = m_loginPrincipal;
-                }
-            }
+            // We will get here if the user has a principal but not a profile
+            // For example, it's a container-managed user who hasn't set up a profile yet
+            log.warn("User profile '" + searchId + "' not found. This is normal for container-auth users who haven't set up a profile yet.");
         }
     }
 
@@ -985,7 +840,7 @@
      * @throws java.security.AccessControlException if the action is not permitted
      * by the security policy
      */
-    public static final Object doPrivileged( WikiSession session, PrivilegedAction action ) throws AccessControlException
+    public static final Object doPrivileged( WikiSession session, PrivilegedAction<?> action ) throws AccessControlException
     {
         return Subject.doAsPrivileged( session.m_subject, action, null );
     }

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=682139&r1=682138&r2=682139&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 Sun Aug  3 05:12:47 2008
@@ -9,6 +9,8 @@
 
 import com.ecyrd.jspwiki.WikiEngine;
 import com.ecyrd.jspwiki.WikiSession;
+import com.ecyrd.jspwiki.auth.WikiPrincipal;
+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),
@@ -17,7 +19,6 @@
  * 
  * @author Andrew Jaquith
  */
-@WikiRequestContext("none")
 public abstract class AbstractActionBean implements WikiActionBean
 {
     protected  Map<String,Object> m_variableMap = new HashMap<String,Object>();
@@ -33,8 +34,6 @@
     
     private static final String DEFAULT_TEMPLATE = "default";
     
-    private final String m_requestContext;
-    
     /**
      * Creates a new instance of this class, without a WikiEngine, Request or
      * WikiPage.
@@ -42,29 +41,26 @@
     protected AbstractActionBean()
     {
         super();
-        m_requestContext = getClass().getAnnotation( WikiRequestContext.class ).value();
     }
 
     /**
      * Returns the content template for this ActionBean.
+     * TODO: make final at some point
      */
-    public final String getContentTemplate()
+    public String getContentTemplate()
     {
         return this.getClass().getAnnotation(WikiRequestContext.class).value();
     }
 
     /**
-     * Returns the Stripes ActionBeanContext associated this WikiContext, lazily
-     * creating one if necessary.
+     * Returns the Stripes ActionBeanContext associated this WikiContext. This
+     * method may return <code>null</code>, and callers should check for
+     * this condition.
      * 
      * @throws IllegalStateException
      */
     public WikiActionBeanContext getContext()
     {
-        if (m_actionBeanContext == null)
-        {
-            setContext(new WikiActionBeanContext());
-        }
         return m_actionBeanContext;
     }
 
@@ -77,6 +73,11 @@
      */
     public Principal getCurrentUser()
     {
+        if ( getWikiSession() == null )
+        {
+            // This shouldn't happen, really...
+            return WikiPrincipal.GUEST;
+        }
         return getWikiSession().getUserPrincipal();
     }
 
@@ -93,12 +94,26 @@
 
     /**
      * Returns the request context for this ActionBean by looking up the 
-     * value of the annotation {@link WikiRequestContext}. Note that if the
-     * annotation is not present, this method will return {@link ecyrd.jspwiki.WikiContext#NONE}.
+     * 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()
     {
-        return m_requestContext;
+        WikiActionBeanContext wac = getContext();
+        if ( wac == null )
+        {
+            return "none";
+        }
+
+        String eventName = wac.getEventName();
+        if ( eventName == null )
+        {
+            return "none";
+        }
+        
+        return HandlerInfo.getHandlerInfo( this.getClass(), eventName ).getRequestContext();
     }
     
     /**
@@ -225,14 +240,89 @@
     // FIXME: This method should really cache the ResourceBundles or something...
     public ResourceBundle getBundle( String bundle ) throws MissingResourceException
     {
-        Locale loc = null;
+        Locale loc = Preferences.getLocale( this );
 
         if( m_actionBeanContext != null && m_actionBeanContext.getRequest() != null )
         {
             loc = m_actionBeanContext.getRequest().getLocale();
         }
         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.
+     */
+    public HttpServletRequest getHttpRequest()
+    {
+        return getContext().getRequest();
+    }
+
+    /**
+     *  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 )
+    {
+        String result = null;
+
+        if( getContext() != null )
+        {
+            result = getContext().getRequest().getParameter( paramName );
+        }
+
+        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
+     * a Stripes event handler method's
+     * {@link com.ecyrd.jspwiki.action.WikiRequestContext} annotation for the
+     * bean class. For event handlers that do not have an
+     * {@linkplain com.ecyrd.jspwiki.action.WikiRequestContext} annotation,
+     * callers can supply a request context value based on the bean class and
+     * the event name; see the
+     * {@link com.ecyrd.jspwiki.action.HandlerInfo#getRequestContext()}
+     * 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
+     */
+    public void setRequestContext( String arg )
+    {
+        HandlerInfo handler = HandlerInfo.getHandlerInfo( this.getClass(), arg );
+        if ( getContext() == null )
+        {
+            throw new IllegalStateException( "WikiActionBean did not set a WikiActionBeanContext!" );
+        }
+        getContext().setEventName( handler.getEventName() );
+    }
+
 }

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AdministerProfilesActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AdministerProfilesActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AdministerProfilesActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AdministerProfilesActionBean.java Sun Aug  3 05:12:47 2008
@@ -9,79 +9,99 @@
 
 import com.ecyrd.jspwiki.auth.NoSuchPrincipalException;
 import com.ecyrd.jspwiki.auth.WikiSecurityException;
-import com.ecyrd.jspwiki.auth.user.DefaultUserProfile;
 import com.ecyrd.jspwiki.auth.user.UserDatabase;
 import com.ecyrd.jspwiki.auth.user.UserProfile;
 
 /**
- * Manages the administration of UserProfiles, from the Administer Profiles page. Receives a List
- * of UserProfiles, which may include a new profile, and persists the changes. Also receives an
- * Array of Strings (login names) for UserProfiles that are to be deleted, and deletes them.
- *
+ * Manages the administration of UserProfiles, from the Administer Profiles
+ * page. Receives a List of UserProfiles, which may include a new profile, and
+ * persists the changes. Also receives an Array of Strings (login names) for
+ * UserProfiles that are to be deleted, and deletes them.
+ * 
  * @author Andrew Jaquith
  */
-@WikiRequestContext("adminProfiles")
-@UrlBinding("/AdministerProfiles.action")
-public class AdministerProfilesActionBean extends AbstractActionBean {
-    
+@UrlBinding( "/AdministerProfiles.jsp" )
+public class AdministerProfilesActionBean extends AbstractActionBean
+{
+
     private String[] m_deleteLoginNames;
+
     private List<UserProfile> m_profiles;
-    
-    @ValidateNestedProperties ({
-        @Validate(field="loginName", required=true, minlength=3, maxlength=50),
-        @Validate(field="password", required=true, minlength=6, maxlength=128),
-        @Validate(field="fullName", required=true, minlength=3, maxlength=50),
-        @Validate(field="wikiName", required=true, minlength=3, maxlength=50),
-        @Validate(field="email", required=false, converter=EmailTypeConverter.class)
-    })
-
-    public String[] getDeleteLoginNames() { return m_deleteLoginNames; }
-    public void setDeleteLoginNames(String[] deleteLoginNames) { m_deleteLoginNames = deleteLoginNames; }
-
-    public List<UserProfile> getUserProfiles() { return m_profiles; }
-    
-    public void setUserProfiles(List<UserProfile> profiles) { this.m_profiles = profiles; }
 
-    @HandlesEvent("Save") @DefaultHandler
-    public Resolution saveChanges() throws WikiSecurityException {
+    @ValidateNestedProperties( { @Validate( field = "loginName", required = true, minlength = 3, maxlength = 50 ),
+                                @Validate( field = "password", required = true, minlength = 6, maxlength = 128 ),
+                                @Validate( field = "fullName", required = true, minlength = 3, maxlength = 50 ),
+                                @Validate( field = "wikiName", required = true, minlength = 3, maxlength = 50 ),
+                                @Validate( field = "email", required = false, converter = EmailTypeConverter.class ) } )
+    public String[] getDeleteLoginNames()
+    {
+        return m_deleteLoginNames;
+    }
+
+    public void setDeleteLoginNames( String[] deleteLoginNames )
+    {
+        m_deleteLoginNames = deleteLoginNames;
+    }
+
+    public List<UserProfile> getUserProfiles()
+    {
+        return m_profiles;
+    }
+
+    public void setUserProfiles( List<UserProfile> profiles )
+    {
+        this.m_profiles = profiles;
+    }
+
+    @DefaultHandler
+    @HandlesEvent( "save" )
+    @WikiRequestContext("adminProfiles")
+    public Resolution saveChanges() throws WikiSecurityException
+    {
         UserDatabase db = super.getContext().getWikiEngine().getUserManager().getUserDatabase();
 
         // Apply any changes to existing profiles (and create new ones)
-        for (UserProfile profile : m_profiles) {
-            
+        for( UserProfile profile : m_profiles )
+        {
+
             // Look up profile; create new if not found
             UserProfile existingProfile;
-            try {
-                existingProfile = db.findByLoginName(profile.getLoginName());
+            try
+            {
+                existingProfile = db.findByLoginName( profile.getLoginName() );
             }
-            catch (NoSuchPrincipalException e)
+            catch( NoSuchPrincipalException e )
             {
-                existingProfile = new DefaultUserProfile();
+                existingProfile = this.getEngine().getUserManager().getUserDatabase().newProfile();
             }
 
             // Make changes to things that have changed
-            existingProfile.setLoginName(profile.getLoginName());
-            existingProfile.setFullname(profile.getFullname());
-            existingProfile.setEmail(profile.getEmail());
-            if (profile.getPassword() != null && profile.getPassword().length() > 0) {
-                existingProfile.setPassword(profile.getPassword());
+            existingProfile.setLoginName( profile.getLoginName() );
+            existingProfile.setFullname( profile.getFullname() );
+            existingProfile.setEmail( profile.getEmail() );
+            if( profile.getPassword() != null && profile.getPassword().length() > 0 )
+            {
+                existingProfile.setPassword( profile.getPassword() );
             }
-            db.save(existingProfile);
+            db.save( existingProfile );
         }
 
         // Then, if the user checked anyone off to be deleted, delete them
-        if (m_deleteLoginNames != null) {
-            for (String loginName : m_deleteLoginNames) {
-                try {
-                    db.deleteByLoginName(loginName);
+        if( m_deleteLoginNames != null )
+        {
+            for( String loginName : m_deleteLoginNames )
+            {
+                try
+                {
+                    db.deleteByLoginName( loginName );
                 }
-                catch (NoSuchPrincipalException e)
+                catch( NoSuchPrincipalException e )
                 {
-                    throw new WikiSecurityException(e.getMessage());
+                    throw new WikiSecurityException( e.getMessage() );
                 }
             }
         }
 
-        return new RedirectResolution("/AdministerProfiles.jsp");
+        return new RedirectResolution( "/AdministerProfiles.jsp" );
     }
-}
\ No newline at end of file
+}

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AttachActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AttachActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AttachActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/AttachActionBean.java Sun Aug  3 05:12:47 2008
@@ -1,20 +1,35 @@
 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 com.ecyrd.jspwiki.WikiContext;
+import com.ecyrd.jspwiki.attachment.Attachment;
 import com.ecyrd.jspwiki.auth.permissions.PagePermission;
 
-@WikiRequestContext("att")
-@UrlBinding("/attach/")
+@UrlBinding("/attach/{page}/{attachment}")
 public class AttachActionBean extends WikiContext
 {
+    private Attachment m_attachment;
+    
+    @DefaultHandler
     @HandlesEvent("upload")
-    @EventPermission(permissionClass=PagePermission.class,target="${page.qualifiedName}",actions=PagePermission.UPLOAD_ACTION)
+    @HandlerPermission(permissionClass=PagePermission.class,target="${page.name}",actions=PagePermission.UPLOAD_ACTION)
+    @WikiRequestContext("att")
     public Resolution upload()
     {
         return null;
     }
+
+    public Attachment getAttachment()
+    {
+        return m_attachment;
+    }
+
+    public void setAttachment( Attachment attachment )
+    {
+        this.m_attachment = attachment;
+    }
 }

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/CommentActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/CommentActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/CommentActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/CommentActionBean.java Sun Aug  3 05:12:47 2008
@@ -7,12 +7,12 @@
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.auth.permissions.PagePermission;
 
-@WikiRequestContext("comment")
-@UrlBinding("/Comment.action")
+@UrlBinding("/Comment.jsp")
 public class CommentActionBean extends WikiContext
 {
     @HandlesEvent("comment")
-    @EventPermission(permissionClass=PagePermission.class, target="${page.qualifiedName}", actions=PagePermission.COMMENT_ACTION)
+    @HandlerPermission(permissionClass=PagePermission.class, target="${page.name}", actions=PagePermission.COMMENT_ACTION)
+    @WikiRequestContext("comment")
     public Resolution comment()
     {
         return null;

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/DeleteActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/DeleteActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/DeleteActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/DeleteActionBean.java Sun Aug  3 05:12:47 2008
@@ -7,12 +7,12 @@
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.auth.permissions.PagePermission;
 
-@WikiRequestContext("del")
-@UrlBinding("/Delete.action")
+@UrlBinding("/Delete.jsp")
 public class DeleteActionBean extends WikiContext
 {
     @HandlesEvent("delete")
-    @EventPermission(permissionClass=PagePermission.class, target="${page.qualifiedName}", actions=PagePermission.DELETE_ACTION)
+    @HandlerPermission(permissionClass=PagePermission.class, target="${page.name}", actions=PagePermission.DELETE_ACTION)
+    @WikiRequestContext("del")
     public Resolution delete()
     {
         return null;

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=682139&r1=682138&r2=682139&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 Sun Aug  3 05:12:47 2008
@@ -1,20 +1,45 @@
 package com.ecyrd.jspwiki.action;
 
-import net.sourceforge.stripes.action.HandlesEvent;
-import net.sourceforge.stripes.action.Resolution;
-import net.sourceforge.stripes.action.UrlBinding;
+import net.sourceforge.stripes.action.*;
 
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.auth.permissions.PagePermission;
 
-@WikiRequestContext("edit")
-@UrlBinding("/Edit.action")
+@UrlBinding("/Edit.jsp")
 public class EditActionBean extends WikiContext
 {
+    @DefaultHandler
     @HandlesEvent("edit")
-    @EventPermission(permissionClass=PagePermission.class, target="${page.qualifiedName}", actions=PagePermission.EDIT_ACTION)
+    @HandlerPermission(permissionClass=PagePermission.class, target="${page.name}", actions=PagePermission.EDIT_ACTION)
+    @WikiRequestContext("edit")
     public Resolution edit()
     {
         return null;
     }
+    
+    /**
+     * Event that extracts the current state of the edited page and forwards the user to the previewer JSP.
+     * 
+     * @return a forward resolution back to the preview page.
+     */
+    @HandlesEvent( "preview" )
+    @HandlerPermission( permissionClass = PagePermission.class, target = "${page.name}", actions = PagePermission.VIEW_ACTION )
+    @WikiRequestContext( "preview" )
+    public Resolution preview()
+    {
+        return new ForwardResolution( "/Preview.jsp" );
+    }
+
+    /**
+     * Event that diffs the current state of the edited page and forwards the user to the diff JSP.
+     * 
+     * @return a forward resolution back to the preview page.
+     */
+    @WikiRequestContext("diff")
+    @HandlesEvent("diff")
+    @HandlerPermission(permissionClass=PagePermission.class, target="${page.name}", 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/ErrorActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/ErrorActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/ErrorActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/ErrorActionBean.java Sun Aug  3 05:12:47 2008
@@ -1,9 +1,18 @@
 package com.ecyrd.jspwiki.action;
 
-import net.sourceforge.stripes.action.UrlBinding;
+import net.sourceforge.stripes.action.*;
 
-@WikiRequestContext("error")
-@UrlBinding("/Error.action")
+@UrlBinding("/Error.jsp")
 public class ErrorActionBean extends AbstractActionBean
 {
+    /**
+     * Default event that forwards control to /Message.jsp.
+     * @return the forward resolution
+     */
+    @DefaultHandler
+    @HandlesEvent("error")
+    @WikiRequestContext("error")
+    public Resolution view() {
+        return new ForwardResolution( "/Error.jsp" );
+    }
 }

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/GroupActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/GroupActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/GroupActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/GroupActionBean.java Sun Aug  3 05:12:47 2008
@@ -8,27 +8,26 @@
 import net.sourceforge.stripes.exception.StripesRuntimeException;
 import net.sourceforge.stripes.validation.*;
 
-import org.apache.commons.lang.ArrayUtils;
-
 import com.ecyrd.jspwiki.WikiEngine;
 import com.ecyrd.jspwiki.auth.WikiSecurityException;
 import com.ecyrd.jspwiki.auth.authorize.Group;
 import com.ecyrd.jspwiki.auth.authorize.GroupManager;
+import com.ecyrd.jspwiki.auth.authorize.Role;
 import com.ecyrd.jspwiki.auth.permissions.GroupPermission;
+import com.ecyrd.jspwiki.auth.permissions.WikiPermission;
 
-@WikiRequestContext("group")
-@UrlBinding("/Group.action")
-public class GroupActionBean extends AbstractActionBean implements GroupContext
+@UrlBinding( "/Group.jsp" )
+public class GroupActionBean extends AbstractActionBean
 {
     private Group m_group = null;
 
     private List<Principal> m_members = new ArrayList<Principal>();
-
+    
     public Group getGroup()
     {
         return m_group;
     }
-
+    
     public List<Principal> getMembers()
     {
         return m_members;
@@ -36,89 +35,106 @@
 
     public boolean isNew()
     {
-        return (m_group.getCreated() == null);
+        return(m_group.getCreated() == null);
     }
 
-    @Validate(required = true)
-    public void setGroup(Group group)
+    @Validate( required = true )
+    public void setGroup( Group group )
     {
         m_group = group;
         m_members.clear();
-        m_members.addAll( m_group.getMembers() );
+        for( Principal member : group.members() )
+        {
+            m_members.add( member );
+        }
     }
 
     /**
      * Sets the member list for the ActionBean, and for the underlying Group.
+     * 
      * @param members the members, separated by carriage returns
      */
-    @Validate(required = true, converter=OneToManyTypeConverter.class)
-    public void setMembers(List<Principal> members)
+    @Validate( required = true, converter = OneToManyTypeConverter.class )
+    public void setMembers( List<Principal> members )
     {
         m_members = members;
         m_group.clear();
-        for ( Principal member : members ) 
+        for( Principal member : members )
         {
             m_group.add( member );
         }
     }
 
-    @ValidationMethod(on = "save")
-    public void validateBeforeSave(ValidationErrors errors)
+    @ValidationMethod( on = "save" )
+    public void validateBeforeSave( ValidationErrors errors )
     {
         // Name cannot be one of the restricted names either
         String name = m_group.getName();
-        if (ArrayUtils.contains(Group.RESTRICTED_GROUPNAMES, name )); 
+        if( Role.isReservedName( name ) )
+            ;
         {
-            errors.add("group", new SimpleError("The group name '" + name + "' is illegal. Choose another."));
+            errors.add( "group", new SimpleError( "The group name '" + name + "' is illegal. Choose another." ) );
         }
     }
 
     /**
-     * Handler method for that deletes the group supplied by {@link #getGroup()}. If the GroupManager
-     * throws a WikiSecurityException because it cannot delete the group for some reason, the 
-     * exception is re-thrown as a StripesRuntimeException.
-     * <code>/Group.jsp</code>.
-     * @throws StripesRuntimeException if the group cannot be deleted for any reason
+     * Handler method for that deletes the group supplied by {@link #getGroup()}.
+     * If the GroupManager throws a WikiSecurityException because it cannot
+     * delete the group for some reason, the exception is re-thrown as a
+     * StripesRuntimeException. <code>/Group.jsp</code>.
+     * 
+     * @throws StripesRuntimeException if the group cannot be deleted for any
+     *             reason
      */
-    @DefaultHandler
-    @HandlesEvent("delete")
-    @EventPermission(permissionClass = GroupPermission.class, target="${group.qualifiedName}", actions=GroupPermission.DELETE_ACTION)
+    @HandlesEvent( "delete" )
+    @HandlerPermission( permissionClass = GroupPermission.class, target = "${group.name}", actions = GroupPermission.DELETE_ACTION )
+    @WikiRequestContext( "deleteGroup" )
     public Resolution delete() throws StripesRuntimeException
     {
-        try 
+        try
         {
             WikiEngine engine = getEngine();
             GroupManager groupMgr = engine.getGroupManager();
             groupMgr.removeGroup( m_group.getName() );
         }
-        catch ( WikiSecurityException e )
+        catch( WikiSecurityException e )
         {
-            throw new StripesRuntimeException(e);
+            throw new StripesRuntimeException( e );
         }
-        return new RedirectResolution(ViewActionBean.class);
+        return new RedirectResolution( ViewActionBean.class );
     }
-    
-    @HandlesEvent("save")
-    @EventPermission(permissionClass = GroupPermission.class, target = "${group.qualifiedName}", actions = GroupPermission.EDIT_ACTION)
+
+    @HandlesEvent( "save" )
+    @HandlerPermission( permissionClass = GroupPermission.class, target = "${group.name}", actions = GroupPermission.EDIT_ACTION )
+    @WikiRequestContext( "editGroup" )
     public Resolution save() throws WikiSecurityException
     {
         GroupManager mgr = getContext().getWikiEngine().getGroupManager();
-        mgr.setGroup(getContext().getWikiSession(), m_group);
+        mgr.setGroup( getContext().getWikiSession(), m_group );
         RedirectResolution r = new RedirectResolution( "/Group.jsp" );
-        r.addParameter("group",m_group.getName());
+        r.addParameter( "group", m_group.getName() );
         return r;
     }
+
+    @HandlesEvent( "create" )
+    @HandlerPermission( permissionClass = WikiPermission.class, target = WikiPermission.CREATE_GROUPS_ACTION, actions = "" )
+    @WikiRequestContext( "createGroup" )
+    public Resolution create()
+    {
+        return new ForwardResolution( "/CreateGroup.jsp" );
+    }
     
     /**
      * Default handler method for "view" events that simply forwards the user to
      * <code>/Group.jsp</code>.
      */
     @DefaultHandler
-    @HandlesEvent("view")
-    @EventPermission(permissionClass = GroupPermission.class, target = "${group.qualifiedName}", actions = GroupPermission.VIEW_ACTION)
+    @HandlesEvent( "view" )
+    @HandlerPermission( permissionClass = GroupPermission.class, target = "${group.name}", actions = GroupPermission.VIEW_ACTION )
+    @WikiRequestContext( "group" )
     public Resolution view()
     {
-        return new ForwardResolution("/Group,jsp");
+        return new ForwardResolution( "/Group,jsp" );
     }
 
 }

Copied: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/GroupTypeConverter.java (from r643690, incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/ui/GroupTypeConverter.java)
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/GroupTypeConverter.java?p2=incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/GroupTypeConverter.java&p1=incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/ui/GroupTypeConverter.java&r1=643690&r2=682139&rev=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/ui/GroupTypeConverter.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/GroupTypeConverter.java Sun Aug  3 05:12:47 2008
@@ -12,7 +12,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.ecyrd.jspwiki.ui;
+package com.ecyrd.jspwiki.action;
 
 import java.util.Collection;
 import java.util.Locale;

Added: 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=682139&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerInfo.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerInfo.java Sun Aug  3 05:12:47 2008
@@ -0,0 +1,397 @@
+package com.ecyrd.jspwiki.action;
+
+import java.lang.annotation.AnnotationFormatError;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.security.Permission;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.jsp.el.ELException;
+
+import net.sourceforge.stripes.action.DefaultHandler;
+import net.sourceforge.stripes.action.HandlesEvent;
+import net.sourceforge.stripes.util.bean.PropertyExpression;
+import net.sourceforge.stripes.util.bean.PropertyExpressionEvaluation;
+
+import com.ecyrd.jspwiki.auth.permissions.PagePermission;
+import com.ecyrd.jspwiki.auth.permissions.PermissionFactory;
+
+/**
+ * Extracts {@link HandlerPermission} annotation metadata for a supplied
+ * ActionBean class using introspection, and allows instantiation of dynamic
+ * Permissions. This class caches HandlerInfo objects for each ActionBean class,
+ * so introspection operations only happen once per class.
+ * 
+ * @author Andrew Jaquith
+ */
+public class HandlerInfo
+{
+    private static final Map<Class<? extends WikiActionBean>, Map<Method, HandlerInfo>> CACHED_INFO = new HashMap<Class<? extends WikiActionBean>, Map<Method, HandlerInfo>>();
+
+    private final Class<? extends WikiActionBean> m_beanClass;
+    
+    private final Method m_handlerMethod;
+
+    private final Class<? extends Permission> m_permissionClass;
+
+    private final String m_permissionTarget;
+
+    private final String m_permissionActions;
+
+    private final String m_handlerName;
+
+    private final PropertyExpression m_permissionTargetExpression;
+
+    private final PropertyExpression m_permissionActionExpression;
+
+    private final String m_requestContext;
+
+    /**
+     * Private constructor that identifies relevant Permission and wiki request
+     * context information for a supplied WikiActionBean's event method. The
+     * supplied event method must have previously been determined to have a
+     * {@link HandlesEvent} annotation. This constructor also looks for a
+     * {@link HandlerPermission} annotation to determine the correct Permission
+     * needed to execute the event (if supplied). Finally, attempts to determine
+     * the name of the wiki request context by looking for a
+     * {@link WikiRequestContext} annotation.
+     * 
+     * @param beanClass the ActionBean implementation for which event information should be created
+     * @param method the method that denotes the event handler
+     * @param eventHandler the name of the event the method handles
+     */
+    private HandlerInfo( Class<? extends WikiActionBean>beanClass, Method method, String eventHandler )
+    {
+        // Determine the permission annotated by @HandlerPermission (if
+        // supplied)
+        Class<? extends Permission> permClass = null;
+        String target = null;
+        String actions = null;
+        HandlerPermission permAnnotation = method.getAnnotation( HandlerPermission.class );
+        if( permAnnotation != null )
+        {
+            permClass = permAnnotation.permissionClass();
+            target = permAnnotation.target();
+            actions = permAnnotation.actions();
+
+            // If the class or target are null, this is an error (a
+            // mistake by some developer or a classloader problem)
+            if( permClass == null || target == null )
+            {
+                throw new AnnotationFormatError( "Malformed annotation: " + method.getClass().getName() + "." + method.getName() );
+            }
+        }
+
+        m_beanClass = beanClass;
+        m_handlerMethod = method;
+        m_permissionClass = permClass;
+        m_permissionTarget = (target == null || HandlerPermission.BLANK.equals( target )) ? null : target;
+        m_permissionActions = (actions == null || HandlerPermission.BLANK.equals( actions )) ? null : actions;
+
+        // Parse the expressions for the target and actions, if supplied as such
+        if( target != null && target.startsWith( "${" ) && target.endsWith( "}" ) )
+        {
+            m_permissionTargetExpression = PropertyExpression.getExpression( target.substring( 2, target.length() - 1 ) );
+        }
+        else
+        {
+            m_permissionTargetExpression = null;
+        }
+        if( actions != null && actions.startsWith( "${" ) && actions.endsWith( "}" ) )
+        {
+            m_permissionActionExpression = PropertyExpression.getExpression( m_permissionTarget.substring( 2, m_permissionTarget.length() - 1 ) );
+        }
+        else
+        {
+            m_permissionActionExpression = null;
+        }
+
+        // Identify the wiki request context identified by @WikiRequestContext
+        // (if supplied)
+        WikiRequestContext requestContext = method.getAnnotation( WikiRequestContext.class );
+        String defaultRequestContext = m_handlerMethod.getClass().getName() + "." + eventHandler;
+        m_requestContext = requestContext != null ? requestContext.value() : defaultRequestContext;
+
+        // Store the Stripes event handler name
+        m_handlerName = eventHandler;
+    }
+
+    protected String getPermissionActions()
+    {
+        return m_permissionActions;
+    }
+
+    protected Class<? extends Permission> getPermissionClass()
+    {
+        return m_permissionClass;
+    }
+
+    protected String getPermissionTarget()
+    {
+        return m_permissionTarget;
+    }
+
+    /**
+     * Returns the property expression for the target, if it specifies a valid
+     * expression, or <code>null</code> otherwise.
+     * 
+     * @return the property expression
+     */
+    protected PropertyExpression getPermissionTargetExpression()
+    {
+        return m_permissionTargetExpression;
+    }
+
+    /**
+     * Returns the property expression for the actions, if it specifies a valid
+     * expression, or <code>null</code> otherwise.
+     * 
+     * @return the property expression
+     */
+    protected PropertyExpression getActionsExpression()
+    {
+        return m_permissionActionExpression;
+    }
+
+    /**
+     * Returns the HandlerInfo object associated with the default Stripes event
+     * handler method for a supplied class. All Stripes ActionBeans (and JSPWiki
+     * WikiActionBeans, by definition) must contain a method with the
+     * {@link net.sourceforge.stripes.action.DefaultHandler} annotation.
+     * 
+     * @param beanClass the ActionBean subclass to inspect
+     * @return the event info object for the default handler method
+     */
+    public static final HandlerInfo getDefaultHandlerInfo( Class<? extends WikiActionBean> beanClass )
+    {
+        Map<Method, HandlerInfo> eventInfoCollection = CACHED_INFO.get( beanClass );
+        if( eventInfoCollection == null )
+        {
+            throw new IllegalArgumentException( "Bean class " + beanClass.getCanonicalName() + " does not have cached event info." );
+        }
+
+        // Find the first @DefaultHandler annotation
+        for( Map.Entry<Method, HandlerInfo> methodEvent : eventInfoCollection.entrySet() )
+        {
+            Method method = methodEvent.getKey();
+            HandlerInfo handlerInfo = methodEvent.getValue();
+            if( method.getAnnotation( DefaultHandler.class ) != null )
+            {
+                return handlerInfo;
+            }
+        }
+        throw new IllegalArgumentException( "Bean class " + beanClass.getCanonicalName() + " has no @DefaultHandler!" );
+    }
+
+    /**
+     * Looks up and returns the HandlerInfo for a supplied WikiActionBean class
+     * and event handler name. The supplied WikiActionBean class must contain a
+     * Stripes event handler method whose {@link HandlesEvent} annotation value
+     * matches the <code>eventHandler</code> parameter value.
+     * 
+     * @param eventHandler the Stripes ActionBean method to inspect
+     * @return the event info object for the handler method
+     */
+    public static final HandlerInfo getHandlerInfo( Class<? extends WikiActionBean> beanClass, String eventHandler )
+    {
+        Collection<HandlerInfo> handlerInfos = getHandlerInfoCollection( beanClass ).values();
+        for( HandlerInfo handlerInfo : handlerInfos )
+        {
+            if( eventHandler.equals( handlerInfo.getEventName() ) )
+            {
+                return handlerInfo;
+            }
+        }
+        throw new IllegalArgumentException( "ActionBean=" + beanClass.getCanonicalName() + ", handler=" + eventHandler
+                                            + " has no HandlerInfo!" );
+    }
+
+    /**
+     * For a supplied ActionBean class, returns a Map with the Stripes event
+     * handler methods as keys, and HandlerInfo objects as values.
+     * 
+     * @param beanClass the ActionBean subclass to inspect
+     * @return the map
+     */
+    public static final Map<Method, HandlerInfo> getHandlerInfoCollection( Class<? extends WikiActionBean> beanClass )
+    {
+        // If we've already figured out the method info, return the cached Map
+        Map<Method, HandlerInfo> eventInfoCollection = CACHED_INFO.get( beanClass );
+        if( eventInfoCollection != null )
+        {
+            return eventInfoCollection;
+        }
+        
+        // Not there, eh? Ok, let's figure it out.
+        eventInfoCollection = new HashMap<Method, HandlerInfo>();
+        CACHED_INFO.put( beanClass, eventInfoCollection );
+
+        Method[] methods = beanClass.getMethods();
+        for( int i = 0; i < methods.length; i++ )
+        {
+            // Does the method have a @HandlesEvent annotation?
+            Method method = methods[i];
+            HandlesEvent eventAnnotation = method.getAnnotation( HandlesEvent.class );
+            if( eventAnnotation != null )
+            {
+                // Create a new event info object
+                HandlerInfo handlerInfo = new HandlerInfo( beanClass, method, eventAnnotation.value() );
+                eventInfoCollection.put( method, handlerInfo );
+            }
+        }
+        return eventInfoCollection;
+    }
+
+    /**
+     * Returns the WikiActionBean class that is the parent of the event method used to
+     * instantiate the HandlerInfo object.
+     * @return
+     */
+    public Class<? extends WikiActionBean> getActionBeanClass()
+    {
+        return m_beanClass;
+    }
+    
+    /**
+     * Returns the Method associated with the event handler. This is the same method
+     * used to instantiate the HandlerInfo object in {@link #HandlerInfo(Method, String)}.
+     * 
+     * @return the method
+     */
+    public Method getHandlerMethod()
+    {
+        return m_handlerMethod;
+    }
+
+    /**
+     * Returns the name of the event, which equal to the value of the handler
+     * method's {@link HandlesEvent} annotation.
+     * 
+     * @return the event name
+     */
+    public String getEventName()
+    {
+        return m_handlerName;
+    }
+
+    /**
+     * <p>
+     * Returns the request context associated with this HandlerInfo object. If
+     * the event handler method contains an additional
+     * {@link WikiRequestContext} annotation, the annotation value will be used.
+     * Otherwise, a default wiki request context will be returned, based on the
+     * WikiActionBean's class name plus the event name, separated by ".".
+     * </p>
+     * <p>
+     * For example, consider the two event handler methods in FooActionBean
+     * below:
+     * </p>
+     * 
+     * <pre>
+     * public class FooActionBean extends WikiActionBean
+     * {
+     *     &#064;WikiRequestContext(&quot;view&quot;)
+     *     &#064;HandlesEvent(&quot;view&quot;)
+     *     public void viewBean() { ... }
+     *     
+     *     &#064;HandlesEvent(&quot;save&quot;)
+     *     public void saveBean() { ... }
+     * }
+     * </pre>
+     * 
+     * <p>
+     * Because it contains a {@link WikiRequestContext} annotation, calling
+     * <code>getRequestContext( FooActionBean.class, "view" )</code> returns
+     * the value <code>view</code>. By contrast, calling
+     * <code>getRequestContext( FooActionBean.class, "save" )</code> returns
+     * the value <code>FooActionBean.save</code>. And because there is no
+     * matching {@link HandlesEvent} annotation for "edit." calling
+     * <code>getRequestContext( FooActionBean.class, "edit" )</code> throws an
+     * {@link IllegalArgumentException}.
+     * </p>
+     * 
+     * @return
+     */
+    public String getRequestContext()
+    {
+        return m_requestContext;
+    }
+
+    /**
+     * 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.
+     * 
+     * @param actionBean the ActionBean that will be used as the base for any EL
+     *            expressions
+     * @return the resolved and instantiated Permission
+     * @throws ELException if EL expressions cannot be parsed, or of the
+     *             Permission itself cannot be instantiated for any reason
+     */
+    public Permission getPermission( WikiActionBean actionBean ) throws ELException
+    {
+        // Get the target class, target and actions
+        boolean hasOneParameter = m_permissionActions == null;
+        String target = m_permissionTarget;
+        String actions = m_permissionActions;
+
+        // Evaluate the target, if it's an expression
+        if( m_permissionTargetExpression != null )
+        {
+            PropertyExpressionEvaluation evaluation = new PropertyExpressionEvaluation( m_permissionTargetExpression, actionBean );
+            target = (String) evaluation.getValue();
+            if( target == null )
+            {
+                // If the target didn't evaluate, assume it's because some
+                // property wasn't set (probably normal)
+                // FIXME: should we throw a checked exception instead?
+                return null;
+            }
+        }
+
+        // Evaluate the actions, if it's an expression
+        if( m_permissionActionExpression != null )
+        {
+            PropertyExpressionEvaluation evaluation = new PropertyExpressionEvaluation( m_permissionActionExpression, actionBean );
+            actions = (String) evaluation.getValue();
+            if( actions == null )
+            {
+                throw new ELException( "Actions expression '${" + m_permissionTargetExpression + "} ' returned null!" );
+            }
+        }
+
+        // Instantiate the permission!
+        Permission perm = null;
+
+        // Filthy hack to use caching for Permission classes we know about
+        if( PagePermission.class.isAssignableFrom( m_permissionClass ) )
+        {
+            return PermissionFactory.getPagePermission( target, actions );
+        }
+
+        // Otherwise, create Permission manually
+        try
+        {
+            if( hasOneParameter )
+            {
+                Constructor c = m_permissionClass.getConstructor( new Class[] { String.class } );
+                perm = (Permission) c.newInstance( new Object[] { target } );
+            }
+            else
+            {
+                Constructor c = m_permissionClass.getConstructor( new Class[] { String.class, String.class } );
+                perm = (Permission) c.newInstance( new Object[] { target, actions } );
+            }
+        }
+        catch( Exception e )
+        {
+            e.printStackTrace();
+            throw new ELException( "Could not evaluate permission info: " + e.getMessage() );
+        }
+
+        return perm;
+    }
+
+}

Propchange: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerInfo.java
------------------------------------------------------------------------------
    svn:executable = *

Copied: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerPermission.java (from r643690, incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/EventPermission.java)
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerPermission.java?p2=incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerPermission.java&p1=incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/EventPermission.java&r1=643690&r2=682139&rev=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/EventPermission.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/HandlerPermission.java Sun Aug  3 05:12:47 2008
@@ -8,11 +8,11 @@
 
 /**
  * <p>Permission annotation that specifies the the class, target and actions of a
- * Permission required to execute a Stripes event method. Annotations are
+ * Permission required to execute a Stripes event handler method. Annotations are
  * specified as follows:</p>
  * <blockquote>
  * <code>
- * &#64;EventPermission(permissionClass="<var>className</var>",target="<var>target</var>",actions="<var>actions</var>")
+ * &#64;HandlerPermission(permissionClass="<var>className</var>",target="<var>target</var>",actions="<var>actions</var>")
  * </code>
  * </blockquote>
  * </p>
@@ -31,11 +31,11 @@
  * <p>For example, the following are all valid annotations:</p>
  * <blockquote>
  * <code>
- * &#64;EventPermission(permissionClass="java.io.FilePermission", target="/tmp/-", actions="read,write")
+ * &#64;HandlerPermission(permissionClass="java.io.FilePermission", target="/tmp/-", actions="read,write")
  * <br/><br/>
- * &#64;EventPermission(permissionClass="com.ecyrd.jspwiki.auth.permissions.PagePermission", target="${page.name}", actions = "edit")
+ * &#64;HandlerPermission(permissionClass="com.ecyrd.jspwiki.auth.permissions.PagePermission", target="${page.name}", actions = "edit")
  * <br/><br/>
- * &#64;EventPermission(permissionClass="com.ecyrd.jspwiki.auth.permissions.GroupPermission", target="${context.request.parameterMap['group'][0]}",actions="view")
+ * &#64;HandlerPermission(permissionClass="com.ecyrd.jspwiki.auth.permissions.GroupPermission", target="${context.request.parameterMap['group'][0]}",actions="view")
  * </code>
  * </blockquote>
  * <p>These examples assume that the ActionBeans they annotate contain the appropriate properties;
@@ -43,7 +43,7 @@
  * and <code>context</code> is assumed to be a {@link com.ecyrd.jspwiki.action.WikiActionBeanContext}
  * property.</p>
  * <p>This Annotation class does not parse, process or instantiate Permissions; it merely specifies
- * the syntax for annotating event handler methods. The collaborating class {@link EventPermissionInfo}
+ * the syntax for annotating event handler methods. The collaborating class {@link HandlerInfo}
  * actually does the heavy lifting.</p>
  * @author Andrew Jaquith
  */
@@ -51,8 +51,10 @@
 @Target( { ElementType.METHOD })
 @Documented
 @Inherited
-public @interface EventPermission
+public @interface HandlerPermission
 {
+    public static final String BLANK = "";
+    
     /**
      * The class of the Permission.
      */
@@ -64,7 +66,7 @@
      * 
      * @return the target
      */
-    String target();
+    String target() default BLANK;
 
     /**
      * The Permission actions, supplied as a static String or as an EL
@@ -72,5 +74,5 @@
      * 
      * @return the actions
      */
-    String actions();
+    String actions() default BLANK;
 }

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/InstallActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/InstallActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/InstallActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/InstallActionBean.java Sun Aug  3 05:12:47 2008
@@ -2,7 +2,7 @@
 
 import java.security.Permission;
 
-import net.sourceforge.stripes.action.UrlBinding;
+import net.sourceforge.stripes.action.*;
 
 import com.ecyrd.jspwiki.WikiEngine;
 import com.ecyrd.jspwiki.auth.NoSuchPrincipalException;
@@ -11,8 +11,7 @@
 import com.ecyrd.jspwiki.auth.user.UserDatabase;
 import com.ecyrd.jspwiki.ui.Installer;
 
-@WikiRequestContext("install")
-@UrlBinding("/Install.action")
+@UrlBinding( "/Install.jsp" )
 public class InstallActionBean extends AbstractActionBean
 {
     public Permission requiredPermission()
@@ -27,11 +26,19 @@
             userDb.findByLoginName( Installer.ADMIN_ID );
             perm = new AllPermission( engine.getApplicationName() );
         }
-        catch ( NoSuchPrincipalException e )
+        catch( NoSuchPrincipalException e )
         {
             // No admin user; thus, no permission required
         }
-            
+
         return perm;
     }
+
+    @DefaultHandler
+    @HandlesEvent( "install" )
+    @WikiRequestContext( "install" )
+    public Resolution view()
+    {
+        return new ForwardResolution( "/Install.jsp" );
+    }
 }

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=682139&r1=682138&r2=682139&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 Sun Aug  3 05:12:47 2008
@@ -1,24 +1,27 @@
 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 com.ecyrd.jspwiki.auth.permissions.WikiPermission;
 
-@WikiRequestContext("login")
-@UrlBinding("/Login.action")
+@UrlBinding("/Login.jsp")
 public class LoginActionBean extends AbstractActionBean
 {
+    @DefaultHandler
     @HandlesEvent("login")
-    @EventPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.LOGIN_ACTION)
+    @HandlerPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.LOGIN_ACTION)
+    @WikiRequestContext("login")
     public Resolution login()
     {
         return null;
     }
 
     @HandlesEvent("logout")
-    @EventPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.LOGIN_ACTION)
+    @HandlerPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.LOGIN_ACTION)
+    @WikiRequestContext("logout")
     public Resolution logout()
     {
         return null;

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=682139&r1=682138&r2=682139&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 Sun Aug  3 05:12:47 2008
@@ -1,10 +1,19 @@
 package com.ecyrd.jspwiki.action;
 
-import net.sourceforge.stripes.action.UrlBinding;
+import net.sourceforge.stripes.action.*;
 
-@WikiRequestContext("message")
-@UrlBinding("/Message.action")
+@UrlBinding("/Message.jsp")
 public class MessageActionBean extends AbstractActionBean
 {
+    /**
+     * Default event that forwards control to /Message.jsp.
+     * @return the forward resolution
+     */
+    @DefaultHandler
+    @HandlesEvent("message")
+    @WikiRequestContext("message")
+    public Resolution view() {
+        return new ForwardResolution( "/Message.jsp" );
+    }
 
 }

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/NewBlogEntryActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/NewBlogEntryActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/NewBlogEntryActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/NewBlogEntryActionBean.java Sun Aug  3 05:12:47 2008
@@ -7,12 +7,12 @@
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.auth.permissions.WikiPermission;
 
-@WikiRequestContext("newBlogEntry")
-@UrlBinding("/NewBlogEntry.action")
+@UrlBinding("/NewBlogEntry.jsp")
 public class NewBlogEntryActionBean extends WikiContext
 {
     @HandlesEvent("create")
-    @EventPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.CREATE_PAGES_ACTION)
+    @HandlerPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.CREATE_PAGES_ACTION)
+    @WikiRequestContext("newBlogEntry")
     public Resolution create()
     {
         return null;

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/NewPageActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/NewPageActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/NewPageActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/NewPageActionBean.java Sun Aug  3 05:12:47 2008
@@ -7,12 +7,12 @@
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.auth.permissions.WikiPermission;
 
-@WikiRequestContext("newPage")
-@UrlBinding("/NewPage.action")
+@UrlBinding("/NewPage.jsp")
 public class NewPageActionBean extends WikiContext
 {
+    @WikiRequestContext("newPage")
     @HandlesEvent("create")
-    @EventPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.CREATE_PAGES_ACTION)
+    @HandlerPermission(permissionClass=WikiPermission.class, target="${engine.applicationName}", actions=WikiPermission.CREATE_PAGES_ACTION)
     public Resolution create()
     {
         return null;

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/PageInfoActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/PageInfoActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/PageInfoActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/PageInfoActionBean.java Sun Aug  3 05:12:47 2008
@@ -1,5 +1,6 @@
 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;
@@ -7,12 +8,13 @@
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.auth.permissions.PagePermission;
 
-@WikiRequestContext("info")
-@UrlBinding("/PageInfo.action")
+@UrlBinding("/PageInfo.jsp")
 public class PageInfoActionBean extends WikiContext
 {
+    @DefaultHandler
     @HandlesEvent("info")
-    @EventPermission(permissionClass=PagePermission.class, target="${page.qualifiedName}", actions=PagePermission.VIEW_ACTION)
+    @WikiRequestContext("info")
+    @HandlerPermission(permissionClass=PagePermission.class, target="${page.name}", actions=PagePermission.VIEW_ACTION)
     public Resolution info()
     {
         return null;

Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/PageModifiedActionBean.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/PageModifiedActionBean.java?rev=682139&r1=682138&r2=682139&view=diff
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/PageModifiedActionBean.java (original)
+++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/com/ecyrd/jspwiki/action/PageModifiedActionBean.java Sun Aug  3 05:12:47 2008
@@ -7,12 +7,12 @@
 import com.ecyrd.jspwiki.WikiContext;
 import com.ecyrd.jspwiki.auth.permissions.PagePermission;
 
-@WikiRequestContext("conflict")
-@UrlBinding("/PageModified.action")
+@UrlBinding( "/PageModified.jsp" )
 public class PageModifiedActionBean extends WikiContext
 {
-    @HandlesEvent("conflict")
-    @EventPermission(permissionClass=PagePermission.class, target="${page.qualifiedName}", actions=PagePermission.VIEW_ACTION)
+    @HandlesEvent( "conflict" )
+    @HandlerPermission( permissionClass = PagePermission.class, target = "${page.name}", actions = PagePermission.VIEW_ACTION )
+    @WikiRequestContext( "conflict" )
     public Resolution conflict()
     {
         return null;



Mime
View raw message