View Javadoc
1   /*
2    * Copyright (c) 2002-2017, 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.plugins.xmlpage.service;
35  
36  import fr.paris.lutece.plugins.xmlpage.util.XmlPageFileUtils;
37  import fr.paris.lutece.plugins.xmlpage.util.XmlPageXercesErrorHandler;
38  import fr.paris.lutece.portal.service.mail.MailService;
39  import fr.paris.lutece.portal.service.template.AppTemplateService;
40  import fr.paris.lutece.portal.service.util.AppLogService;
41  import fr.paris.lutece.portal.service.util.AppPathService;
42  import fr.paris.lutece.portal.service.util.AppPropertiesService;
43  import fr.paris.lutece.util.html.HtmlTemplate;
44  
45  import org.xml.sax.SAXException;
46  import org.xml.sax.XMLReader;
47  import org.xml.sax.helpers.XMLReaderFactory;
48  
49  import java.io.File;
50  import java.io.IOException;
51  
52  import java.util.Collection;
53  import java.util.Iterator;
54  
55  
56  /**
57   * Service for Daemon FetchXmlFilesDaemon
58   */
59  public class FetchXmlFilesService
60  {
61      private static final String PROPERTY_DIRECTORY_TEMP_EXTENSION = "xmlpage.directory.temp.extension";
62      private static final String PROPERTY_PAGE_MAIL_VALIDATION_OK_MESSAGE = "skin/plugins/xmlpage/validation_ok.html";
63      private static final String PROPERTY_PAGE_MAIL_VALIDATION_KO_MESSAGE = "skin/plugins/xmlpage/validation_ko.html";
64      private static final String PROPERTY_PAGE_MAIL_PUBLICATION_OK_MESSAGE = "skin/plugins/xmlpage/publication_ok.html";
65      private static final String PROPERTY_PAGE_MAIL_PUBLICATION_KO_MESSAGE = "skin/plugins/xmlpage/publication_ko.html";
66      private static final String BOOKMARK_MAIL_GROUP_NAME = "@group_name@";
67      private static final String BOOKMARK_MAIL_ERROR_MESSAGE = "@error_message@";
68      private static final String PATH_SEPARATOR = "/";
69      private static final String EMPTY_STRING = "";
70      private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
71      private static final String XML_VALIDATOR_XML_READER = "org.apache.xerces.parsers.SAXParser";
72      private static final String XML_VALIDATOR_FEATURE_NAMESPACE = "http://xml.org/sax/features/namespaces";
73      private static final String XML_VALIDATOR_FEATURE_VALIDATION = "http://xml.org/sax/features/validation";
74      private static final String XML_VALIDATOR_FEATURE_VALIDATION_SCHEMA = "http://apache.org/xml/features/validation/schema";
75      private static final String XML_VALIDATOR_VALIDATION_SCHEMA_FULL_CHECKING = "http://apache.org/xml/features/validation/schema-full-checking";
76      private static final String XML_VALIDATOR_PROPERTY_SCHEMA_NO_NAMESPACE = "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";
77      private static FetchXmlFilesService _singleton = new FetchXmlFilesService(  );
78  
79      /**
80       * Returns the instance of the singleton
81       * @return The instance of the singleton
82       */
83      public static FetchXmlFilesService getInstance(  )
84      {
85          return _singleton;
86      }
87  
88      /**
89       * Method called by Daemon FecthXmlFilesDaemon
90       * @return String contening a message to log
91       */
92      public String fetchXmlFiles(  )
93      {
94          Collection listGroup = XmlPageLoaderProperties.getAllXmlPageByGroup(  );
95          Iterator itListGroup = listGroup.iterator(  );
96          StringBuffer sbFinalResult = new StringBuffer(  );
97  
98          while ( itListGroup.hasNext(  ) )
99          {
100             XmlPageGroup xmlPageGroup = (XmlPageGroup) itListGroup.next(  );
101             AppLogService.debug( "fetchXmlPages - Group name = " + xmlPageGroup.getName(  ) );
102 
103             StringBuffer sbGroupResult = new StringBuffer(  );
104 
105             // Check presence of transfert lock
106             if ( checkLockFileDetected( xmlPageGroup.getLockTransfertPath(  ) ) )
107             {
108                 sbGroupResult.append( xmlPageGroup.getName(  ) );
109                 sbGroupResult.append( " - The lock transfert file exists !" );
110                 sbGroupResult.append( LINE_SEPARATOR );
111             }
112 
113             // Check presence of publication lock
114             else if ( checkLockFileDetected( xmlPageGroup.getLockPublicationPath(  ) ) )
115             {
116                 sbGroupResult.append( xmlPageGroup.getName(  ) );
117                 sbGroupResult.append( " - The lock publication file exists !" );
118                 sbGroupResult.append( LINE_SEPARATOR );
119             }
120             else
121             {
122                 // Creating lock file
123                 if ( ( xmlPageGroup.getLockPublicationPath(  ) != null ) &&
124                         !XmlPageFileUtils.createFile( xmlPageGroup.getLockPublicationPath(  ) ) )
125                 {
126                     sbGroupResult.append( xmlPageGroup.getName(  ) );
127                     sbGroupResult.append( " - Error during creation of lock file !" );
128                     sbGroupResult.append( LINE_SEPARATOR );
129                 }
130 
131                 // Validate all XML Files before copying
132                 sbGroupResult.append( validateAllXmlFiles( xmlPageGroup ) );
133 
134                 // If all XML files are valid, copy files into WEB directory
135                 if ( sbGroupResult.length(  ) == 0 )
136                 {
137                     sbGroupResult.append( copyAllXmlAndResources( xmlPageGroup ) );
138                 }
139 
140                 // Emptying content cache
141                 if ( sbGroupResult.length(  ) == 0 )
142                 {
143                     XmlPageService.getInstance(  ).resetCache(  );
144                 }
145 
146                 // Deleting lock file
147                 if ( ( xmlPageGroup.getLockPublicationPath(  ) != null ) &&
148                         !XmlPageFileUtils.removeFile( xmlPageGroup.getLockPublicationPath(  ) ) )
149                 {
150                     sbGroupResult.append( xmlPageGroup.getName(  ) );
151                     sbGroupResult.append( " - Error during deletion of lock file !" );
152                     sbGroupResult.append( LINE_SEPARATOR );
153                 }
154             }
155 
156             if ( ( sbGroupResult != null ) && ( sbGroupResult.length(  ) > 0 ) )
157             {
158                 AppLogService.error( "Group result = " + sbGroupResult.toString(  ) );
159                 sbFinalResult.append( "fetchXmlFiles for " + xmlPageGroup.getName(  ) + " = A problem occurred" );
160                 sbFinalResult.append( LINE_SEPARATOR );
161             }
162             else
163             {
164                 sbFinalResult.append( "fetchXmlFiles for " + xmlPageGroup.getName(  ) + " = OK" );
165                 sbFinalResult.append( LINE_SEPARATOR );
166             }
167         }
168 
169         return sbFinalResult.toString(  );
170     }
171 
172     /**
173      * Detect a lock file
174      * @param strLockFilePath File path for lock
175      * @return true if lock file is detected, false otherwise
176      */
177     private boolean checkLockFileDetected( String strLockFilePath )
178     {
179         if ( strLockFilePath != null )
180         {
181             File lockTransfertFile = new File( strLockFilePath );
182 
183             if ( lockTransfertFile.exists(  ) )
184             {
185                 AppLogService.info( "checkLockFileDetected : " + strLockFilePath + " - file exists !" );
186 
187                 return true;
188             }
189 
190             return false;
191         }
192         else
193         {
194             return false;
195         }
196     }
197 
198     /**
199      * Validate all XML Files from a group with theirs XSD Schemas
200      * @param xmlPageGroup group to validate its files
201      * @return message for logging
202      */
203     private String validateAllXmlFiles( XmlPageGroup xmlPageGroup )
204     {
205         StringBuffer sbResultat = new StringBuffer(  );
206         Iterator itLstXmlPageElement = xmlPageGroup.getListXmlPageElement(  ).keySet(  ).iterator(  );
207 
208         while ( itLstXmlPageElement.hasNext(  ) )
209         {
210             Object xmlPageElementKey = itLstXmlPageElement.next(  );
211 
212             if ( !validateXmlFile( xmlPageGroup,
213                         (XmlPageElement) xmlPageGroup.getListXmlPageElement(  ).get( xmlPageElementKey ) ) )
214             {
215                 sbResultat.append( xmlPageGroup.getName(  ) );
216                 sbResultat.append( " - " );
217                 sbResultat.append( xmlPageElementKey );
218                 sbResultat.append( " - XML File not valid !" );
219                 sbResultat.append( LINE_SEPARATOR );
220             }
221         }
222 
223         // Sending validation email
224         sendValidationMail( xmlPageGroup, sbResultat.toString(  ) );
225 
226         return sbResultat.toString(  );
227     }
228 
229     /**
230      * Validate a XML File with its XSD Schema
231      * @param xmlPageGroup group to validate its files
232      * @param xmlPageElement XML File informations for validating
233      * @return true if the XML File is correct, false otherwise
234      */
235     private boolean validateXmlFile( XmlPageGroup xmlPageGroup, XmlPageElement xmlPageElement )
236     {
237         String strXmlFilePath = xmlPageGroup.getInputFilesDirectoryPath(  ).concat( PATH_SEPARATOR )
238                                             .concat( xmlPageElement.getXmlFileName(  ) );
239 
240         File xmlFile = new File( strXmlFilePath );
241 
242         String strXsdFilePath = xmlPageGroup.getXsdFilesDirectoryPath(  ).concat( PATH_SEPARATOR )
243                                             .concat( xmlPageElement.getXsdSchema(  ) );
244 
245         // if validation is required, a file is ok if it exists and is valid
246         // if validation is not required, we allow the file not to exist (no check made)
247         if ( xmlPageElement.getIsValidationRequired(  ).booleanValue(  ) )
248         {
249             // if validation is required, we should check first that the file exists.
250             if ( xmlFile.exists(  ) )
251             {
252                 try
253                 {
254                     XMLReader xmlReader = XMLReaderFactory.createXMLReader( XML_VALIDATOR_XML_READER );
255                     xmlReader.setFeature( XML_VALIDATOR_FEATURE_NAMESPACE, true );
256                     xmlReader.setFeature( XML_VALIDATOR_FEATURE_VALIDATION, true );
257                     xmlReader.setFeature( XML_VALIDATOR_FEATURE_VALIDATION_SCHEMA, true );
258                     xmlReader.setFeature( XML_VALIDATOR_VALIDATION_SCHEMA_FULL_CHECKING, true );
259                     xmlReader.setProperty( XML_VALIDATOR_PROPERTY_SCHEMA_NO_NAMESPACE, strXsdFilePath );
260 
261                     xmlReader.setErrorHandler( new XmlPageXercesErrorHandler(  ) );
262                     xmlReader.parse( strXmlFilePath );
263 
264                     return true;
265                 }
266                 catch ( IOException ioe )
267                 {
268                     AppLogService.error( "validateXmlFile : IOException", ioe );
269 
270                     return false;
271                 }
272                 catch ( SAXException saxe )
273                 {
274                     AppLogService.error( "validateXmlFile : SAXException", saxe );
275 
276                     return false;
277                 }
278             }
279             else
280             {
281                 // if validation is required and file is not found, log an error
282                 AppLogService.error( "validateXmlFile : " + strXmlFilePath + " - file doesn't exist !" );
283 
284                 return false;
285             }
286         }
287 
288         // if validation is not required : no check
289         return true;
290     }
291 
292     /**
293      * Copy all XML Files and resources of a group into web directory
294      * @param xmlPageGroup working group
295      * @return message for logging
296      */
297     private String copyAllXmlAndResources( XmlPageGroup xmlPageGroup )
298     {
299         StringBuffer sbResultat = new StringBuffer(  );
300         Iterator itLstXmlPageElement = xmlPageGroup.getListXmlPageElement(  ).values(  ).iterator(  );
301         String strTempXmlDir = null;
302         String strOriginalXmlDir = null;
303         String strPropertyResourceDir = null;
304 
305         while ( itLstXmlPageElement.hasNext(  ) )
306         {
307             XmlPageElement xmlPageElement = (XmlPageElement) itLstXmlPageElement.next(  );
308 
309             if ( strTempXmlDir == null )
310             {
311                 // Creating temporary XML directory
312                 strOriginalXmlDir = xmlPageElement.getXmlFilesDirectoryPath(  );
313                 strPropertyResourceDir = xmlPageElement.getResourceFilesDirectoryPath(  );
314                 strTempXmlDir = strOriginalXmlDir.concat( AppPropertiesService.getProperty( 
315                             PROPERTY_DIRECTORY_TEMP_EXTENSION ) );
316                 XmlPageFileUtils.makeDirectory( strTempXmlDir );
317             }
318 
319             // Copy XML File
320             XmlPageFileUtils.copyFile( xmlPageGroup.getInputFilesDirectoryPath(  ), xmlPageElement.getXmlFileName(  ),
321                 strTempXmlDir );
322         }
323 
324         // check whether the resources should be considered
325         boolean bConsiderResources = ( ( strPropertyResourceDir != null ) &&
326             ( !strPropertyResourceDir.equals( EMPTY_STRING ) ) );
327         String strOriginalResourcesDir = null;
328         String strTempResourcesDir = null;
329 
330         if ( bConsiderResources )
331         {
332             // initializing original and temp resource dirs
333             strOriginalResourcesDir = AppPathService.getWebAppPath(  ).concat( PATH_SEPARATOR )
334                                                     .concat( strPropertyResourceDir );
335             strTempResourcesDir = strOriginalResourcesDir.concat( AppPropertiesService.getProperty( 
336                         PROPERTY_DIRECTORY_TEMP_EXTENSION ) );
337 
338             // Creating temporary resources directory  
339             XmlPageFileUtils.makeDirectory( strTempResourcesDir );
340 
341             // Copying all resource files
342             File fInputDirectory = new File( xmlPageGroup.getInputFilesDirectoryPath(  ) );
343             String[] strFileNames = fInputDirectory.list(  );
344             Iterator itListExtension = xmlPageGroup.getListExtensionFileCopy(  ).iterator(  );
345 
346             while ( itListExtension.hasNext(  ) )
347             {
348                 String strExtension = (String) itListExtension.next(  );
349 
350                 for ( int i = 0; i < strFileNames.length; i++ )
351                 {
352                     if ( strFileNames[i].endsWith( strExtension ) )
353                     {
354                         XmlPageFileUtils.copyFile( xmlPageGroup.getInputFilesDirectoryPath(  ), strFileNames[i],
355                             strTempResourcesDir );
356                     }
357                 }
358             }
359         }
360 
361         // Deleting original XML 
362         XmlPageFileUtils.removeDirectory( strOriginalXmlDir );
363 
364         // Renaming temporary XML
365         if ( !XmlPageFileUtils.renameDirectory( strTempXmlDir, strOriginalXmlDir ) )
366         {
367             sbResultat.append( "Can't rename directory : " + strTempXmlDir );
368             sbResultat.append( LINE_SEPARATOR );
369         }
370 
371         // Deleting original resources directories
372         if ( bConsiderResources )
373         {
374             XmlPageFileUtils.removeDirectory( strOriginalResourcesDir );
375 
376             // Renaming temporary resources directories
377             if ( !XmlPageFileUtils.renameDirectory( strTempResourcesDir, strOriginalResourcesDir ) )
378             {
379                 sbResultat.append( "Can't rename directory : " + strTempResourcesDir );
380                 sbResultat.append( LINE_SEPARATOR );
381             }
382         }
383 
384         // Sending publication email
385         sendPublicationMail( xmlPageGroup, sbResultat.toString(  ) );
386 
387         return sbResultat.toString(  );
388     }
389 
390     /**
391      * Method for sending validation email (OK or KO)
392      * @param xmlPageGroup working group
393      * @param strMessage message for errors
394      */
395     private static void sendValidationMail( XmlPageGroup xmlPageGroup, String strMessage )
396     {
397         String strSenderName = xmlPageGroup.getMailSenderName(  );
398         String strSenderEmail = xmlPageGroup.getMailSenderEmail(  );
399         String strMailSubject = null;
400         HtmlTemplate templateMailValidation = null;
401 
402         if ( EMPTY_STRING.equals( strMessage ) )
403         {
404             strMailSubject = xmlPageGroup.getMailValidationOkSubject(  );
405             templateMailValidation = AppTemplateService.getTemplate( PROPERTY_PAGE_MAIL_VALIDATION_OK_MESSAGE );
406         }
407         else
408         {
409             strMailSubject = xmlPageGroup.getMailValidationKoSubject(  );
410             templateMailValidation = AppTemplateService.getTemplate( PROPERTY_PAGE_MAIL_VALIDATION_KO_MESSAGE );
411             templateMailValidation.substitute( BOOKMARK_MAIL_ERROR_MESSAGE, strMessage );
412         }
413 
414         templateMailValidation.substitute( BOOKMARK_MAIL_GROUP_NAME, xmlPageGroup.getName(  ) );
415 
416         MailService.sendMailHtml( xmlPageGroup.getMailRecipientList(  ), strSenderName, strSenderEmail, strMailSubject,
417             templateMailValidation.getHtml(  ) );
418     }
419 
420     /**
421      * Method for sending publication email (OK or KO)
422      * @param xmlPageGroup working group
423      * @param strMessage message for errors
424      */
425     private static void sendPublicationMail( XmlPageGroup xmlPageGroup, String strMessage )
426     {
427         String strSenderName = xmlPageGroup.getMailSenderName(  );
428         String strSenderEmail = xmlPageGroup.getMailSenderEmail(  );
429         String strMailSubject = null;
430         HtmlTemplate templateMailValidation = null;
431 
432         if ( EMPTY_STRING.equals( strMessage ) )
433         {
434             strMailSubject = xmlPageGroup.getMailPublicationOkSubject(  );
435             templateMailValidation = AppTemplateService.getTemplate( PROPERTY_PAGE_MAIL_PUBLICATION_OK_MESSAGE );
436         }
437         else
438         {
439             strMailSubject = xmlPageGroup.getMailPublicationKoSubject(  );
440             templateMailValidation = AppTemplateService.getTemplate( PROPERTY_PAGE_MAIL_PUBLICATION_KO_MESSAGE );
441             templateMailValidation.substitute( BOOKMARK_MAIL_ERROR_MESSAGE, strMessage );
442         }
443 
444         templateMailValidation.substitute( BOOKMARK_MAIL_GROUP_NAME, xmlPageGroup.getName(  ) );
445 
446         MailService.sendMailHtml( xmlPageGroup.getMailRecipientList(  ), strSenderName, strSenderEmail, strMailSubject,
447             templateMailValidation.getHtml(  ) );
448     }
449 }