View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.util.mvc.xpage;
35  
36  import fr.paris.lutece.portal.service.security.AccessLogService;
37  import java.io.IOException;
38  import java.io.OutputStream;
39  import java.io.PrintWriter;
40  import java.lang.reflect.InvocationTargetException;
41  import java.lang.reflect.Method;
42  import java.util.ArrayList;
43  import java.util.HashMap;
44  import java.util.List;
45  import java.util.Locale;
46  import java.util.Map;
47  import java.util.Map.Entry;
48  import java.util.Set;
49  
50  import javax.servlet.http.HttpServletRequest;
51  import javax.servlet.http.HttpServletResponse;
52  import javax.validation.ConstraintViolation;
53  
54  import org.apache.logging.log4j.Logger;
55  import org.springframework.util.ReflectionUtils;
56  
57  import fr.paris.lutece.portal.service.i18n.I18nService;
58  import fr.paris.lutece.portal.service.message.SiteMessageException;
59  import fr.paris.lutece.portal.service.plugin.Plugin;
60  import fr.paris.lutece.portal.service.security.AccessLoggerConstants;
61  import fr.paris.lutece.portal.service.security.LuteceUser;
62  import fr.paris.lutece.portal.service.security.SecurityService;
63  import fr.paris.lutece.portal.service.security.UserNotSignedException;
64  import fr.paris.lutece.portal.service.template.AppTemplateService;
65  import fr.paris.lutece.portal.service.util.AppException;
66  import fr.paris.lutece.portal.service.util.AppLogService;
67  import fr.paris.lutece.portal.service.util.AppPropertiesService;
68  import fr.paris.lutece.portal.util.mvc.utils.MVCMessage;
69  import fr.paris.lutece.portal.util.mvc.utils.MVCMessageBox;
70  import fr.paris.lutece.portal.util.mvc.utils.MVCUtils;
71  import fr.paris.lutece.portal.util.mvc.xpage.annotations.Controller;
72  import fr.paris.lutece.portal.web.LocalVariables;
73  import fr.paris.lutece.portal.web.l10n.LocaleService;
74  import fr.paris.lutece.portal.web.xpages.XPage;
75  import fr.paris.lutece.portal.web.xpages.XPageApplication;
76  import fr.paris.lutece.util.ErrorMessage;
77  import fr.paris.lutece.util.bean.BeanUtil;
78  import fr.paris.lutece.util.beanvalidation.BeanValidationUtil;
79  import fr.paris.lutece.util.html.HtmlTemplate;
80  import fr.paris.lutece.util.url.UrlItem;
81  
82  /**
83   * MVC XPage Application
84   */
85  public abstract class MVCApplication implements XPageApplication
86  {
87      private static final long serialVersionUID = 6093635383465830355L;
88  
89      // markers
90      private static final String MARK_ERRORS = "errors";
91      private static final String MARK_INFOS = "infos";
92      private static final String MARK_WARNINGS = "warnings";
93      private static final String MARK_MESSAGE_BOX = "messageBox";
94  
95      // constants
96      private static final String URL_PORTAL = "Portal.jsp";
97      private static final String PATH_PORTAL = "jsp/site/";
98      private static final String VIEW_MESSAGEBOX = "messageBox";
99      private static final String CONTENT_TYPE_JSON = "application/json";
100     private static final String CONTENT_TYPE_XML = "application/xml";
101 
102     // instance vars
103     private static Logger _logger = MVCUtils.getLogger( );
104     private List<ErrorMessage> _listErrors = new ArrayList<>( );
105     private List<ErrorMessage> _listInfos = new ArrayList<>( );
106     private List<ErrorMessage> _listWarnings = new ArrayList<>( );
107     private MVCMessageBox _messageBox;
108     private Controller _controller = getClass( ).getAnnotation( Controller.class );
109 
110     /**
111      * Returns the content of the page
112      *
113      * @param request
114      *            The http request
115      * @param nMode
116      *            The current mode
117      * @param plugin
118      *            The plugin object
119      * @return The XPage
120      * @throws fr.paris.lutece.portal.service.message.SiteMessageException
121      *             Message displayed if an exception occurs
122      * @throws UserNotSignedException
123      *             if an authentication is required by a view
124      */
125     @Override
126     public XPage getPage( HttpServletRequest request, int nMode, Plugin plugin ) throws SiteMessageException, UserNotSignedException
127     {
128         return processController( request );
129     }
130 
131     // //////////////////////////////////////////////////////////////////////////
132     // Controller
133 
134     /**
135      * XPage controller
136      * 
137      * @param request
138      *            The HTTP request
139      * @return The XPage
140      * @throws UserNotSignedException
141      *             if an authentication is required by a view
142      * @throws SiteMessageException
143      *             if a message is thrown by an action
144      */
145     private XPage processController( HttpServletRequest request ) throws UserNotSignedException, SiteMessageException
146     {
147         Method [ ] methods = ReflectionUtils.getAllDeclaredMethods( getClass( ) );
148 
149         try
150         {
151             if ( isMessageBox( request ) )
152             {
153                 return messageBox( request );
154             }
155 
156             LuteceUser registredUser = getRegistredUser( request );
157 
158             // Process views
159             Method m = MVCUtils.findViewAnnotedMethod( request, methods );
160 
161             if ( m != null )
162             {
163                 AccessLogService.getInstance( ).trace( AccessLoggerConstants.EVENT_TYPE_READ, m.getName( ), registredUser,
164                         request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_FO );
165                 return (XPage) m.invoke( this, request );
166             }
167 
168             // Process actions
169             m = MVCUtils.findActionAnnotedMethod( request, methods );
170 
171             if ( m != null )
172             {
173                 AccessLogService.getInstance( ).debug( AccessLoggerConstants.EVENT_TYPE_ACTION, m.getName( ), registredUser,
174                         request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_FO );
175                 return (XPage) m.invoke( this, request );
176             }
177 
178             // No view or action found so display the default view
179             m = MVCUtils.findDefaultViewMethod( methods );
180 
181             AccessLogService.getInstance( ).trace( AccessLoggerConstants.EVENT_TYPE_ACTION, m.getName( ), registredUser,
182                     request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_FO );
183             return (XPage) m.invoke( this, request );
184         }
185         catch( InvocationTargetException e )
186         {
187             if ( e.getTargetException( ) instanceof UserNotSignedException )
188             {
189                 throw (UserNotSignedException) e.getTargetException( );
190             }
191 
192             if ( e.getTargetException( ) instanceof SiteMessageException )
193             {
194                 throw (SiteMessageException) e.getTargetException( );
195             }
196 
197             if ( e.getTargetException( ) instanceof RuntimeException )
198             {
199                 throw new AppException( "MVC Error dispaching view and action ", (RuntimeException) e.getTargetException( ) );
200             }
201 
202             throw new AppException( "MVC Error dispaching view and action ", e );
203         }
204         catch( IllegalAccessException e )
205         {
206             throw new AppException( "MVC Error dispaching view and action ", e );
207         }
208     }
209 
210     /**
211      * Returns the XPage name
212      * 
213      * @return The XPage name
214      */
215     protected String getXPageName( )
216     {
217         return _controller.xpageName( );
218     }
219 
220     /**
221      * Returns the default page title
222      * 
223      * @param locale
224      *            The locale
225      * @return The default page title
226      */
227     protected String getDefaultPageTitle( Locale locale )
228     {
229         if ( !_controller.pageTitleProperty( ).equals( "" ) )
230         {
231             return AppPropertiesService.getProperty( _controller.pageTitleProperty( ) );
232         }
233         else
234             if ( !_controller.pageTitleI18nKey( ).equals( "" ) )
235             {
236                 return I18nService.getLocalizedString( _controller.pageTitleI18nKey( ), locale );
237             }
238 
239         return _controller.xpageName( );
240     }
241 
242     /**
243      * Returns the default page path
244      * 
245      * @param locale
246      *            The locale
247      * @return The default pagepath
248      */
249     protected String getDefaultPagePath( Locale locale )
250     {
251         if ( !_controller.pagePathProperty( ).equals( "" ) )
252         {
253             return AppPropertiesService.getProperty( _controller.pagePathProperty( ) );
254         }
255         else
256             if ( !_controller.pagePathI18nKey( ).equals( "" ) )
257             {
258                 return I18nService.getLocalizedString( _controller.pagePathI18nKey( ), locale );
259             }
260 
261         return _controller.xpageName( );
262     }
263 
264     // //////////////////////////////////////////////////////////////////////////
265     // XPage utils
266 
267     /**
268      * Returns a new XPage object with default values
269      * 
270      * @return An XPage Object
271      */
272     protected XPage getXPage( )
273     {
274         XPageportal/web/xpages/XPage.html#XPage">XPage page = new XPage( );
275 
276         page.setTitle( getDefaultPageTitle( LocaleService.getDefault( ) ) );
277         page.setPathLabel( getDefaultPagePath( LocaleService.getDefault( ) ) );
278 
279         return page;
280     }
281 
282     /**
283      * Returns a new XPage object with default values and the content filled by a template
284      * 
285      * @param strTemplate
286      *            The template
287      * @return An XPage Object
288      */
289     protected XPage getXPage( String strTemplate )
290     {
291         XPage page = getXPage( );
292 
293         HtmlTemplate t = AppTemplateService.getTemplate( strTemplate );
294         page.setContent( t.getHtml( ) );
295 
296         return page;
297     }
298 
299     /**
300      * Returns a new XPage object with default values and the content filled by a template using a default model and for a given locale
301      * 
302      * @param strTemplate
303      *            The template
304      * @param locale
305      *            The locale
306      * @return An XPage Object
307      */
308     protected XPage getXPage( String strTemplate, Locale locale )
309     {
310         return getXPage( strTemplate, locale, getModel( ) );
311     }
312 
313     /**
314      * Returns a new XPage object with default values and the content filled by a template using a given model and for a given locale
315      * 
316      * @param strTemplate
317      *            The template
318      * @param locale
319      *            The locale
320      * @param model
321      *            The model
322      *
323      * @return An XPage Object
324      */
325     protected XPage getXPage( String strTemplate, Locale locale, Map<String, Object> model )
326     {
327         XPage page = getXPage( );
328 
329         HtmlTemplate t = AppTemplateService.getTemplate( strTemplate, locale, model );
330         page.setContent( t.getHtml( ) );
331         page.setTitle( getDefaultPageTitle( locale ) );
332         page.setPathLabel( getDefaultPagePath( locale ) );
333 
334         return page;
335     }
336 
337     /**
338      * Get a model Object filled with default values
339      * 
340      * @return The model
341      */
342     protected Map<String, Object> getModel( )
343     {
344         Map<String, Object> model = new HashMap<>( );
345         fillCommons( model );
346 
347         return model;
348     }
349 
350     // //////////////////////////////////////////////////////////////////////////
351     // Bean processing
352 
353     /**
354      * Populate a bean using parameters in http request
355      * 
356      * @param bean
357      *            bean to populate
358      * @param request
359      *            http request
360      */
361     protected void populate( Object bean, HttpServletRequest request )
362     {
363         BeanUtil.populate( bean, request, null );
364     }
365 
366     /**
367      * Populate a bean using parameters in http request, with locale date format controls
368      * 
369      * @param bean
370      *            bean to populate
371      * @param request
372      *            http request
373      * @param locale
374      *            the locale
375      */
376     protected void populate( Object bean, HttpServletRequest request, Locale locale )
377     {
378         BeanUtil.populate( bean, request, locale );
379     }
380 
381     /**
382      * Validate a bean. If the validation failed, error messages of this MVCApplication are updated.<br>
383      * This method should be used only if error messages of constraints of the bean are NOT i18n Keys. If they are I18n keys, the method
384      * {@link #validateBean(Object, Locale)} should be used instead.
385      * 
386      * @param <T>
387      *            The bean class
388      * @param bean
389      *            The bean
390      * @return true if validated otherwise false
391      */
392     protected <T> boolean validateBean( T bean )
393     {
394         Set<ConstraintViolation<T>> errors = BeanValidationUtil.validate( bean );
395 
396         if ( errors.isEmpty( ) )
397         {
398             return true;
399         }
400 
401         for ( ConstraintViolation<T> constraint : errors )
402         {
403             MVCMessage/util/mvc/utils/MVCMessage.html#MVCMessage">MVCMessage error = new MVCMessage( );
404             error.setMessage( constraint.getMessage( ) );
405             _listErrors.add( error );
406         }
407 
408         return false;
409     }
410 
411     /**
412      * Validate a bean. If the validation failed, error messages of this MVCApplication are updated.<br>
413      * This method should be used only if error messages of constraints of the bean are i18n Keys. If they are not I18n keys, the method
414      * {@link #validateBean(Object)} should be used instead.
415      * 
416      * @param <T>
417      *            The bean class
418      * @param bean
419      *            The bean
420      * @param locale
421      *            The locale
422      * @return true if validated otherwise false
423      */
424     protected <T> boolean validateBean( T bean, Locale locale )
425     {
426         Set<ConstraintViolation<T>> errors = BeanValidationUtil.validate( bean );
427 
428         if ( errors.isEmpty( ) )
429         {
430             return true;
431         }
432 
433         for ( ConstraintViolation<T> constraint : errors )
434         {
435             MVCMessage/util/mvc/utils/MVCMessage.html#MVCMessage">MVCMessage error = new MVCMessage( );
436             error.setMessage( I18nService.getLocalizedString( constraint.getMessage( ), locale ) );
437             _listErrors.add( error );
438         }
439 
440         return false;
441     }
442 
443     /**
444      * Add an error message. The error message must NOT be an I18n key.
445      * 
446      * @param strMessage
447      *            The message
448      */
449     protected void addError( String strMessage )
450     {
451         _listErrors.add( new MVCMessage( strMessage ) );
452     }
453     
454     /**
455      * Add an error message. The error message must NOT be an I18n key.
456      * 
457      * @param strMessage
458      *            The message
459      * @param  strFieldName the field name           
460      */
461     protected void addError( String strMessage, String strFieldName )
462     {
463         _listErrors.add( new MVCMessage( strMessage,strFieldName ) );
464     }
465 
466     /**
467      * Add an error message. The error message must be an I18n key.
468      * 
469      * @param strMessageKey
470      *            The message
471      * @param locale
472      *            The locale to display the message in
473      */
474     protected void addError( String strMessageKey, Locale locale )
475     {
476         _listErrors.add( new MVCMessage( I18nService.getLocalizedString( strMessageKey, locale ) ) );
477     }
478 
479     
480     /**
481      * Add an warning message. The warning message must NOT be an I18n key.
482      * 
483      * @param strMessage
484      *            The message
485      */
486     protected void addWarning( String strMessage )
487     {
488         _listWarnings.add( new MVCMessage( strMessage ) );
489     }
490     
491     /**
492      * Add an warning message. The warning message must NOT be an I18n key.
493      * 
494      * @param strMessage
495      *            The message
496      *            
497      * @param  strFieldName the field name            
498      *            
499      */
500     protected void addWarning( String strMessage, String strFieldName  )
501     {
502         _listWarnings.add( new MVCMessage( strMessage,strFieldName ) );
503     }
504     
505 
506 
507     /**
508      * Add an warning message. The warning message must be an I18n key.
509      * 
510      * @param strMessageKey
511      *            The message
512      * @param locale
513      *            The locale to display the message in
514      */
515     protected void addWarning( String strMessageKey, Locale locale )
516     {
517         _listWarnings.add( new MVCMessage( I18nService.getLocalizedString( strMessageKey, locale ) ) );
518     }
519 
520     /**
521      * Add an info message. The info message must NOT be an I18n key.
522      * 
523      * @param strMessage
524      *            The message
525      */
526     protected void addInfo( String strMessage )
527     {
528         _listInfos.add( new MVCMessage( strMessage ) );
529     }
530     
531     /**
532      * Add an info message. The info message must NOT be an I18n key.
533      * 
534      * @param strMessage
535      *            The message
536      * @param  strFieldName the field name             
537      */
538     protected void addInfo( String strMessage, String strFieldName )
539     {
540         _listInfos.add( new MVCMessage( strMessage,strFieldName )  );
541     }
542 
543     /**
544      * Add an info message. The info message must be an I18n key.
545      * 
546      * @param strMessageKey
547      *            The message key
548      * @param locale
549      *            The locale to display the message in
550      */
551     protected void addInfo( String strMessageKey, Locale locale )
552     {
553         _listInfos.add( new MVCMessage( I18nService.getLocalizedString( strMessageKey, locale ) ) );
554     }
555 
556     /**
557      * Fill the model with commons objects used in templates
558      * 
559      * @param model
560      *            The model
561      */
562     protected void fillCommons( Map<String, Object> model )
563     {
564         List<ErrorMessage> listErrors = new ArrayList<>( _listErrors );
565         List<ErrorMessage> listInfos = new ArrayList<>( _listInfos );
566         List<ErrorMessage> listWarnings = new ArrayList<>( _listWarnings );
567         model.put( MARK_ERRORS, listErrors );
568         model.put( MARK_INFOS, listInfos );
569         model.put( MARK_WARNINGS, listWarnings );
570         _listErrors.clear( );
571         _listInfos.clear( );
572         _listWarnings.clear( );
573     }
574 
575     // //////////////////////////////////////////////////////////////////////////
576     // Redirect utils
577 
578     /**
579      * Redirect to requested page
580      *
581      * @param request
582      *            the http request
583      * @param strTarget
584      *            the targeted page
585      * @return the page requested
586      */
587     protected XPage redirect( HttpServletRequest request, String strTarget )
588     {
589         HttpServletResponse response = LocalVariables.getResponse( );
590 
591         try
592         {
593             _logger.debug( "Redirect :{}", strTarget );
594             response.sendRedirect( strTarget );
595         }
596         catch( IOException e )
597         {
598             _logger.error( "Unable to redirect : {} : {}", strTarget, e.getMessage( ), e );
599         }
600         XPage/portal/web/xpages/XPage.html#XPage">XPage xpage=new XPage();
601         xpage.setSendRedirect(true);
602         return xpage;
603     }
604 
605     /**
606      * Redirect to an url defined by given parameters
607      * 
608      * @param request
609      *            The HTTP request
610      * @param strView
611      *            The View name
612      * @param strParameter
613      *            The additional parameter
614      * @param nValue
615      *            The additional parameter's value
616      * @return The XPage redirected
617      */
618     protected XPage redirect( HttpServletRequest request, String strView, String strParameter, int nValue )
619     {
620         UrlItemtil/url/UrlItem.html#UrlItem">UrlItem url = new UrlItem( getViewUrl( strView ) );
621         url.addParameter( strParameter, nValue );
622 
623         return redirect( request, url.getUrl( ) );
624     }
625 
626     /**
627      * Redirect to an url defined by given parameters
628      * 
629      * @param request
630      *            The HTTP request
631      * @param strView
632      *            The View name
633      * @param strParameter1
634      *            The first additional parameter
635      * @param nValue1
636      *            The first additional parameter's value
637      * @param strParameter2
638      *            The second additionnal parameter
639      * @param nValue2
640      *            The second additionnal parameter's value
641      * @return The XPage redirected
642      */
643     protected XPage redirect( HttpServletRequest request, String strView, String strParameter1, int nValue1, String strParameter2, int nValue2 )
644     {
645         UrlItemtil/url/UrlItem.html#UrlItem">UrlItem url = new UrlItem( getViewUrl( strView ) );
646         url.addParameter( strParameter1, nValue1 );
647         url.addParameter( strParameter2, nValue2 );
648 
649         return redirect( request, url.getUrl( ) );
650     }
651 
652     /**
653      * Redirect to an url defined by given parameters
654      * 
655      * @param request
656      *            The HTTP request
657      * @param strView
658      *            The View name
659      * @param additionalParameters
660      *            A map containing parameters to add to the URL. Keys of the map are parameters name, and values are parameters values
661      * @return The XPage redirected
662      */
663     protected XPage redirect( HttpServletRequest request, String strView, Map<String, String> additionalParameters )
664     {
665         UrlItemtil/url/UrlItem.html#UrlItem">UrlItem url = new UrlItem( getViewUrl( strView ) );
666 
667         if ( additionalParameters != null )
668         {
669             for ( Entry<String, String> entry : additionalParameters.entrySet( ) )
670             {
671                 url.addParameter( entry.getKey( ), entry.getValue( ) );
672             }
673         }
674 
675         return redirect( request, url.getUrl( ) );
676     }
677 
678     /**
679      * Redirect to requested view
680      *
681      * @param request
682      *            the http request
683      * @param strView
684      *            the targeted view
685      * @return the page requested
686      */
687     protected XPage redirectView( HttpServletRequest request, String strView )
688     {
689         return redirect( request, getViewUrl( strView ) );
690     }
691 
692     /**
693      * Get a View URL
694      * 
695      * @param strView
696      *            The view name
697      * @return The URL
698      */
699     protected String getViewUrl( String strView )
700     {
701         UrlItemtil/url/UrlItem.html#UrlItem">UrlItem url = new UrlItem( URL_PORTAL );
702         url.addParameter( MVCUtils.PARAMETER_PAGE, getXPageName( ) );
703         url.addParameter( MVCUtils.PARAMETER_VIEW, strView );
704 
705         return url.getUrl( );
706     }
707 
708     /**
709      * Gets the view URL with the JSP path
710      * 
711      * @param strView
712      *            The view
713      * @return The URL
714      */
715     protected String getViewFullUrl( String strView )
716     {
717         return PATH_PORTAL + getViewUrl( strView );
718     }
719 
720     /**
721      * Get Action URL
722      * 
723      * @param strAction
724      *            The view name
725      * @return The URL
726      */
727     protected String getActionUrl( String strAction )
728     {
729         UrlItemtil/url/UrlItem.html#UrlItem">UrlItem url = new UrlItem( URL_PORTAL );
730         url.addParameter( MVCUtils.PARAMETER_PAGE, getXPageName( ) );
731         url.addParameter( MVCUtils.PARAMETER_ACTION, strAction );
732 
733         return url.getUrl( );
734     }
735 
736     /**
737      * Get Action URL
738      * 
739      * @param strAction
740      *            The view name
741      * @return The URL
742      */
743     protected String getActionFullUrl( String strAction )
744     {
745         return PATH_PORTAL + getActionUrl( strAction );
746     }
747 
748     /**
749      * Initiates a file download
750      * 
751      * @param strData
752      *            Data of the file to download
753      * @param strFilename
754      *            Name of file
755      * @param strContentType
756      *            content type to set to the response
757      * @return The page requested
758      */
759     protected XPage download( String strData, String strFilename, String strContentType )
760     {
761         HttpServletResponse response = LocalVariables.getResponse( );
762         PrintWriter out = null;
763         response.setHeader( "Content-Disposition", "attachment; filename=\"" + strFilename + "\";" );
764         MVCUtils.addDownloadHeaderToResponse( response, strFilename, strContentType );
765 
766         try
767         {
768             out = response.getWriter( );
769             out.print( strData );
770         }
771         catch( IOException e )
772         {
773             AppLogService.error( e.getStackTrace( ), e );
774         }
775         finally
776         {
777             if ( out != null )
778             {
779                 out.close( );
780             }
781         }
782 
783         return new XPage( );
784     }
785 
786     /**
787      * Initiates a download of a byte array
788      * 
789      * @param data
790      *            Data to download
791      * @param strFilename
792      *            Name of the downloaded file
793      * @param strContentType
794      *            Content type to set to the response
795      * @return The page requested
796      */
797     protected XPage download( byte [ ] data, String strFilename, String strContentType )
798     {
799         HttpServletResponse response = LocalVariables.getResponse( );
800         OutputStream os;
801         MVCUtils.addDownloadHeaderToResponse( response, strFilename, strContentType );
802 
803         try
804         {
805             os = response.getOutputStream( );
806             os.write( data );
807             os.close( );
808         }
809         catch( IOException e )
810         {
811             AppLogService.error( e.getStackTrace( ), e );
812         }
813 
814         return new XPage( );
815     }
816 
817     /**
818      * Return a response as JSON content
819      * 
820      * @param strJSON
821      *            The JSON
822      * @return An unused XPage
823      */
824     protected XPage responseJSON( String strJSON )
825     {
826         HttpServletResponse response = LocalVariables.getResponse( );
827         response.setContentType( CONTENT_TYPE_JSON );
828 
829         try
830         {
831             PrintWriter out = response.getWriter( );
832             out.print( strJSON );
833             out.flush( );
834             out.close( );
835         }
836         catch( IOException e )
837         {
838             AppLogService.error( e.getStackTrace( ), e );
839         }
840 
841         return new XPage( );
842     }
843 
844     /**
845      * Return a response as XML content
846      * 
847      * @param strXML
848      *            The XML
849      * @return An unused XPage
850      */
851     protected XPage responseXML( String strXML )
852     {
853         HttpServletResponse response = LocalVariables.getResponse( );
854         response.setContentType( CONTENT_TYPE_XML );
855 
856         try
857         {
858             PrintWriter out = response.getWriter( );
859             out.print( strXML );
860             out.flush( );
861             out.close( );
862         }
863         catch( IOException e )
864         {
865             AppLogService.error( e.getStackTrace( ), e );
866         }
867 
868         return new XPage( );
869     }
870 
871     // //////////////////////////////////////////////////////////////////////////
872     // MESSAGE BOX MANAGEMENT
873 
874     /**
875      * Redirect to a Message Box page
876      * 
877      * @param request
878      *            The HTTP request
879      * @param messageBox
880      *            The MessageBox infos
881      * @return A redirect XPage
882      */
883     protected XPage redirectMessageBox( HttpServletRequest request, MVCMessageBox messageBox )
884     {
885         _messageBox = messageBox;
886 
887         return redirectView( request, VIEW_MESSAGEBOX );
888     }
889 
890     /**
891      * Check if a message box is asked for
892      * 
893      * @param request
894      *            The HTTP request
895      * @return If a message box is asked
896      */
897     private boolean isMessageBox( HttpServletRequest request )
898     {
899         String strView = request.getParameter( MVCUtils.PARAMETER_VIEW );
900 
901         return ( ( strView != null ) && ( strView.equals( VIEW_MESSAGEBOX ) ) );
902     }
903 
904     /**
905      * Default getLocale() implementation. Could be overriden
906      * 
907      * @param request
908      *            The HTTP request
909      * @return The Locale
910      */
911     protected Locale getLocale( HttpServletRequest request )
912     {
913         return LocaleService.getContextUserLocale( request );
914     }
915 
916     /**
917      * Display the Message BOX
918      * 
919      * @param request
920      *            The HTTP request
921      * @return The message box
922      */
923     private XPage messageBox( HttpServletRequest request )
924     {
925         _messageBox.localize( getLocale( request ) );
926 
927         Map<String, Object> model = getModel( );
928         model.put( MARK_MESSAGE_BOX, _messageBox );
929 
930         return getXPage( _messageBox.getTemplate( ), getLocale( request ), model );
931     }
932 
933     /**
934      * get the registred User
935      * 
936      * @param request
937      * @return the lutece user if registred, null otherwise
938      */
939     protected LuteceUser getRegistredUser( HttpServletRequest request )
940     {
941         // get authenticated user if authentication is enable
942         if ( SecurityService.isAuthenticationEnable( ) )
943         {
944             LuteceUser luteceUser = SecurityService.getInstance( ).getRegisteredUser( request );
945             if ( luteceUser != null )
946             {
947                 return luteceUser;
948             }
949         }
950 
951         return null;
952     }
953 }