KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > web > app > portlet > AlfrescoFacesPortlet


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.web.app.portlet;
18
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23
24 import javax.faces.application.ViewHandler;
25 import javax.faces.component.UIViewRoot;
26 import javax.faces.context.FacesContext;
27 import javax.portlet.ActionRequest;
28 import javax.portlet.ActionResponse;
29 import javax.portlet.PortletException;
30 import javax.portlet.PortletRequestDispatcher;
31 import javax.portlet.PortletSession;
32 import javax.portlet.RenderRequest;
33 import javax.portlet.RenderResponse;
34 import javax.portlet.UnavailableException;
35
36 import org.alfresco.i18n.I18NUtil;
37 import org.alfresco.repo.security.authentication.AuthenticationException;
38 import org.alfresco.service.cmr.security.AuthenticationService;
39 import org.alfresco.util.TempFileProvider;
40 import org.alfresco.web.app.Application;
41 import org.alfresco.web.app.servlet.AuthenticationHelper;
42 import org.alfresco.web.app.servlet.AuthenticationStatus;
43 import org.alfresco.web.bean.ErrorBean;
44 import org.alfresco.web.bean.FileUploadBean;
45 import org.alfresco.web.bean.LoginBean;
46 import org.alfresco.web.bean.repository.User;
47 import org.apache.commons.fileupload.FileItem;
48 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
49 import org.apache.commons.fileupload.portlet.PortletFileUpload;
50 import org.apache.commons.logging.Log;
51 import org.apache.commons.logging.LogFactory;
52 import org.apache.myfaces.portlet.MyFacesGenericPortlet;
53 import org.apache.myfaces.portlet.PortletUtil;
54 import org.springframework.web.context.WebApplicationContext;
55
56 /**
57  * Class to extend the MyFacesGenericPortlet to provide behaviour specific to Alfresco web client.
58  * Handles upload of multi-part forms through a JSR-168 Portlet, generic error handling and session
59  * login authentication.
60  *
61  * @author Gavin Cornwell, Kevin Roast
62  */

