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.plugins.formengine.service;
35  
36  import fr.paris.lutece.plugins.formengine.business.Notice;
37  import fr.paris.lutece.plugins.formengine.business.NoticeFilter;
38  import fr.paris.lutece.plugins.formengine.business.NoticeGroup;
39  import fr.paris.lutece.plugins.formengine.business.NoticeGroupFilter;
40  import fr.paris.lutece.plugins.formengine.business.NoticeGroupHome;
41  import fr.paris.lutece.plugins.formengine.business.NoticeHome;
42  import fr.paris.lutece.plugins.formengine.business.jaxb.formdefinition.FormDefinition;
43  import fr.paris.lutece.plugins.formengine.business.jaxb.formdefinition.FormElements;
44  import fr.paris.lutece.plugins.formengine.business.jaxb.formdefinition.SubFormDefinition;
45  import fr.paris.lutece.plugins.formengine.web.Form;
46  import fr.paris.lutece.plugins.formengine.web.SubForm;
47  import fr.paris.lutece.portal.service.plugin.Plugin;
48  import fr.paris.lutece.portal.service.plugin.PluginService;
49  import fr.paris.lutece.portal.service.util.AppLogService;
50  import fr.paris.lutece.portal.service.util.AppPathService;
51  import fr.paris.lutece.portal.service.util.AppPropertiesService;
52  import fr.paris.lutece.util.ReferenceItem;
53  import fr.paris.lutece.util.ReferenceList;
54  import fr.paris.lutece.util.filesystem.FileListFilter;
55  
56  import org.w3c.dom.CDATASection;
57  import org.w3c.dom.Document;
58  import org.w3c.dom.Element;
59  import org.w3c.dom.Node;
60  import org.w3c.dom.NodeList;
61  
62  import org.xml.sax.SAXException;
63  import org.xml.sax.SAXParseException;
64  
65  import java.io.File;
66  import java.io.FilenameFilter;
67  
68  import java.lang.reflect.Constructor;
69  
70  import java.util.Collection;
71  import java.util.HashMap;
72  import java.util.List;
73  import java.util.Map;
74  
75  import javax.xml.bind.JAXBContext;
76  import javax.xml.bind.JAXBException;
77  import javax.xml.bind.Unmarshaller;
78  import javax.xml.parsers.DocumentBuilder;
79  import javax.xml.parsers.DocumentBuilderFactory;
80  
81  
82  /**
83   * This class is responsible for registrating the forms. It scans the directory containing all the form definitions
84   * and load the data from those files into the Form and SubForm objects.
85   */
86  public final class FormsRegistrationService
87  {
88      private static final String PATH_FORM_DEFINITIONS = "formengine.path.formdefinitions";
89      private static final String EXTENSION_FILE = "xml";
90      private static final String CLASS_NAME_STRING = "java.lang.String";
91      private static final String PROPERTY_FORMDEFINITION_PACKAGE_NAME = "formengine.jaxb.packagename.formdefinition";
92      private static final String PLUGIN_NAME = "formengine";
93      private static final String NO_FORM = "Aucun formulaire";
94      private static final String DEFAULT_WORKGROUP = "all";
95      private static final String XML_ATTR_NAME = "name";
96      private static final String XML_NODE_NOTICE_GROUP = "noticeGroup";
97      private static final String XML_NODE_NOTICE = "notice";
98      private static final String DEFAULT_FORM_INDEX = "-1";
99      private static final int DEFAULT_ID_MAILING_LIST = -1;
100 
101     //private static final int DEFAULT_ID_RSS_LIST = -1;
102     private static Map<String, Form> _mapForms = new HashMap<String, Form>(  );
103 
104     /**
105      * Constructor
106      */
107     private FormsRegistrationService(  )
108     {
109     }
110 
111     /**
112      * Load the forms from the form definition files.
113      * Scans  the form definitions directory and instanciate
114      * the corresponding objects.
115 	 *
116      * @see FormsRegistrationService#loadForm(File, Unmarshaller)
117      *
118      */
119     public static void loadForms(  )
120     {
121         try
122         {
123         	Unmarshaller unmarshaller = getUnmarshaller();
124 
125             File dirPlugin = new File( AppPathService.getPath( PATH_FORM_DEFINITIONS ) );
126 
127             if ( ( dirPlugin != null ) && dirPlugin.exists(  ) )
128             {
129                 FilenameFilter select = new FileListFilter( "", EXTENSION_FILE );
130                 File[] listFile = dirPlugin.listFiles( select );
131 
132                 for ( int i = 0; i < listFile.length; i++ )
133                 {
134                     File file = listFile[i];
135 
136                     try
137                     {
138                     	loadForm( file, unmarshaller );
139                     }
140                     catch ( Exception e )
141                     {
142                         AppLogService.error( PLUGIN_NAME.toUpperCase(  ) + " : " + e.getMessage(  ), e );
143                     }
144                 }
145             }
146         }
147         catch ( JAXBException e )
148         {
149             AppLogService.error( PLUGIN_NAME.toUpperCase(  ) + " : " + e.getMessage(  ), e );
150         }
151     }
152 
153     /**
154      * Return the form from its name
155      * @param strFormName the name of the form to retrieve
156      * @return the form of given name
157      * This is the method used by FormEngineApp to access a form
158      */
159     public static Form getForm( String strFormName )
160     {
161         Form form = (Form) _mapForms.get( strFormName );
162 
163         return form;
164     }
165 
166     /**
167      *
168      * @return forms names
169      */
170     public static Collection<String> getForms(  )
171     {
172         return _mapForms.keySet(  );
173     }
174 
175     /**
176      * Return the list of forms
177      * @return the list of forms
178      */
179     public static ReferenceList getListForm(  )
180     {
181         ReferenceList refListForms = new ReferenceList(  );
182         Collection<Form> colForms = _mapForms.values(  );
183 
184         refListForms.addItem( -1, NO_FORM );
185 
186         int count = 0;
187 
188         for ( Form form : colForms )
189         {
190             Collection<SubForm> colSubForms = form.getSubForm(  ).values(  );
191 
192             for ( SubForm subform : colSubForms )
193             {
194                 refListForms.addItem( count, form.getName(  ) + "-" + subform.getName(  ) );
195                 count++;
196             }
197         }
198 
199         return refListForms;
200     }
201 
202     /**
203      * Gets the map form.
204      * <br>
205      * Same behaviour as {@link #getListForm()}, without empty value.
206      * Key is <code>form id</code> and value is <code>form name</code>
207      * @return the map
208      * @see #getListForm()
209      */
210     public static Map<String, String> getMapForm(  )
211     {
212         Map<String, String> mapForms = new HashMap<String, String>(  );
213 
214         int nCount = 0;
215 
216         for ( Form form : _mapForms.values(  ) )
217         {
218             for ( SubForm subform : (Collection<SubForm>) form.getSubForm(  ).values(  ) )
219             {
220                 mapForms.put( Integer.toString( nCount ), form.getName(  ) + "-" + subform.getName(  ) );
221                 nCount++;
222             }
223         }
224 
225         return mapForms;
226     }
227 
228     /**
229      * Return the id of forms
230      * @param strFormName The name of the form
231      * @return the id of forms
232      */
233     public static String getIdForm( String strFormName )
234     {
235         String indexOfForm = DEFAULT_FORM_INDEX;
236         ReferenceList refListForm = FormsRegistrationService.getListForm(  );
237 
238         for ( ReferenceItem refItem : refListForm )
239         {
240             if ( ( refItem.getName(  ) ).equals( strFormName ) )
241             {
242                 indexOfForm = refItem.getCode(  );
243             }
244         }
245 
246         return indexOfForm;
247     }
248 
249     /**
250      * Notices initialization
251      */
252     public static void initNotices(  )
253     {
254         JAXBContext jaxbContextFormElements = null;
255         Plugin plugin = PluginService.getPlugin( PLUGIN_NAME );
256         String strPackageName = AppPropertiesService.getProperty( PROPERTY_FORMDEFINITION_PACKAGE_NAME );
257         Unmarshaller unmarshaller;
258 
259         try
260         {
261             jaxbContextFormElements = JAXBContext.newInstance( strPackageName );
262             unmarshaller = jaxbContextFormElements.createUnmarshaller(  );
263 
264             File dirPlugin = new File( AppPathService.getPath( PATH_FORM_DEFINITIONS ) );
265 
266             if ( ( dirPlugin != null ) && dirPlugin.exists(  ) )
267             {
268                 FilenameFilter select = new FileListFilter( "", EXTENSION_FILE );
269                 File[] listFile = dirPlugin.listFiles( select );
270 
271                 for ( int i = 0; i < listFile.length; i++ )
272                 {
273                     File file = listFile[i];
274 
275                     try
276                     {
277                         FormDefinition formDefinition = (FormDefinition) unmarshaller.unmarshal( file );
278                         DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(  );
279                         docBuilderFactory.setCoalescing( true );
280 
281                         DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(  );
282                         Document doc = docBuilder.parse( file );
283                         Notice notice = null;
284 
285                         doc.getDocumentElement(  ).normalize(  );
286 
287                         // Select the node noticeGroup
288                         NodeList noticesList = doc.getElementsByTagName( XML_NODE_NOTICE_GROUP );
289 
290                         for ( int j = 0; j < noticesList.getLength(  ); j++ )
291                         {
292                             notice = new Notice(  );
293 
294                             Element noticeNode = (Element) noticesList.item( j );
295 
296                             //NamedNodeMap nnm = noticeNode.getAttributes();
297 
298                             // Get the parameter "name" of noticeGroup node
299                             String strAttribute = "";
300 
301                             strAttribute += noticeNode.getAttribute( XML_ATTR_NAME );
302 
303                             // Get the parameter "name" of subFormDefinition node
304                             String strSubForm = "";
305                             strSubForm += ( (Element) noticeNode.getParentNode(  ).getParentNode(  ).getParentNode(  ) ).getAttribute( XML_ATTR_NAME );
306 
307                             // Build the name of the notice
308                             String strFormName = formDefinition.getName(  ) + "-" + strSubForm;
309                             String strNoticeName = formDefinition.getName(  ) + "-" + strSubForm + "-" + strAttribute;
310 
311                             // Get the value of the subNode
312                             String strValue = "";
313                             NodeList noticesTextList = noticeNode.getElementsByTagName( XML_NODE_NOTICE );
314 
315                             for ( int k = 0; k < noticesTextList.getLength(  ); k++ )
316                             {
317                                 Node noticeTextNode = noticesTextList.item( k );
318 
319                                 String strSubFormText = "";
320                                 strSubFormText += ( (Element) noticeTextNode.getParentNode(  ).getParentNode(  )
321                                                                             .getParentNode(  ).getParentNode(  ) ).getAttribute( XML_ATTR_NAME );
322 
323                                 if ( strSubFormText.equals( strSubForm ) )
324                                 {
325                                     if ( noticeTextNode.getFirstChild(  ).getNodeType(  ) == Node.TEXT_NODE )
326                                     {
327                                         strValue = noticeTextNode.getFirstChild(  ).getNodeValue(  );
328                                     }
329                                     else if ( noticeTextNode.getFirstChild(  ).getNodeType(  ) == Node.CDATA_SECTION_NODE )
330                                     {
331                                         CDATASection cdata = (CDATASection) noticeTextNode.getFirstChild(  );
332                                         strValue = cdata.getData(  );
333                                     }
334                                 }
335 
336                                 // Get index of current Form
337                                 String indexOfForm = getIdForm( strFormName );
338 
339                                 // Build the Notice Object
340                                 notice.setTitle( strNoticeName );
341                                 notice.setMessage( strValue );
342                                 notice.setWorkgroupKey( DEFAULT_WORKGROUP );
343                                 notice.setIdDiffusion( DEFAULT_ID_MAILING_LIST );
344 
345                                 //notice.setIdRss( DEFAULT_ID_RSS_LIST );
346                                 boolean bExist = false;
347 
348                                 NoticeGroupFilter filter = new NoticeGroupFilter(  );
349                                 filter.setForm( indexOfForm );
350 
351                                 List<NoticeGroup> noticeGroupList = NoticeGroupHome.findByFilter( filter, plugin );
352 
353                                 if ( noticeGroupList.isEmpty(  ) )
354                                 {
355                                     // create notice group [same values as notice]
356                                     NoticeGroup noticeGroup = new NoticeGroup(  );
357                                     noticeGroup.setForm( indexOfForm );
358                                     noticeGroup.setTitle( strNoticeName );
359                                     noticeGroup.setWorkgroupKey( DEFAULT_WORKGROUP );
360                                     noticeGroup.setEnabled( true );
361 
362                                     AppLogService.info( "Creating notice gruop for form " + formDefinition.getName(  ) +
363                                         "-" + strSubForm + " : " + noticeGroup.getTitle(  ) );
364                                     NoticeGroupHome.create( noticeGroup, plugin );
365 
366                                     // assign to created group
367                                     notice.setIdNoticeGroup( noticeGroup.getId(  ) );
368                                     AppLogService.info( "Creating notice for form " + formDefinition.getName(  ) + "-" +
369                                         strSubForm + " : " + notice.getMessage(  ) );
370                                     NoticeHome.create( notice, plugin );
371                                 }
372                                 else
373                                 {
374                                     for ( NoticeGroup noticeGroup : noticeGroupList )
375                                     {
376                                         NoticeFilter noticeFilter = new NoticeFilter(  );
377                                         noticeFilter.setIdNoticeGroup( noticeGroup.getId(  ) );
378 
379                                         List<Notice> listNotice = NoticeHome.getNoticeList( noticeFilter, plugin );
380 
381                                         for ( Notice n : listNotice )
382                                         {
383                                             if ( ( n.getMessage(  ).equals( notice.getMessage(  ) ) ) )
384                                             {
385                                                 bExist = true;
386                                             }
387                                         }
388                                     }
389 
390                                     if ( !bExist )
391                                     {
392                                         // assign to first found group
393                                         notice.setIdNoticeGroup( noticeGroupList.get( 0 ).getId(  ) );
394                                         AppLogService.info( "Creating notice for form " + formDefinition.getName(  ) +
395                                             "-" + strSubForm + " : " + notice.getMessage(  ) );
396                                         NoticeHome.create( notice, plugin );
397                                     }
398                                 }
399                             }
400                         }
401                     }
402                     catch ( SAXParseException err )
403                     {
404                         AppLogService.error( err );
405                     }
406                     catch ( SAXException e )
407                     {
408                         AppLogService.error( e );
409                     }
410                     catch ( Throwable t )
411                     {
412                         AppLogService.error( t );
413                     }
414                 }
415             }
416         }
417         catch ( JAXBException e )
418         {
419             AppLogService.error( PLUGIN_NAME.toUpperCase(  ) + " : " + e.getMessage(  ), e );
420         }
421     }
422     
423     /**
424      * Loads a {@link Forms} and its {@link SubForm} with the given file data.
425      * This method may be used to add dynamically a new form.
426      * <i>Do not forget that the form name should be unique.</i>
427      * @param fileFormDefinition the file containing form definition
428      * @throws JAXBException if an exception occur parsing the file
429      */
430     public static void loadForm( File fileFormDefinition ) throws JAXBException
431     {
432         loadForm( fileFormDefinition, getUnmarshaller(  ) );
433 
434     }
435     
436     /**
437      * Gets an unmarshaller
438      * @return the created unmarshaller
439      * @throws JAXBException if an error occur during creation
440      */
441     private static Unmarshaller getUnmarshaller(  ) throws JAXBException
442     {
443     	JAXBContext jaxbContextFormElements = null;
444         String strPackageName = AppPropertiesService.getProperty( PROPERTY_FORMDEFINITION_PACKAGE_NAME );
445         jaxbContextFormElements = JAXBContext.newInstance( strPackageName );
446         
447         return jaxbContextFormElements.createUnmarshaller(  );
448     }
449     
450     /**
451      * Gets the {@link FormDefinition} for the given file
452      * @param fileFormDefinition the file to parse
453      * @return the form definition
454      * @throws JAXBException if an error occurs parsing the file
455      */
456     public static FormDefinition getFormDefinition( File fileFormDefinition ) throws JAXBException
457     {
458     	return getFormDefinition( fileFormDefinition, getUnmarshaller() );
459     }
460     
461     /**
462      * Gets the {@link FormDefinition} for the given file
463      * @param fileFormDefinition the file to parse
464      * @param unmarshaller the unmarshaller 
465      * @return the form definition
466      * @throws JAXBException if an error occurs parsing the file
467      */
468     public static FormDefinition getFormDefinition( File fileFormDefinition, Unmarshaller unmarshaller ) throws JAXBException
469     {
470     	return (FormDefinition) unmarshaller.unmarshal( fileFormDefinition );
471     }
472     
473     /**
474      * Removes a {@link Form} from the map.
475      * This does <b>NOT</b> removes the files.
476      * @return <code>true</code> if the operation actually removed the form, <code>false</code> otherwise.
477      */
478     public static boolean unregisterForm( String strForm )
479     {
480     	return _mapForms.remove( strForm ) != null;
481     }
482     
483     /**
484      * Loads a {@link Forms} and its {@link SubForm} with the given file data.
485      * @param fileFormDefinition the file containing form definition
486      * @param unmarshaller the unmarshaller
487      */
488     private static void loadForm( File fileFormDefinition, Unmarshaller unmarshaller )
489     {
490         try
491         {
492             FormDefinition formDefinition = getFormDefinition( fileFormDefinition, unmarshaller );
493 
494             String strFormClassName = formDefinition.getClassName(  );
495 
496             Class<?> formClass = Class.forName( strFormClassName );
497             Class<?> stringClass = Class.forName( CLASS_NAME_STRING );
498             Constructor<?> formConstructor = formClass.getConstructor( new Class[] { stringClass } );
499             String strFormName = formDefinition.getName(  );
500             Form form = (Form) formConstructor.newInstance( (Object[]) new String[] { strFormName } );
501 
502             form.setTitle( formDefinition.getTitle(  ) );
503 
504             // retrieve the outputs
505             form.setOutputs( formDefinition.getOutputs(  ) );
506 
507             _mapForms.put( formDefinition.getName(  ), form );
508 
509             List<SubFormDefinition> listSubForms = formDefinition.getSubForms(  ).getSubFormDefinition(  );
510 
511             SubForm previousSubForm = null;
512 
513             for ( int index = 0; index < listSubForms.size(  ); index++ )
514             {
515                 SubFormDefinition subformDefinition = listSubForms.get( index );
516 
517                 String strSubFormClassName = subformDefinition.getClassName(  );
518                 SubForm subForm = (SubForm) Class.forName( strSubFormClassName ).newInstance(  );
519 
520                 subForm.setName( subformDefinition.getName(  ) );
521                 subForm.setTitle( subformDefinition.getTitle(  ) );
522 
523                 // keep the fields in order to initialise later the objets in session.
524                 subForm.initFormElements( (FormElements) subformDefinition.getFormElements(  ) );
525 
526                 subForm.setParentForm( form );
527                 form.addSubForm( subformDefinition.getName(  ), subForm );
528 
529                 if ( index == 0 )
530                 {
531                     form.setFirstSubForm( subForm );
532                 }
533 
534                 subForm.setPreviousSubForm( previousSubForm );
535 
536                 if ( previousSubForm != null )
537                 {
538                     previousSubForm.setNextSubForm( subForm );
539                 }
540 
541                 previousSubForm = subForm;
542             }
543         }
544         catch ( Exception e )
545         {
546             AppLogService.error( PLUGIN_NAME.toUpperCase(  ) + " : " + e.getMessage(  ), e );
547         }
548 
549     }
550 }