View Javadoc

1   package net.trajano.twiff.internal.servlet;
2   
3   import java.beans.BeanInfo;
4   import java.beans.Introspector;
5   import java.beans.PropertyDescriptor;
6   import java.io.IOException;
7   import java.io.Serializable;
8   import java.net.URL;
9   import javax.servlet.ServletException;
10  import javax.servlet.http.HttpServlet;
11  import javax.servlet.http.HttpServletRequest;
12  import javax.servlet.http.HttpServletResponse;
13  import net.trajano.twiff.ActionPageLookup;
14  import net.trajano.twiff.ActionResultProcessor;
15  import net.trajano.twiff.Configuration;
16  import net.trajano.twiff.InstantiationException;
17  import net.trajano.twiff.UnprocessedException;
18  import net.trajano.twiff.internal.ServletContextAdapterImpl;
19  import net.trajano.twiff.internal.token.dao.SessionTokenDao;
20  import net.trajano.twiff.internal.webxml.WebXmlAdapter;
21  import org.apache.commons.beanutils.BeanUtils;
22  import org.hibernate.Session;
23  import org.hibernate.SessionFactory;
24  import org.hibernate.Transaction;
25  
26  /***
27   * This implements a form handler that does not do the post-redirect-get
28   * pattern. This should not be used normally unless it is not possible to have a
29   * datastore on the web tier.
30   * 
31   * @author Archimedes Trajano
32   */
33  public final class ActionServlet extends HttpServlet {
34      /***
35       * Location of web.xml in servlet context.
36       */
37      private static final String WEB_XML = "/WEB-INF/web.xml"; //$NON-NLS-1$
38  
39      /***
40       * @param configuration
41       * @param pageLookup
42       * @param actionResultProcessors
43       * @param webXmlAdapter
44       */
45      public ActionServlet(final Configuration configuration, final ActionPageLookup pageLookup, final ActionResultProcessor[] actionResultProcessors, final WebXmlAdapter webXmlAdapter) {
46          this.pageLookup = pageLookup;
47          this.configuration = configuration;
48          this.actionResultProcessors = actionResultProcessors;
49          this.webXmlAdapter = webXmlAdapter;
50      }
51  
52      /***
53       * The webXml adapter.
54       */
55      private final WebXmlAdapter webXmlAdapter;
56  
57      /***
58       * Action processors.
59       */
60      private final ActionResultProcessor[] actionResultProcessors;
61  
62      /***
63       * Configuration.
64       */
65      private final Configuration configuration;
66  
67      /***
68       * Lookup.
69       */
70      private final ActionPageLookup pageLookup;
71  
72      /***
73       * Handles POST requests.
74       * 
75       * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
76       *           javax.servlet.http.HttpServletResponse)
77       */
78      protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
79          ServletContextAdapterImpl adapter = new ServletContextAdapterImpl(getServletContext());
80          SessionFactory sessionFactory = adapter.getSessionFactory();
81          Session session = null;
82          try {
83              ActionServletRequestAdapter requestAdapter = new ActionServletRequestAdapter(request, configuration.getTokenFieldName());
84              session = sessionFactory.openSession();
85              if (isTokenAvailable(session, requestAdapter.getSessionId(), requestAdapter.getTokenId(), request, response)) {
86                  return;
87              }
88              Class pageClass;
89              try {
90                  pageClass = pageLookup.getPageBeanClass(request);
91              } catch (ClassNotFoundException e) {
92                  throw new InstantiationException(e);
93              }
94              RendererUtil.registerPageBean(request, pageClass);
95              Serializable bean = (Serializable) requestAdapter.getContainer().getComponentInstanceOfType(pageClass);
96              BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
97              for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
98                  if (descriptor.getWriteMethod() != null) {
99                      final Object[] objects = requestAdapter.getPostData().get(descriptor.getName());
100                     if (objects == null) {
101                         continue;
102                     } else if (objects.length == 1) {
103                         BeanUtils.setProperty(bean, descriptor.getName(), objects[0]);
104                     } else {
105                         BeanUtils.setProperty(bean, descriptor.getName(), objects);
106                     }
107                 }
108             }
109             Object result = pageLookup.getActionMethod(request).invoke(bean);
110             for (ActionResultProcessor resultProcessor : actionResultProcessors) {
111                 if (resultProcessor.isResultProcessable(result, request)) {
112                     String newUrl = resultProcessor.processActionResult(result, request);
113                     Transaction tx = session.beginTransaction();
114                     SessionTokenDao dao = new SessionTokenDao(session);
115                     dao.updateTokenInfo(requestAdapter.getSessionId(), requestAdapter.getTokenId(), new URL(new URL(request.getRequestURL().toString()), newUrl.toString()), bean);
116                     tx.commit();
117                     response.sendRedirect(response.encodeRedirectURL(newUrl));
118                     return;
119                 }
120             }
121             throw new UnprocessedException(result);
122         } catch (ServletException e) {
123             throw e;
124         } catch (IOException e) {
125             throw e;
126         } catch (Exception e) {
127             throw new ServletException(e);
128         } finally {
129             if (session != null) {
130                 session.close();
131             }
132         }
133     }
134 
135     /***
136      * This will return true if there is a token available in the database
137      * already. If not it will create one. It will also put in the redirect
138      * URLs.
139      * 
140      * @param session
141      *                   Hibernate session
142      * @param sessionId
143      *                   HTTP session ID
144      * @param tokenId
145      *                   token ID
146      * @param request
147      *                   servlet request to get the context and dispatcher from
148      * @param response
149      *                   servlet response to put the redirect in
150      * @return true if a token was already available in the database
151      * @throws IOException
152      * @throws ServletException
153      */
154     private boolean isTokenAvailable(final Session session, final String sessionId, final String tokenId, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
155         Transaction tx = session.beginTransaction();
156         SessionTokenDao dao = new SessionTokenDao(session);
157         boolean ret = false;
158         if (dao.isTokenAvailable(sessionId, tokenId)) {
159             if (dao.isTokenValid(sessionId, tokenId)) {
160                 response.sendRedirect(response.encodeRedirectURL(dao.getRedirectUrl(sessionId, tokenId).toExternalForm()));
161             } else {
162                 StringBuffer redirectUrl = new StringBuffer();
163                 redirectUrl.append(webXmlAdapter.getMappingForServlet(RedirectServlet.class));
164                 redirectUrl.append('?');
165                 redirectUrl.append(configuration.getTokenFieldName());
166                 redirectUrl.append('=');
167                 redirectUrl.append(tokenId);
168                 response.sendRedirect(response.encodeRedirectURL(redirectUrl.toString()));
169             }
170             ret = true;
171         } else {
172             dao.addToken(sessionId, tokenId);
173         }
174         tx.commit();
175         return ret;
176     }
177 }