View Javadoc
1   package org.andromda.cartridges.jsf.portlet.myfaces.tomahawk;
2   
3   import java.io.IOException;
4   import javax.portlet.ActionRequest;
5   import javax.portlet.ActionResponse;
6   import javax.portlet.PortletConfig;
7   import javax.portlet.PortletException;
8   import javax.portlet.RenderRequest;
9   import javax.portlet.RenderResponse;
10  import org.andromda.cartridges.jsf.portlet.myfaces.tomahawk.support.ExtensionsResponseWrapper;
11  import org.andromda.cartridges.jsf.portlet.myfaces.tomahawk.support.HttpServletRequestWrapper;
12  import org.andromda.cartridges.jsf.portlet.myfaces.tomahawk.support.HttpServletResponseWrapper;
13  import org.andromda.cartridges.jsf.portlet.myfaces.tomahawk.support.MultipartPortletRequestWrapper;
14  import org.apache.commons.fileupload.portlet.PortletFileUpload;
15  import org.apache.commons.logging.Log;
16  import org.apache.commons.logging.LogFactory;
17  import org.apache.myfaces.renderkit.html.util.AddResource;
18  import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
19  import org.apache.portals.bridges.portletfilter.PortletFilter;
20  import org.apache.portals.bridges.portletfilter.PortletFilterChain;
21  import org.apache.portals.bridges.portletfilter.PortletFilterConfig;
22  
23  /**
24   * This portlet filter supports Tomahawk's extended components, such as
25   * inputHtml and fileUpload.
26   *
27   * @author <a href="mailto:shinsuke@yahoo.co.jp">Shinsuke Sugaya</a>
28   * @author Chad Brandon
29   */
30  public class ExtensionsPortletFilter
31      implements PortletFilter
32  {
33      private static final Log log = LogFactory.getLog(ExtensionsPortletFilter.class);
34  
35      private static final String UPLOAD_REPOSITORY_PATH = "uploadRepositoryPath";
36  
37      private static final String UPLOAD_THRESHOLD_SIZE = "uploadThresholdSize";
38  
39      private static final String UPLOAD_MAX_FILE_SIZE = "uploadMaxFileSize";
40  
41      private static final String MULTIPART_ENCODING = "multipartEncoding";
42  
43      private int uploadMaxFileSize = 100 * 1024 * 1024; // 10 MB
44  
45      private int uploadThresholdSize = 1 * 1024 * 1024; // 1 MB
46  
47      private String uploadRepositoryPath = null; // standard temp directory
48  
49      private String multipartEncoding = null;
50  
51      private PortletConfig portletConfig;
52  
53      /**
54       * Called by init method of MyFacesFilterPortlet to initialize this portlet
55       * filter.
56       *
57       * @param filterConfig
58       * @throws PortletException
59       */
60      public void init(PortletFilterConfig filterConfig) throws PortletException
61      {
62          if (log.isDebugEnabled())
63          {
64              log.debug("Initializing ExtensionsPortletFilter.");
65          }
66  
67          setPortletConfig(filterConfig.getPortletConfig());
68  
69          // for inputFileUpload
70          String param = filterConfig.getInitParameter(UPLOAD_MAX_FILE_SIZE);
71  
72          uploadMaxFileSize = resolveSize(param, uploadMaxFileSize);
73  
74          param = filterConfig.getInitParameter(UPLOAD_THRESHOLD_SIZE);
75  
76          uploadThresholdSize = resolveSize(param, uploadThresholdSize);
77  
78          uploadRepositoryPath = filterConfig.getInitParameter(UPLOAD_REPOSITORY_PATH);
79  
80          multipartEncoding = filterConfig.getInitParameter(MULTIPART_ENCODING);
81  
82          if (log.isDebugEnabled())
83          {
84              log.debug("uploadMaxFileSize=" + uploadMaxFileSize);
85              log.debug("uploadThresholdSize=" + uploadThresholdSize);
86              log.debug("uploadRepositoryPath=" + uploadRepositoryPath);
87              log.debug("multipartEncoding=" + multipartEncoding);
88          }
89      }
90  
91      /**
92       * Called by render method of MyFacesFilterPortlet to put tags, such as
93       * &lt;style&gt;, into &lt;head&gt;.
94       *
95       * @param request
96       * @param response
97       * @param chain PortletFilterChain instance
98       * @throws PortletException
99       * @throws IOException
100      */
101     @SuppressWarnings("deprecation")
102     public void renderFilter(
103         RenderRequest request,
104         RenderResponse response,
105         PortletFilterChain chain) throws PortletException, IOException
106     {
107         if (log.isDebugEnabled())
108         {
109             log.debug("called renderFilter.");
110             log.debug("RenderRequest=" + request.getClass().getName());
111             log.debug("RenderResponse=" + response.getClass().getName());
112         }
113 
114         final HttpServletRequestWrapper extendedRequest = new HttpServletRequestWrapper(
115             request,
116             getPortletConfig().getPortletContext());
117 
118         // Serve resources
119         AddResource addResource = null;
120         try
121         {
122             addResource = AddResourceFactory.getInstance(extendedRequest);
123         }
124         catch (Throwable throwable)
125         {
126             log.error(throwable);
127             throw new PortletException(throwable);
128         }
129 
130         try
131         {
132             addResource.responseStarted();
133 
134             if (addResource.requiresBuffer())
135             {
136                 final HttpServletResponseWrapper servletResponse = new HttpServletResponseWrapper(response);
137                 final ExtensionsResponseWrapper extendedResponse = new ExtensionsResponseWrapper(
138                     servletResponse,
139                     response);
140 
141                 // call next rednerFilter
142                 chain.renderFilter(request, extendedResponse);
143 
144                 extendedResponse.finishResponse();
145 
146                 // only parse HTML responses
147                 if (extendedResponse.getContentType() != null
148                     && isValidContentType(extendedResponse.getContentType()))
149                 {
150                     addResource.parseResponse(
151                         extendedRequest,
152                         extendedResponse.toString(),
153                         servletResponse);
154 
155                     addResource.writeMyFacesJavascriptBeforeBodyEnd(
156                         extendedRequest,
157                         servletResponse);
158 
159                     if (!addResource.hasHeaderBeginInfos())
160                     {
161                         // writes the response if no header info is needed
162                         addResource.writeResponse(extendedRequest, servletResponse);
163                         return;
164                     }
165 
166                     // Some headerInfo has to be added
167                     addResource.writeWithFullHeader(extendedRequest, servletResponse);
168 
169                     // writes the response
170                     addResource.writeResponse(extendedRequest, servletResponse);
171                 }
172                 else
173                 {
174 
175                     byte[] responseArray = extendedResponse.getBytes();
176 
177                     if (responseArray.length > 0)
178                     {
179                         // When not filtering due to not valid content-type,
180                         // deliver the byte-array instead of a charset-converted
181                         // string.  Otherwise a binary stream gets corrupted.
182                         servletResponse.getOutputStream().write(responseArray);
183                     }
184                 }
185 
186             }
187             else
188             {
189                 chain.renderFilter(request, response);
190             }
191         }
192         finally
193         {
194             addResource.responseFinished();
195         }
196     }
197 
198     /**
199      * Called by render method of MyFacesFilterPortlet to wrap the request when
200      * it has a multipart content.
201      *
202      * @param request
203      * @param response
204      * @param chain PortletFilterChain instance
205      * @throws PortletException
206      * @throws IOException
207      */
208     public void processActionFilter(
209         ActionRequest request,
210         ActionResponse response,
211         PortletFilterChain chain) throws PortletException, IOException
212     {
213         if (log.isDebugEnabled())
214         {
215             log.debug("called processActionFilter.");
216         }
217 
218         // Check multipart/form-data
219         if (PortletFileUpload.isMultipartContent(request))
220         {
221             if (log.isDebugEnabled())
222                 log.debug("ActionRequest is multipart content.");
223             if (multipartEncoding != null)
224             {
225                 if (log.isDebugEnabled())
226                     log.debug("Mutlipart encoding is " + multipartEncoding);
227                 request.setCharacterEncoding(multipartEncoding);
228             }
229             request = new MultipartPortletRequestWrapper(
230                 request,
231                 uploadMaxFileSize,
232                 uploadThresholdSize,
233                 uploadRepositoryPath);
234         }
235 
236         // call next processActionFilter
237         chain.processActionFilter(request, response);
238     }
239 
240     /**
241      * Called by destroy method of MyFacesFilterPortlet to destroy this portlet
242      * filter.
243      */
244     public void destroy()
245     {}
246 
247     private int resolveSize(String param, int defaultValue)
248     {
249         int numberParam = defaultValue;
250 
251         if (param != null)
252         {
253             param = param.toLowerCase();
254             int factor = 1;
255             String number = param;
256 
257             if (param.endsWith("g"))
258             {
259                 factor = 1024 * 1024 * 1024;
260                 number = param.substring(0, param.length() - 1);
261             }
262             else if (param.endsWith("m"))
263             {
264                 factor = 1024 * 1024;
265                 number = param.substring(0, param.length() - 1);
266             }
267             else if (param.endsWith("k"))
268             {
269                 factor = 1024;
270                 number = param.substring(0, param.length() - 1);
271             }
272 
273             numberParam = Integer.parseInt(number) * factor;
274         }
275         return numberParam;
276     }
277 
278     /**
279      * @return Returns the portletConfig.
280      */
281     public PortletConfig getPortletConfig()
282     {
283         return portletConfig;
284     }
285 
286     /**
287      * @param portletConfig The portletConfig to set.
288      */
289     public void setPortletConfig(PortletConfig portletConfig)
290     {
291         this.portletConfig = portletConfig;
292     }
293 
294     /**
295      * @param contentType
296      * @return validContentType
297      */
298     public boolean isValidContentType(String contentType)
299     {
300         return contentType != null
301             && (contentType.startsWith("text/html") || contentType.startsWith("text/xml")
302                 || contentType.startsWith("application/xhtml+xml") || contentType
303                 .startsWith("application/xml"));
304     }
305 }