In most applications, the Actions either do the heavy lifting, or know someone who does.
Presentation - Coding Logic
How can we code navigational logic? How can we code against web resources? How can we use business objects in a web application?
We've already seen several Action classes "in action", now lets take a closer look.
- ActionSupport
- ActionContext
- Interceptors
- Business Objects
Exercise - Browse
Story: Subscribers can create and edit an account profile.
- Utilize a custom Interceptor to enforce authentification
- Secure the entire application by default, and relax authentification only where needed
- Use a global result to forward to the Login action if authentification fails
Prerequisites
- Interceptors
- Token Session Interceptor
- Authentification Interceptors
Exercises
- Review the Browse use case
- Create interceptor stacks for user, user-submit, guest, guest-submit
- Users are authenticated ("logged in"), guests are not
- Set the default interceptor to user.
- Update the relevant actions to use the appropriate interceptor stack
- Update forms to include the token tag
Hint Code
- Create an AuthentificationInterceptor class to plug into the new stacks. (Also on the CD.)
import com.opensymphony.xwork.interceptor.Interceptor; import com.opensymphony.xwork.ActionInvocation; import com.opensymphony.xwork.Action; import java.util.Map; import org.apache.struts.apps.mailreader.dao.User; public class AuthenticationInterceptor implements Interceptor { public void destroy () {} public void init() {} public String intercept(ActionInvocation actionInvocation) throws Exception { Map session = actionInvocation.getInvocationContext().getSession(); User user = (User) session.get(MailReaderSupport.USER_KEY); boolean isAuthenticated = (null!=user) && (null!=user.getDatabase()); if (!isAuthenticated) { return Action.LOGIN; } else { return actionInvocation.invoke(); } } }
The interceptors element can be placed within the package element, before the default-action-ref
<interceptors>
<interceptor name="authentication"
class="AuthenticationInterceptor"/>
<!-- other new stacks -->
<interceptor-stack name="user-submit" >
<interceptor-ref name="token-session" />
<interceptor-ref name="user"/>
</interceptor-stack>
<!-- other new stacks -->
</interceptors>
<default-interceptor-ref name="user"/>
If authentification fails, the interceptor will look for a "login" result. Add login as a global result.
<default-action-ref name="Missing"/> <global-results> <result name="login" type="redirect-action">Logon</result> </global-results>
The interceptor stack reference can be added anywhere within an action element.
<action name="Hello" class="Hello"> <result>/pages/Hello.jsp</result> <interceptor-ref name="guest"/> </action>
Accomplishments
- Utilized a custom Interceptor to enforce authentification
- Secured the entire application by default, and relaxed authentification only where needed
- Used a global result to forward to the Login action if authentification fails
Extra Credit
- Write webtests that try to access restricted pages. Does control forward to Login?
- Some actions can throw an Exception. Add a global exception error handler that will forward to a error result. Create a generic Error page to display when an unexpected error occurs. Create a NPE action that throws a null pointer exception to test the page.
<global-exception-mappings>
<exception-mapping
result="error"
exception="java.lang.Throwable"/>
</global-exception-mappings>