63 public class AlfrescoFacesPortlet extends MyFacesGenericPortlet
64 {
65    private static final String JavaDoc PREF_ALF_USERNAME = "_alfUserName";
66    public static final String JavaDoc INSTANCE_NAME = "AlfrescoClientInstance";
67    public static final String JavaDoc MANAGED_BEAN_PREFIX = "javax.portlet.p." + INSTANCE_NAME + "?";
68    
69    private static final String JavaDoc ERROR_PAGE_PARAM = "error-page";
70    private static final String JavaDoc ERROR_OCCURRED = "error-occurred";
71    
72    private static Log logger = LogFactory.getLog(AlfrescoFacesPortlet.class);
73
74    private String JavaDoc loginPage = null;
75    private String JavaDoc errorPage = null;
76    
77    
78    /**
79     * Called by the portlet container to allow the portlet to process an action request.
80     */

81    public void processAction(ActionRequest request, ActionResponse response)
82       throws PortletException, IOException JavaDoc
83    {
84       Application.setInPortalServer(true);
85       
86       // Set the current locale
87
I18NUtil.setLocale(Application.getLanguage(request.getPortletSession()));
88       
89       boolean isMultipart = PortletFileUpload.isMultipartContent(request);
90       
91       try
92       {
93          // NOTE: Due to filters not being called within portlets we can not make use
94
// of the MyFaces file upload support, therefore we are using a pure
95
// portlet request/action to handle file uploads until there is a
96
// solution.
97

98          if (isMultipart)
99          {
100             if (logger.isDebugEnabled())
101                logger.debug("Handling multipart request...");
102             
103             PortletSession session = request.getPortletSession();
104             
105             // get the file from the request and put it in the session
106
DiskFileItemFactory factory = new DiskFileItemFactory();
107             PortletFileUpload upload = new PortletFileUpload(factory);
108             List JavaDoc<FileItem> fileItems = upload.parseRequest(request);
109             Iterator JavaDoc<FileItem> iter = fileItems.iterator();
110             FileUploadBean bean = new FileUploadBean();
111             while(iter.hasNext())
112             {
113                FileItem item = iter.next();
114                String JavaDoc filename = item.getName();
115                if(item.isFormField() == false)
116                {
117                   if (logger.isDebugEnabled())
118                      logger.debug("Processing uploaded file: " + filename);
119                   
120                   // workaround a bug in IE where the full path is returned
121
// IE is only available for Windows so only check for the Windows path separator
122
int idx = filename.lastIndexOf('\\');
123                   
124                   if (idx == -1)
125                   {
126                      // if there is no windows path separator check for *nix
127
idx = filename.lastIndexOf('/');
128                   }
129                   
130                   if (idx != -1)
131                   {
132                      filename = filename.substring(idx + File.separator.length());
133                   }
134                   
135                   File JavaDoc tempFile = TempFileProvider.createTempFile("alfresco", ".upload");
136                   item.write(tempFile);
137                   bean.setFile(tempFile);
138                   bean.setFileName(filename);
139                   bean.setFilePath(tempFile.getAbsolutePath());
140                   session.setAttribute(FileUploadBean.FILE_UPLOAD_BEAN_NAME, bean,
141                                        PortletSession.PORTLET_SCOPE);
142                }
143             }
144             
145             // it doesn't matter what the value is we just need the VIEW_ID parameter
146
// to tell the faces portlet bridge to treat the request as a JSF request,
147
// this will send us back to the same page we came from, which is fine for
148
// most scenarios.
149
response.setRenderParameter(VIEW_ID, "a-jsf-page");
150          }
151          else
152          {
153             User user = (User)request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
154             if (user != null)
155             {
156                // setup the authentication context
157
try
158                {
159                   WebApplicationContext ctx = (WebApplicationContext)getPortletContext().getAttribute(
160                         WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
161                   AuthenticationService auth = (AuthenticationService)ctx.getBean("authenticationService");
162                   auth.validate(user.getTicket());
163                   
164                   // save last username into portlet preferences, get from LoginBean state
165
LoginBean loginBean = (LoginBean)request.getPortletSession().getAttribute(AuthenticationHelper.LOGIN_BEAN);
166                   if (loginBean != null)
167                   {
168                      //
169
// TODO: Need to login to JBoss Portal to get a user here to store prefs against
170
// so not really a suitable solution as they get thrown away at present!
171
// Also would need to store prefs PER user - so auto login for each...?
172
//
173
String JavaDoc oldValue = request.getPreferences().getValue(PREF_ALF_USERNAME, null);
174                      if (oldValue == null || oldValue.equals(loginBean.getUsernameInternal()) == false)
175                      {
176                         request.getPreferences().setValue(PREF_ALF_USERNAME, loginBean.getUsernameInternal());
177                         request.getPreferences().store();
178                      }
179                   }
180                   
181                   // do the normal JSF processing
182
super.processAction(request, response);
183                }
184                catch (AuthenticationException authErr)
185                {
186                   // remove User object as it's now useless
187
request.getPortletSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER);
188                }
189             }
190             else
191             {
192                // do the normal JSF processing as we may be on the login page
193
super.processAction(request, response);
194             }
195          }
196       }
197       catch (Throwable JavaDoc e)
198       {
199          if (getErrorPage() != null)
200          {
201             handleError(request, response, e);
202          }
203          else
204          {
205             logger.warn("No error page configured, re-throwing exception");
206             
207             if (e instanceof PortletException)
208             {
209                throw (PortletException)e;
210             }
211             else if (e instanceof IOException JavaDoc)
212             {
213                throw (IOException JavaDoc)e;
214             }
215             else
216             {
217                throw new PortletException(e);
218             }
219          }
220       }
221    }
222
223    /**
224     * @see org.apache.myfaces.portlet.MyFacesGenericPortlet#facesRender(javax.portlet.RenderRequest, javax.portlet.RenderResponse)
225     */

226    protected void facesRender(RenderRequest request, RenderResponse response)
227       throws PortletException, IOException JavaDoc
228    {
229       Application.setInPortalServer(true);
230       
231       // Set the current locale
232
I18NUtil.setLocale(Application.getLanguage(request.getPortletSession()));
233       
234       if (request.getParameter(ERROR_OCCURRED) != null)
235       {
236          String JavaDoc errorPage = Application.getErrorPage(getPortletContext());
237          
238          if (logger.isDebugEnabled())
239             logger.debug("An error has occurred, redirecting to error page: " + errorPage);
240          
241          response.setContentType("text/html");
242          PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(errorPage);
243          dispatcher.include(request, response);
244       }
245       else
246       {
247          WebApplicationContext ctx = (WebApplicationContext)getPortletContext().getAttribute(
248                WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
249          AuthenticationService auth = (AuthenticationService)ctx.getBean("AuthenticationService");
250          
251          // if we have no User object in the session then an HTTP Session timeout must have occured
252
// use the viewId to check that we are not already on the login page
253
PortletSession session = request.getPortletSession();
254          String JavaDoc viewId = request.getParameter(VIEW_ID);
255          User user = (User)request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
256          if (user == null && (viewId == null || viewId.equals(getLoginPage()) == false))
257          {
258             if (AuthenticationHelper.portalGuestAuthenticate(ctx, session, auth) == AuthenticationStatus.Guest)
259             {
260                if (logger.isDebugEnabled())
261                   logger.debug("Guest access successful.");
262                
263                // perform the forward to the page processed by the Faces servlet
264
response.setContentType("text/html");
265                request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
266                nonFacesRequest(request, response, "/jsp/browse/browse.jsp");
267             }
268             else
269             {
270                if (logger.isDebugEnabled())
271                   logger.debug("No valid User login, requesting login page. ViewId: " + viewId);
272                
273                // set last used username as special session value used by the LoginBean
274
session.setAttribute(AuthenticationHelper.SESSION_USERNAME,
275                      request.getPreferences().getValue(PREF_ALF_USERNAME, null));
276                
277                // login page is the default portal page
278
response.setContentType("text/html");
279                request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
280                nonFacesRequest(request, response);
281             }
282          }
283          else
284          {
285             if (session.getAttribute(AuthenticationHelper.SESSION_INVALIDATED) != null)
286             {
287                // remove the username preference value as explicit logout was requested by the user
288
request.getPreferences().reset(PREF_ALF_USERNAME);
289                session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED);
290             }
291             
292             try
293             {
294                if (user != null)
295                {
296                   if (logger.isDebugEnabled())
297                      logger.debug("Validating ticket: " + user.getTicket());
298                   
299                   // setup the authentication context
300
auth.validate(user.getTicket());
301                }
302                
303                // do the normal JSF processing
304
super.facesRender(request, response);
305             }
306             catch (AuthenticationException authErr)
307             {
308                // ticket is no longer valid!
309
if (logger.isDebugEnabled())
310                   logger.debug("Invalid ticket, requesting login page.");
311                
312                // remove User object as it's now useless
313
request.getPortletSession().removeAttribute(AuthenticationHelper.AUTHENTICATION_USER);
314                
315                // login page is the default portal page
316
response.setContentType("text/html");
317                request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
318                nonFacesRequest(request, response);
319             }
320             catch (Throwable JavaDoc e)
321             {
322                if (getErrorPage() != null)
323                {
324                   handleError(request, response, e);
325                }
326                else
327                {
328                   logger.warn("No error page configured, re-throwing exception");
329                   
330                   if (e instanceof PortletException)
331                   {
332                      throw (PortletException)e;
333                   }
334                   else if (e instanceof IOException JavaDoc)
335                   {
336                      throw (IOException JavaDoc)e;
337                   }
338                   else
339                   {
340                      throw new PortletException(e);
341                   }
342                }
343             }
344          }
345       }
346    }
347    
348    /**
349     * Handles errors that occur during a process action request
350     */

351    private void handleError(ActionRequest request, ActionResponse response, Throwable JavaDoc error)
352       throws PortletException, IOException JavaDoc
353    {
354       // get the error bean from the session and set the error that occurred.
355
PortletSession session = request.getPortletSession();
356       ErrorBean errorBean = (ErrorBean)session.getAttribute(ErrorBean.ERROR_BEAN_NAME,
357                              PortletSession.PORTLET_SCOPE);
358       if (errorBean == null)
359       {
360          errorBean = new ErrorBean();
361          session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean, PortletSession.PORTLET_SCOPE);
362       }
363       errorBean.setLastError(error);
364       
365       response.setRenderParameter(ERROR_OCCURRED, "true");
366    }
367    
368    /**
369     * Handles errors that occur during a render request
370     */

