View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de 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.web.stylesheet;
35  
36  import fr.paris.lutece.portal.business.portalcomponent.PortalComponentHome;
37  import fr.paris.lutece.portal.business.portlet.PortletType;
38  import fr.paris.lutece.portal.business.portlet.PortletTypeHome;
39  import fr.paris.lutece.portal.business.style.Mode;
40  import fr.paris.lutece.portal.business.style.ModeHome;
41  import fr.paris.lutece.portal.business.style.Style;
42  import fr.paris.lutece.portal.business.style.StyleHome;
43  import fr.paris.lutece.portal.business.stylesheet.StyleSheet;
44  import fr.paris.lutece.portal.business.stylesheet.StyleSheetHome;
45  import fr.paris.lutece.portal.service.fileupload.FileUploadService;
46  import fr.paris.lutece.portal.service.i18n.I18nService;
47  import fr.paris.lutece.portal.service.message.AdminMessage;
48  import fr.paris.lutece.portal.service.message.AdminMessageService;
49  import fr.paris.lutece.portal.service.template.AppTemplateService;
50  import fr.paris.lutece.portal.service.util.AppLogService;
51  import fr.paris.lutece.portal.service.util.AppPathService;
52  import fr.paris.lutece.portal.service.util.AppPropertiesService;
53  import fr.paris.lutece.portal.web.admin.AdminFeaturesPageJspBean;
54  import fr.paris.lutece.portal.web.constants.Messages;
55  import fr.paris.lutece.portal.web.constants.Parameters;
56  import fr.paris.lutece.portal.web.upload.MultipartHttpServletRequest;
57  import fr.paris.lutece.portal.web.util.LocalizedPaginator;
58  import fr.paris.lutece.util.ReferenceList;
59  import fr.paris.lutece.util.html.HtmlTemplate;
60  import fr.paris.lutece.util.html.Paginator;
61  import fr.paris.lutece.util.sort.AttributeComparator;
62  import fr.paris.lutece.util.url.UrlItem;
63  
64  import org.apache.commons.fileupload.FileItem;
65  
66  import org.xml.sax.InputSource;
67  
68  import java.io.ByteArrayInputStream;
69  import java.io.File;
70  import java.io.FileOutputStream;
71  import java.io.IOException;
72  
73  import java.util.Collection;
74  import java.util.Collections;
75  import java.util.HashMap;
76  import java.util.List;
77  import java.util.Map;
78  
79  import javax.servlet.http.HttpServletRequest;
80  
81  import javax.xml.parsers.SAXParser;
82  import javax.xml.parsers.SAXParserFactory;
83  
84  
85  /**
86   * This class provides the user interface to manage StyleSheet features
87   */
88  public class StyleSheetJspBean extends AdminFeaturesPageJspBean
89  {
90      ////////////////////////////////////////////////////////////////////////////
91      // Constants
92  
93      // Right
94      /**
95       * Right to manage stylesheets
96       */
97      public static final String RIGHT_MANAGE_STYLESHEET = "CORE_STYLESHEET_MANAGEMENT";
98  
99      /**
100      * Serial version UID
101      */
102     private static final long serialVersionUID = 8176263113722225633L;
103 
104     // Markers
105     private static final String MARK_MODE_ID = "mode_id";
106     private static final String MARK_MODE_LIST = "mode_list";
107     private static final String MARK_STYLESHEET_LIST = "stylesheet_list";
108     private static final String MARK_STYLE_LIST = "style_list";
109     private static final String MARK_STYLESHEET = "stylesheet";
110     private static final String MARK_PAGINATOR = "paginator";
111     private static final String MARK_NB_ITEMS_PER_PAGE = "nb_items_per_page";
112     private static final String MARK_PORTAL_COMPONENT_NAME = "portal_component_name";
113     private static final String MARK_PORTLET_TYPE_NAME = "portlet_type_name";
114     private static final String MARK_STYLE_DESCRIPTION = "style_description";
115 
116     // Templates files path
117     private static final String TEMPLATE_MANAGE_STYLESHEETS = "admin/stylesheet/manage_stylesheets.html";
118     private static final String TEMPLATE_CREATE_STYLESHEET = "admin/stylesheet/create_stylesheet.html";
119     private static final String TEMPLATE_MODIFY_STYLESHEET = "admin/stylesheet/modify_stylesheet.html";
120     private static final String TEMPLATE_STYLE_SELECT_OPTION = "admin/stylesheet/style_select_option.html";
121 
122     // Properties
123     private static final String PROPERTY_PATH_XSL = "path.stylesheet";
124     private static final String PROPERTY_STYLESHEETS_PER_PAGE = "paginator.stylesheet.itemsPerPage";
125     private static final String MESSAGE_STYLESHEET_ALREADY_EXISTS = "portal.style.message.stylesheetAlreadyExists";
126     private static final String MESSAGE_STYLESHEET_NOT_VALID = "portal.style.message.stylesheetNotValid";
127     private static final String MESSAGE_CONFIRM_DELETE_STYLESHEET = "portal.style.message.stylesheetConfirmDelete";
128     private static final String LABEL_ALL = "portal.util.labelAll";
129     private static final String JSP_DO_REMOVE_STYLESHEET = "jsp/admin/style/DoRemoveStyleSheet.jsp";
130     private static final String JSP_REMOVE_STYLE = "RemoveStyle.jsp";
131     private int _nItemsPerPage;
132     private int _nDefaultItemsPerPage;
133     private String _strCurrentPageIndex;
134 
135     /**
136      * Displays the stylesheets list
137      * @return the html code for displaying the stylesheets list
138      * @param request The request
139      */
140     public String getManageStyleSheet( HttpServletRequest request )
141     {
142         // Parameters processing
143         String strModeId = request.getParameter( Parameters.MODE_ID );
144         strModeId = ( strModeId != null ) ? strModeId : "-1";
145 
146         int nModeId = Integer.parseInt( strModeId );
147 
148         ReferenceList listModes = ModeHome.getModes(  );
149         String strComboItem = I18nService.getLocalizedString( LABEL_ALL, getLocale(  ) );
150         listModes.addItem( -1, strComboItem );
151 
152         List<StyleSheet> listStyleSheets = (List<StyleSheet>) StyleSheetHome.getStyleSheetList( nModeId );
153 
154         String strSortedAttributeName = request.getParameter( Parameters.SORTED_ATTRIBUTE_NAME );
155         String strAscSort = null;
156 
157         if ( strSortedAttributeName != null )
158         {
159             strAscSort = request.getParameter( Parameters.SORTED_ASC );
160 
161             boolean bIsAscSort = Boolean.parseBoolean( strAscSort );
162 
163             Collections.sort( listStyleSheets, new AttributeComparator( strSortedAttributeName, bIsAscSort ) );
164         }
165 
166         _nDefaultItemsPerPage = AppPropertiesService.getPropertyInt( PROPERTY_STYLESHEETS_PER_PAGE, 50 );
167         _strCurrentPageIndex = Paginator.getPageIndex( request, Paginator.PARAMETER_PAGE_INDEX, _strCurrentPageIndex );
168         _nItemsPerPage = Paginator.getItemsPerPage( request, Paginator.PARAMETER_ITEMS_PER_PAGE, _nItemsPerPage,
169                 _nDefaultItemsPerPage );
170 
171         String strURL = getHomeUrl( request );
172 
173         if ( strSortedAttributeName != null )
174         {
175             strURL += ( "?" + Parameters.SORTED_ATTRIBUTE_NAME + "=" + strSortedAttributeName );
176         }
177 
178         if ( strAscSort != null )
179         {
180             strURL += ( "&" + Parameters.SORTED_ASC + "=" + strAscSort );
181         }
182 
183         LocalizedPaginator<StyleSheet> paginator = new LocalizedPaginator<StyleSheet>( listStyleSheets, _nItemsPerPage,
184                 strURL, Paginator.PARAMETER_PAGE_INDEX, _strCurrentPageIndex, getLocale(  ) );
185 
186         Map<String, Object> model = new HashMap<String, Object>(  );
187         model.put( MARK_MODE_ID, strModeId );
188         model.put( MARK_NB_ITEMS_PER_PAGE, "" + _nItemsPerPage );
189         model.put( MARK_PAGINATOR, paginator );
190         model.put( MARK_STYLESHEET_LIST, paginator.getPageItems(  ) );
191         model.put( MARK_MODE_LIST, listModes );
192 
193         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MANAGE_STYLESHEETS, getLocale(  ), model );
194 
195         return getAdminPage( template.getHtml(  ) );
196     }
197 
198     /**
199      * Returns the create form of a new stylesheet with the upload field
200      * @param request the http request
201      * @return the html code for the create form of a new stylesheet
202      */
203     public String getCreateStyleSheet( HttpServletRequest request )
204     {
205         String strModeId = request.getParameter( Parameters.MODE_ID );
206 
207         Map<String, Object> model = new HashMap<String, Object>(  );
208         model.put( MARK_STYLE_LIST, getStyleList(  ) );
209         model.put( MARK_MODE_LIST, ModeHome.getModes(  ) );
210         model.put( MARK_MODE_ID, strModeId );
211 
212         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_CREATE_STYLESHEET, getLocale(  ), model );
213 
214         return getAdminPage( template.getHtml(  ) );
215     }
216 
217     /**
218      * Processes the creation form of a new stylesheet by recovering the parameters
219      * in the http request
220      * @param request the http request
221      * @return The Jsp URL of the process result
222      */
223     public String doCreateStyleSheet( HttpServletRequest request )
224     {
225         StyleSheet stylesheet = new StyleSheet(  );
226         MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
227         String strErrorUrl = getData( multipartRequest, stylesheet );
228 
229         if ( strErrorUrl != null )
230         {
231             return strErrorUrl;
232         }
233 
234         //insert in the table stylesheet of the database
235         StyleSheetHome.create( stylesheet );
236 
237         //create a local file
238         localStyleSheetFile( stylesheet );
239 
240         //Displays the list of the stylesheet files
241         return getHomeUrl( request );
242     }
243 
244     /**
245      * Reads stylesheet's data
246      * @param multipartRequest The request
247      * @param stylesheet The style sheet
248      * @return An error message URL or null if no error
249      */
250     private String getData( MultipartHttpServletRequest multipartRequest, StyleSheet stylesheet )
251     {
252         String strErrorUrl = null;
253         String strDescription = multipartRequest.getParameter( Parameters.STYLESHEET_NAME );
254         String strStyleId = multipartRequest.getParameter( Parameters.STYLES );
255         String strModeId = multipartRequest.getParameter( Parameters.MODE_STYLESHEET );
256 
257         FileItem fileSource = multipartRequest.getFile( Parameters.STYLESHEET_SOURCE );
258         byte[] baXslSource = fileSource.get(  );
259         String strFilename = FileUploadService.getFileNameOnly( fileSource );
260 
261         // Mandatory fields
262         if ( strDescription.equals( "" ) || ( strFilename == null ) || strFilename.equals( "" ) )
263         {
264             return AdminMessageService.getMessageUrl( multipartRequest, Messages.MANDATORY_FIELDS,
265                 AdminMessage.TYPE_STOP );
266         }
267 
268         //test the existence of style or mode already associate with this stylesheet
269         int nStyleId = Integer.parseInt( strStyleId );
270         int nModeId = Integer.parseInt( strModeId );
271         int nCount = StyleSheetHome.getStyleSheetNbPerStyleMode( nStyleId, nModeId );
272 
273         // Do not create a stylesheet of there is already one
274         if ( ( nCount >= 1 ) && ( stylesheet.getId(  ) == 0 /* creation */ ) )
275         {
276             return AdminMessageService.getMessageUrl( multipartRequest, MESSAGE_STYLESHEET_ALREADY_EXISTS,
277                 AdminMessage.TYPE_STOP );
278         }
279 
280         // Check the XML validity of the XSL stylesheet
281         if ( isValid( baXslSource ) != null )
282         {
283             Object[] args = { isValid( baXslSource ) };
284 
285             return AdminMessageService.getMessageUrl( multipartRequest, MESSAGE_STYLESHEET_NOT_VALID, args,
286                 AdminMessage.TYPE_STOP );
287         }
288 
289         stylesheet.setDescription( strDescription );
290         stylesheet.setStyleId( Integer.parseInt( strStyleId ) );
291         stylesheet.setModeId( Integer.parseInt( strModeId ) );
292         stylesheet.setSource( baXslSource );
293         stylesheet.setFile( strFilename );
294 
295         return strErrorUrl;
296     }
297 
298     /**
299      * Returns the form to update a stylesheet whose identifer is stored in the http request
300      * @param request The http request
301      * @return The html code
302      */
303     public String getModifyStyleSheet( HttpServletRequest request )
304     {
305         String strStyleSheetId = request.getParameter( Parameters.STYLESHEET_ID );
306         int nId = Integer.parseInt( strStyleSheetId );
307 
308         Map<String, Object> model = new HashMap<String, Object>(  );
309         model.put( MARK_STYLE_LIST, getStyleList(  ) );
310         model.put( MARK_MODE_LIST, ModeHome.getModes(  ) );
311         model.put( MARK_STYLESHEET, StyleSheetHome.findByPrimaryKey( nId ) );
312 
313         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MODIFY_STYLESHEET, getLocale(  ), model );
314 
315         return getAdminPage( template.getHtml(  ) );
316     }
317 
318     /**
319      * Return a ReferenceList with id style for code and a concatenation of portal name + portlet type name + style description for name.
320      * @return The {@link ReferenceList}
321      */
322     public ReferenceList getStyleList(  )
323     {
324         Collection<Style> stylesList = StyleHome.getStylesList(  );
325         ReferenceList stylesListWithLabels = new ReferenceList(  );
326 
327         for ( Style style : stylesList )
328         {
329             HashMap<String, Object> model = new HashMap<String, Object>(  );
330             model.put( MARK_PORTAL_COMPONENT_NAME,
331                 PortalComponentHome.findByPrimaryKey( style.getPortalComponentId(  ) ).getName(  ) );
332 
333             PortletType portletType = PortletTypeHome.findByPrimaryKey( style.getPortletTypeId(  ) );
334 
335             model.put( MARK_PORTLET_TYPE_NAME,
336                 ( ( portletType != null ) ? ( I18nService.getLocalizedString( portletType.getNameKey(  ), getLocale(  ) ) )
337                                           : "" ) );
338             model.put( MARK_STYLE_DESCRIPTION, style.getDescription(  ) );
339 
340             HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_STYLE_SELECT_OPTION, getLocale(  ), model );
341             stylesListWithLabels.addItem( style.getId(  ), template.getHtml(  ) );
342         }
343 
344         return stylesListWithLabels;
345     }
346 
347     /**
348      * Processes the updating form of a stylesheet whose new parameters are stored in the
349      * http request
350      * @param request The http request
351      * @return The Jsp URL of the process result
352      */
353     public String doModifyStyleSheet( HttpServletRequest request )
354     {
355         MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
356         int nId = Integer.parseInt( multipartRequest.getParameter( Parameters.STYLESHEET_ID ) );
357         StyleSheet stylesheet = StyleSheetHome.findByPrimaryKey( nId );
358         String strErrorUrl = getData( multipartRequest, stylesheet );
359 
360         if ( strErrorUrl != null )
361         {
362             return strErrorUrl;
363         }
364 
365         // Remove the old local file
366         removeOldLocalStyleSheet( nId );
367 
368         // Update the stylesheet in database
369         StyleSheetHome.update( stylesheet );
370 
371         // Recreate the local file
372         localStyleSheetFile( stylesheet );
373 
374         // Displays the management stylesheet page
375         return getHomeUrl( request );
376     }
377 
378     /**
379      * Returns the confirm of removing the style whose identifier is in
380      * the http request
381      *
382      * @param request The Http request
383      * @return the html code for the remove confirmation page
384      */
385     public String getRemoveStyleSheet( HttpServletRequest request )
386     {
387         String strId = request.getParameter( Parameters.STYLESHEET_ID );
388         UrlItem url = new UrlItem( JSP_DO_REMOVE_STYLESHEET );
389         url.addParameter( Parameters.STYLESHEET_ID, strId );
390 
391         StyleSheet stylesheet = StyleSheetHome.findByPrimaryKey( Integer.parseInt( strId ) );
392         Object[] args = { stylesheet.getDescription(  ) };
393 
394         return AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRM_DELETE_STYLESHEET, args, url.getUrl(  ),
395             AdminMessage.TYPE_CONFIRMATION );
396     }
397 
398     /**
399      * Processes the deletion of a stylesheet
400      * @param request the http request
401      * @return The Jsp URL of the process result
402      */
403     public String doRemoveStyleSheet( HttpServletRequest request )
404     {
405         int nId = Integer.parseInt( request.getParameter( Parameters.STYLESHEET_ID ) );
406         int nIdStyle = Integer.parseInt( request.getParameter( Parameters.STYLE_ID ) );
407         StyleSheet stylesheet = StyleSheetHome.findByPrimaryKey( nId );
408         String strFile = stylesheet.getFile(  );
409         StyleSheetHome.remove( nId );
410 
411         //removal of the XSL file
412         int nModeId = stylesheet.getModeId(  );
413         Mode mode = ModeHome.findByPrimaryKey( nModeId );
414         String strPathStyleSheet = AppPathService.getPath( PROPERTY_PATH_XSL ) + mode.getPath(  );
415         File fileToDelete = new File( strPathStyleSheet, strFile );
416 
417         if ( fileToDelete.exists(  ) )
418         {
419             fileToDelete.delete(  );
420         }
421 
422         // return getHomeUrl( request );
423         return JSP_REMOVE_STYLE + "?" + Parameters.STYLE_ID + "=" + nIdStyle;
424     }
425 
426     //////////////////////////////////////////////////////////////////////////////////
427     // Private implementation
428 
429     /**
430      *  Use parsing for validate the modify xsl file
431      *
432      * @param baXslSource The XSL source
433      * @return the message exception when the validation is false
434      */
435     private String isValid( byte[] baXslSource )
436     {
437         String strError = null;
438 
439         try
440         {
441             SAXParserFactory factory = SAXParserFactory.newInstance(  );
442             SAXParser analyzer = factory.newSAXParser(  );
443             InputSource is = new InputSource( new ByteArrayInputStream( baXslSource ) );
444             analyzer.getXMLReader(  ).parse( is );
445         }
446         catch ( Exception e )
447         {
448             strError = e.getMessage(  );
449         }
450 
451         return strError;
452     }
453 
454     /**
455      * Create and Update the local download file
456      *
457      * @param stylesheet The style sheet
458      */
459     private void localStyleSheetFile( StyleSheet stylesheet )
460     {
461         int nModeId = stylesheet.getModeId(  );
462         Mode mode = ModeHome.findByPrimaryKey( nModeId );
463         String strPathStyleSheet = AppPathService.getPath( PROPERTY_PATH_XSL ) + mode.getPath(  );
464         String strFileName = stylesheet.getFile(  );
465         String strFilePath = strPathStyleSheet + strFileName;
466 
467         FileOutputStream fos = null;
468 
469         try
470         {
471             File file = new File( strFilePath );
472 
473             if ( file.exists(  ) )
474             {
475                 file.delete(  );
476             }
477 
478             fos = new FileOutputStream( file );
479             fos.write( stylesheet.getSource(  ) );
480             fos.flush(  );
481         }
482         catch ( IOException e )
483         {
484             AppLogService.error( e.getMessage(  ), e );
485         }
486         finally
487         {
488             if ( fos != null )
489             {
490                 try
491                 {
492                     fos.close(  );
493                 }
494                 catch ( IOException e )
495                 {
496                     AppLogService.error( e.getMessage(  ), e );
497                 }
498             }
499         }
500     }
501 
502     /**
503      * remove the xsl file from the tmp directory
504      * @param nId the identifier of the file
505      */
506     private void removeOldLocalStyleSheet( int nId )
507     {
508         //Remove the file which been modify
509         StyleSheet stylesheet = StyleSheetHome.findByPrimaryKey( nId );
510         int nMode = stylesheet.getModeId(  );
511         Mode mode = ModeHome.findByPrimaryKey( nMode );
512         String strPathStyleSheet = AppPathService.getPath( PROPERTY_PATH_XSL ) + mode.getPath(  );
513         String strOldFileName = stylesheet.getFile(  );
514         String strOldFilePath = strPathStyleSheet + strOldFileName;
515         File oldFile = new File( strOldFilePath );
516 
517         if ( oldFile.exists(  ) )
518         {
519             oldFile.delete(  );
520         }
521     }
522 }