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