371    private void handleError(RenderRequest request, RenderResponse response, Throwable JavaDoc error)
372       throws PortletException, IOException JavaDoc
373    {
374       // get the error bean from the session and set the error that occurred.
375
PortletSession session = request.getPortletSession();
376       ErrorBean errorBean = (ErrorBean)session.getAttribute(ErrorBean.ERROR_BEAN_NAME,
377                              PortletSession.PORTLET_SCOPE);
378       if (errorBean == null)
379       {
380          errorBean = new ErrorBean();
381          session.setAttribute(ErrorBean.ERROR_BEAN_NAME, errorBean, PortletSession.PORTLET_SCOPE);
382       }
383       errorBean.setLastError(error);
384
385       // if the faces context is available set the current view to the browse page
386
// so that the error page goes back to the application (rather than going back
387
// to the same page which just throws the error again meaning we can never leave
388
// the error page)
389
FacesContext context = FacesContext.getCurrentInstance();
390       if (context != null)
391       {
392          ViewHandler viewHandler = context.getApplication().getViewHandler();
393          // TODO: configure the portlet error return page
394
UIViewRoot view = viewHandler.createView(context, "/jsp/browse/browse.jsp");
395          context.setViewRoot(view);
396       }
397
398       // get the error page and include that instead
399
String JavaDoc errorPage = getErrorPage();
400       
401       if (logger.isDebugEnabled())
402          logger.debug("An error has occurred, redirecting to error page: " + errorPage);
403       
404       response.setContentType("text/html");
405       PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(errorPage);
406       dispatcher.include(request, response);
407    }
408    
409    /**
410     * @see org.apache.myfaces.portlet.MyFacesGenericPortlet#setDefaultViewSelector()
411     */

412    protected void setDefaultViewSelector() throws UnavailableException
413    {
414       super.setDefaultViewSelector();
415       if (this.defaultViewSelector == null)
416       {
417          this.defaultViewSelector = new AlfrescoDefaultViewSelector();
418       }
419    }
420
421    /**
422     * @return Retrieves the configured login page
423     */

424    private String JavaDoc getLoginPage()
425    {
426       if (this.loginPage == null)
427       {
428          this.loginPage = Application.getLoginPage(getPortletContext());
429       }
430       
431       return this.loginPage;
432    }
433    
434    /**
435     * @return Retrieves the configured error page
436     */

437    private String JavaDoc getErrorPage()
438    {
439       if (this.errorPage == null)
440       {
441          this.errorPage = Application.getErrorPage(getPortletContext());
442       }
443       
444       return this.errorPage;
445    }
446 }
447
Popular Tags