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.web;
35  
36  import java.io.StringWriter;
37  import java.net.URL;
38  import java.sql.Date;
39  import java.sql.Time;
40  import java.util.ArrayList;
41  import java.util.Collection;
42  import java.util.Collections;
43  import java.util.Enumeration;
44  import java.util.HashMap;
45  import java.util.List;
46  import java.util.Locale;
47  import java.util.Map;
48  
49  import javax.servlet.http.HttpServletRequest;
50  import javax.servlet.http.HttpSession;
51  import javax.xml.bind.JAXBContext;
52  import javax.xml.bind.JAXBException;
53  import javax.xml.bind.Marshaller;
54  import javax.xml.bind.Validator;
55  import javax.xml.validation.Schema;
56  import javax.xml.validation.SchemaFactory;
57  
58  import org.apache.commons.fileupload.FileItem;
59  import org.xml.sax.SAXException;
60  
61  import fr.paris.lutece.plugins.formengine.business.jaxb.formdefinition.Output;
62  import fr.paris.lutece.plugins.formengine.business.jaxb.formdefinition.OutputSet;
63  import fr.paris.lutece.plugins.formengine.business.jaxb.formdefinition.Outputs;
64  import fr.paris.lutece.plugins.formengine.business.jaxb.transaction.ObjectFactory;
65  import fr.paris.lutece.plugins.formengine.business.jaxb.transaction.SenderInfo;
66  import fr.paris.lutece.plugins.formengine.business.jaxb.transaction.ServerInfo;
67  import fr.paris.lutece.plugins.formengine.business.jaxb.transaction.Transaction;
68  import fr.paris.lutece.plugins.formengine.business.jaxb.transaction.TransactionData;
69  import fr.paris.lutece.plugins.formengine.business.jaxb.transaction.TransactionInfo;
70  import fr.paris.lutece.plugins.formengine.service.draft.DraftBackupService;
71  import fr.paris.lutece.plugins.formengine.service.output.GeneratorFactory;
72  import fr.paris.lutece.plugins.formengine.service.output.IdGenerator;
73  import fr.paris.lutece.plugins.formengine.service.output.OutputFactory;
74  import fr.paris.lutece.plugins.formengine.service.output.OutputProcessor;
75  import fr.paris.lutece.plugins.formengine.service.output.TransactionFileIdGenerator;
76  import fr.paris.lutece.plugins.formengine.service.parameter.FormEngineParameterService;
77  import fr.paris.lutece.plugins.formengine.util.JSONUtils;
78  import fr.paris.lutece.portal.service.message.SiteMessageException;
79  import fr.paris.lutece.portal.service.security.UserNotSignedException;
80  import fr.paris.lutece.portal.service.util.AppException;
81  import fr.paris.lutece.portal.service.util.AppLogService;
82  import fr.paris.lutece.portal.service.util.AppPropertiesService;
83  import fr.paris.lutece.util.ReferenceItem;
84  import fr.paris.lutece.util.date.DateUtil;
85  
86  
87  /**
88   * This classe defines the main characteristics and methods of a form
89   */
90  public abstract class Form
91  {
92      public static final String RESOURCE_TYPE = "FORMENGINE";
93      private static final String SESSION_ATTRIBUTE_FORM_DOCUMENT = "FORM_DOCUMENT";
94      private static final String SESSION_ATTRIBUTE_TRANSACTION_ID = "TRANSACTION_ID";
95      private static final String SESSION_ATTRIBUTE_FORM_ERRORS = "ERRORS";
96      private static final String SESSION_ATTRIBUTE_BLOCK_PROCESSING = "BLOCK_PROCESS";
97      private static final String PROPERTY_FORMDEFINITION_PACKAGE_NAME = "formengine.jaxb.packagename.formdefinition";
98      private static final String PROPERTY_TRANSACTION_PACKAGE_NAME = "formengine.jaxb.packagename.transaction";
99      private static final String SEPARATOR_PACKAGE = ":";
100     private static final String PARAMETER_DATE_BEGIN = "_date_begin";
101     private static final String PARAMETER_DATE_END = "_date_end";
102 
103     /**
104      * FIXME : WORKAROUND -- should use
105      * {@link javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI} instead.
106      * JSR173 jar overrides javax.xml.XMLConstants and does not provide
107      * W3C_XML_SCHEMA_NS_URI.
108      * Resolution error could occur at runtime.
109      * @see <a
110      *      href="http://dev.lutece.paris.fr/jira/browse/FORMENGINE-22">FORMENGINE-22</a>
111      * 
112      */
113     private static final String W3C_XML_SCHEMA_NS_URI = "http://www.w3.org/2001/XMLSchema";
114     private String _strTitle;
115     private String _strName;
116     private SubForm _subformFirst;
117     private Map<String, SubForm> _subForms;
118 
119     /** <subform,<sessionId,<fieldName,fileItems>>> */
120     private Map<String, Map<String, Map<String, List<FileItem>>>> _mapAsynchronousUploads = new HashMap<String, Map<String, Map<String, List<FileItem>>>>( );
121     private Outputs _outputs;
122     private JAXBContext _jaxbSpecificContext;
123     private JAXBContext _jaxbContextFormElements;
124     private Schema _javaxXsdSchema;
125     private DraftBackupService _draftBackupService;
126 
127     /**
128      * Constructor
129      * @param strFormName name of form
130      */
131     public Form( String strFormName )
132     {
133         this.setName( strFormName );
134 
135         try
136         {
137             String strTransactionPackageName = AppPropertiesService.getProperty( PROPERTY_TRANSACTION_PACKAGE_NAME );
138             String strContext = this.getGeneratedPackageName( ) + SEPARATOR_PACKAGE + strTransactionPackageName;
139             // create context for specific xml generation
140             _jaxbSpecificContext = JAXBContext.newInstance( strContext );
141 
142             // jaxb context for forms display and modification
143             String strFormElementsPackageName = AppPropertiesService.getProperty( PROPERTY_FORMDEFINITION_PACKAGE_NAME );
144             _jaxbContextFormElements = JAXBContext.newInstance( strFormElementsPackageName );
145         }
146         catch ( JAXBException ex )
147         {
148             throw new AppException( "Formengine : an error occurred while instancing the form : " + strFormName, ex );
149         }
150 
151         _subForms = new HashMap( );
152     }
153 
154     /**
155      * Set the XSD schema
156      * @param strSchemaPath The path of schema
157      */
158     public void setXSDSchema( String strSchemaPath )
159     {
160         if ( strSchemaPath != null )
161         {
162             try
163             {
164                 // FIXME : use : javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI
165                 // currently [jre1.5] : http://www.w3.org/2001/XMLSchema
166                 //init schema
167                 SchemaFactory sf = SchemaFactory.newInstance( W3C_XML_SCHEMA_NS_URI );
168 
169                 URL xsdUrl = this.getClass( ).getClassLoader( ).getResource( strSchemaPath );
170                 _javaxXsdSchema = sf.newSchema( xsdUrl );
171             }
172             catch ( SAXException ex )
173             {
174                 AppLogService.info( "Schema not loaded : '" + strSchemaPath + "', cause :" + ex.getLocalizedMessage( ) );
175             }
176         }
177     }
178 
179     ////////////////////////////////////////////////////////////////////////////
180     // Abstract methods
181     /**
182      * This method should be overriden.
183      * It defines the absolute path of the directory where are stored the xsl
184      * files
185      * @return The absolute path for xsl stylesheets
186      */
187     public abstract String getXslDirectoryPath( );
188 
189     /**
190      * This method should be overriden to indicate the home package name of the
191      * classes generated by JAXB. This refers to the classes responsible for
192      * generating
193      * the specific part of the output xml file.
194      * @return the fully qualified package name
195      */
196     protected abstract String getGeneratedPackageName( );
197 
198     /**
199      * This method should be overriden to indicate the code of the transaction
200      * @return the transaction code for a given form
201      */
202     public abstract String getTransactionCode( );
203 
204     /**
205      * This method should be overriden to indicate the instance name
206      * @return the instance name for a given form
207      */
208     public abstract String getInstanceName( );
209 
210     /**
211      * This method should be overriden to indicate the name of the transaction
212      * @return the transaction name for a given form
213      */
214     public abstract String getTransactionName( );
215 
216     ////////////////////////////////////////////////////////////////////////////
217     // Default implementation
218     /**
219      * Get the name of the form
220      * @return the subform title
221      */
222     public String getName( )
223     {
224         return _strName;
225     }
226 
227     /**
228      * Set the name of the form
229      * @param strName the name to set
230      */
231     public final void setName( String strName )
232     {
233         _strName = strName;
234     }
235 
236     /**
237      * Get the title of the form
238      * @return the subform title
239      */
240     public String getTitle( )
241     {
242         return _strTitle;
243     }
244 
245     /**
246      * Set the title of the form
247      * @param strTitle the title to set
248      */
249     public void setTitle( String strTitle )
250     {
251         _strTitle = strTitle;
252     }
253 
254     /**
255      * Get the outputs of the form
256      * @return the subform outputs
257      */
258     public Outputs getOutputs( )
259     {
260         return _outputs;
261     }
262 
263     /**
264      * Set the outputs of the form
265      * @param outputs the outputs to set
266      */
267     public void setOutputs( Outputs outputs )
268     {
269         _outputs = outputs;
270     }
271 
272     /**
273      * Get the transaction Id in session
274      * @param request the http request
275      * @return the transaction id
276      */
277     public String getTransactionId( HttpServletRequest request )
278     {
279         return (String) this.getSessionAttribute( request, SESSION_ATTRIBUTE_TRANSACTION_ID );
280     }
281 
282     /**
283      * Set the transaction Id in session
284      * @param request the http request
285      * @param strTransactionId the transactionid
286      */
287     public void setTransactionId( HttpServletRequest request, String strTransactionId )
288     {
289         setSessionAttribute( request, SESSION_ATTRIBUTE_TRANSACTION_ID, strTransactionId );
290     }
291 
292     /**
293      * This method returns a SubForm from a given name
294      * @param strName The name of the SubForm to retrieve
295      * @return The SubForm object or null of not found
296      */
297     public SubForm getSubForm( String strName )
298     {
299         return (SubForm) _subForms.get( strName );
300     }
301 
302     /**
303      * This method returns all SubForm
304      * @return The Map of Subform object or null of not found
305      */
306     public Map getSubForm( )
307     {
308         return _subForms;
309     }
310 
311     /**
312      * Add a subform to the current form
313      * @param strName The SubForm name
314      * @param subForm The SubForm object
315      */
316     public void addSubForm( String strName, SubForm subForm )
317     {
318         _subForms.put( strName, subForm );
319     }
320 
321     /**
322      * This method is used to defined the first SubForm of the form.
323      * This subform is the default subform if the request parameter is not
324      * defined.
325      * @param subform The first SubForm
326      */
327     public void setFirstSubForm( SubForm subform )
328     {
329         _subformFirst = subform;
330     }
331 
332     /**
333      * This method returns the first SubForm of the form.
334      * This subform is the default subform if the request parameter is not
335      * defined.
336      * @return The first SubForm
337      */
338     public SubForm getFirstSubForm( )
339     {
340         return _subformFirst;
341     }
342 
343     /**
344      * This method build an XML document from a given object.
345      * The object must have been generated by JAXB and be part
346      * of the specific package.
347      * @param object The object to marshall
348      * @return The XML built as a String
349      */
350     public String getXml( Object object )
351     {
352         String strXml = "";
353 
354         if ( object == null )
355         {
356             return strXml;
357         }
358 
359         try
360         {
361             StringWriter writer = new StringWriter( );
362             Marshaller marshaller = _jaxbSpecificContext.createMarshaller( );
363             marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
364             marshaller.marshal( object, writer );
365             strXml = writer.toString( );
366         }
367         catch ( JAXBException e )
368         {
369             throw new AppException( "Formengine : an error occurred during marshalling for the form : "
370                     + this.getName( ), e );
371         }
372 
373         return strXml;
374     }
375 
376     /**
377      * This method retruns the root element containing the form data.
378      * @param request The HTTP Request
379      * @return The root element as an object
380      */
381     public Object getFormDocument( HttpServletRequest request )
382     {
383         // Retrieve the object from a session attribute
384         Object object = this.getSessionAttribute( request, SESSION_ATTRIBUTE_FORM_DOCUMENT );
385 
386         if ( object == null )
387         {
388             AppLogService.info( "FORMENGINE : FormDocument retrieved is null" );
389         }
390 
391         return object;
392     }
393 
394     /**
395      * Allow/forbid access to a subform given its name
396      * @param request the httm request
397      * @param strSubFormName the name of the subform to state access of
398      * @param bIsSubFormAllowed true if the subform access should be allowed,
399      *            false otherwise
400      */
401     public void setIsAccessToSubFormAllowed( HttpServletRequest request, String strSubFormName,
402             boolean bIsSubFormAllowed )
403     {
404         SubForm subform = this.getSubForm( strSubFormName );
405 
406         if ( subform != null )
407         {
408             subform.setIsSubFormAllowed( request, bIsSubFormAllowed );
409         }
410     }
411 
412     /**
413      * Check that the access to a subform is allowed.
414      * This implies that the access to all previous subforms has been allowed.
415      * @param request the http request
416      * @param strSubFormName the name of the subform to check access of
417      * @return Subform is allowed
418      * @throws UserNotSignedException if user must be signed on
419      */
420     public boolean checkIsAccessToSubFormAllowed( HttpServletRequest request, String strSubFormName )
421             throws UserNotSignedException
422     {
423         SubForm subform = this.getSubForm( strSubFormName );
424         boolean bAllowed = false;
425 
426         while ( ( subform != null ) )
427         {
428             bAllowed = subform.getIsSubFormAllowed( request );
429 
430             if ( !bAllowed )
431             {
432                 break;
433             }
434 
435             subform = subform.getPreviousSubForm( );
436         }
437 
438         return bAllowed;
439     }
440 
441     /**
442      * This method sets the object corresponding to the root element of the form
443      * @param request The HTTP request
444      * @param object The root element of the form data.
445      */
446     public void setFormDocument( HttpServletRequest request, Object object )
447     {
448         // Store the object in a session attribute
449         this.setSessionAttribute( request, SESSION_ATTRIBUTE_FORM_DOCUMENT, object );
450     }
451 
452     /**
453      * This method provides the XML document corresponding to the form specific
454      * data.
455      * @param request The HTTP request
456      * @return The XML document as a String, ie the xml stream correponding to
457      *         the root specific element
458      */
459     public String getXmlFormDocument( HttpServletRequest request )
460     {
461         return getXml( getFormDocument( request ) );
462     }
463 
464     /**
465      * This method provides a validator to check data stored in
466      * the generated classes according the XML schema.
467      * @throws JAXBException If JAXB Error occurs
468      * @return A validator object
469      */
470     public Validator getXmlValidator( ) throws JAXBException
471     {
472         return _jaxbSpecificContext.createValidator( );
473     }
474 
475     /**
476      * This method provides a marshaller to create an XML document from
477      * the generated classes
478      * @throws JAXBException If JAXB Error occurs
479      * @return A marshaller object
480      */
481     public Marshaller getXmlMarshaller( ) throws JAXBException
482     {
483         Marshaller marshaller = _jaxbSpecificContext.createMarshaller( );
484 
485         if ( _javaxXsdSchema != null )
486         {
487             //add xsd schema
488             marshaller.setSchema( _javaxXsdSchema );
489         }
490 
491         return marshaller;
492     }
493 
494     /**
495      * This method process the form. It should called by the last subform after
496      * the final validation.
497      * @param request The HTTP request
498      * 
499      */
500     public void processForm( HttpServletRequest request )
501     {
502         // test if generation has already be done (protect from back)
503         Boolean bForbidden = (Boolean) this.getSessionAttribute( request, SESSION_ATTRIBUTE_BLOCK_PROCESSING );
504 
505         // fix case where session has been flushed : the parameter in session is null but access to
506         // output generation should not be granted.
507         // Thus, if the form document is null also, this means that session has been flushed :
508         // Access to output generation is not granted
509         if ( ( bForbidden == null ) && ( this.getFormDocument( request ) == null ) )
510         {
511             bForbidden = Boolean.TRUE;
512         }
513 
514         if ( ( bForbidden == null ) || ( !bForbidden.booleanValue( ) ) )
515         {
516             Outputs outputs = this.getOutputs( );
517 
518             for ( OutputSet outputSet : outputs.getOutputSet( ) )
519             {
520                 boolean bUseHeader = outputSet.isUseTransactionHeaders( );
521 
522                 Object transactionObject;
523 
524                 // if we use header, init the transaction object and generate xml
525                 if ( bUseHeader )
526                 {
527                     IdGenerator idGenerator;
528 
529                     // the transaction id generator might have been customized
530                     String strSpecificTransactionIdGenerator = outputSet.getSpecificTransactionIdGeneratorClassName( );
531 
532                     if ( ( strSpecificTransactionIdGenerator != null )
533                             && ( !strSpecificTransactionIdGenerator.trim( ).equals( "" ) ) )
534                     {
535                         idGenerator = GeneratorFactory.getGenerator( strSpecificTransactionIdGenerator );
536                     }
537                     else
538                     {
539                         // if no custom id generator, use default one
540                         idGenerator = GeneratorFactory.getGenerator( TransactionFileIdGenerator.class.getName( ) );
541                     }
542 
543                     // the generator might need to know the form name
544                     String strNewId = idGenerator.getNewId( this );
545 
546                     // put the transactionId in session for display
547                     this.setTransactionId( request, strNewId );
548 
549                     // initialise transaction object
550                     Transaction transaction = this.initializeTransactionHeaders( request );
551 
552                     // set the id
553                     transaction.setTransactionId( strNewId );
554 
555                     // insert the specific document into the transaction
556                     ObjectFactory factory = new ObjectFactory( );
557                     TransactionData data = factory.createTransactionData( );
558                     data.setAny( getFormDocument( request ) );
559                     transaction.setTransactionData( data );
560                     transactionObject = transaction;
561                 }
562                 else
563                 // generate specific xml if no header
564                 {
565                     transactionObject = this.getFormDocument( request );
566                 }
567 
568                 // get all the output element of this outputSet
569                 Collection<Output> colOutputs = outputSet.getOutput( );
570 
571                 for ( Output output : colOutputs )
572                 {
573                     String strOutputClassName = output.getOutputProcessorClassName( );
574 
575                     OutputProcessor ouputProcessor = OutputFactory.getOutput( strOutputClassName );
576                     ouputProcessor.process( this, transactionObject );
577                 }
578             }
579 
580             // successed : prevent from coming back here
581             this.setSessionAttribute( request, SESSION_ATTRIBUTE_BLOCK_PROCESSING, Boolean.TRUE );
582         }
583     }
584 
585     /**
586      * 
587      * @param request the HTTP request
588      * @return Transaction
589      */
590     Transaction initializeTransactionHeaders( HttpServletRequest request )
591     {
592         ObjectFactory factory = new ObjectFactory( );
593 
594         SenderInfo sender = factory.createSenderInfo( );
595         sender.setRemoteAddress( request.getRemoteAddr( ) );
596 
597         String strUser = this.getRemoteUser( request );
598 
599         if ( strUser != null )
600         {
601             sender.setRemoteUser( strUser );
602         }
603         else
604         {
605             sender.setRemoteUser( "" );
606         }
607 
608         ServerInfo server = factory.createServerInfo( );
609         String strInstanceName = this.getInstanceName( );
610         server.setInstanceName( strInstanceName );
611 
612         TransactionInfo tInfo = factory.createTransactionInfo( );
613         tInfo.setTransactionCode( this.getTransactionCode( ) );
614         tInfo.setTransactionName( this.getTransactionName( ) );
615 
616         Transaction transaction = factory.createTransaction( );
617         transaction.setSenderInfo( sender );
618         transaction.setServerInfo( server );
619         transaction.setTransactionInfo( tInfo );
620 
621         // generate the date and time of the transaction
622         Date currentSqlDate = new Date( System.currentTimeMillis( ) );
623         Time currentSqlTime = new Time( System.currentTimeMillis( ) );
624         transaction.setTransactionDate( currentSqlDate );
625         transaction.setTransactionTime( currentSqlTime );
626 
627         return transaction;
628     }
629 
630     /**
631      * This method returns the user of the request. The default implementation
632      * returns the getRemoteUser of the request.
633      * 
634      * @param request The HTTP request
635      * @return The user as a String
636      */
637     public String getRemoteUser( HttpServletRequest request )
638     {
639         return request.getRemoteUser( );
640     }
641 
642     /**
643      * Add an error to the current session
644      * @param request The HTTP request
645      * @param strErrorKey The error key defined in a properties file
646      */
647     public void addError( HttpServletRequest request, String strErrorKey )
648     {
649         this.addError( request, strErrorKey, null );
650     }
651 
652     /**
653      * Add an error to the current session, completing the message in property
654      * with a parameter
655      * @param request The HTTP request
656      * @param strErrorKey The error key defined in a properties file
657      * @param strParameter The parameter to insert
658      */
659     public void addError( HttpServletRequest request, String strErrorKey, String strParameter )
660     {
661         FormErrorsList errors = (FormErrorsList) this.getSessionAttribute( request, SESSION_ATTRIBUTE_FORM_ERRORS );
662 
663         if ( errors == null )
664         {
665             errors = new FormErrorsList( );
666         }
667 
668         errors.addError( strErrorKey, strParameter );
669         setSessionAttribute( request, SESSION_ATTRIBUTE_FORM_ERRORS, errors );
670     }
671 
672     /**
673      * Add an error to the current session, completing the message in property
674      * with a parameter
675      * @param request The HTTP request
676      * @param strErrorMessage The error message
677      */
678     public void addErrorMessage( HttpServletRequest request, String strErrorMessage )
679     {
680         FormErrorsList errors = (FormErrorsList) this.getSessionAttribute( request, SESSION_ATTRIBUTE_FORM_ERRORS );
681 
682         if ( errors == null )
683         {
684             errors = new FormErrorsList( );
685         }
686 
687         errors.addErrorMessage( strErrorMessage );
688         setSessionAttribute( request, SESSION_ATTRIBUTE_FORM_ERRORS, errors );
689     }
690 
691     /**
692      * Reset all filling errors associated to the session
693      * @param request The HTTP request
694      */
695     public void resetErrors( HttpServletRequest request )
696     {
697         FormErrorsList errors = (FormErrorsList) this.getSessionAttribute( request, SESSION_ATTRIBUTE_FORM_ERRORS );
698 
699         if ( errors != null )
700         {
701             errors.clear( );
702         }
703 
704         setSessionAttribute( request, SESSION_ATTRIBUTE_FORM_ERRORS, errors );
705     }
706 
707     /**
708      * Returns all filling errors associated to the session.
709      * @param request the HTTP request
710      * @return errors
711      */
712     public String[] getErrors( HttpServletRequest request )
713     {
714         FormErrorsList list = (FormErrorsList) this.getSessionAttribute( request, SESSION_ATTRIBUTE_FORM_ERRORS );
715 
716         if ( list == null )
717         {
718             return null;
719         }
720 
721         String[] errors = new String[list.size( )];
722 
723         for ( int i = 0; i < list.size( ); i++ )
724         {
725             errors[i] = (String) list.get( i );
726         }
727 
728         return errors;
729     }
730 
731     /**
732      * This method provides a marshaller to create a subform page
733      * from the form definition classes
734      * @return A marshaller object
735      * @throws JAXBException If JAXB Error occurs
736      */
737     public Marshaller getFormElementsMarshaller( ) throws JAXBException
738     {
739         return _jaxbContextFormElements.createMarshaller( );
740     }
741 
742     /**
743      * 
744      * @param request the HTTP request
745      * @param strAttributeName the name of attribute
746      * @param attribute Attributes
747      */
748     public void setSessionAttribute( HttpServletRequest request, String strAttributeName, Object attribute )
749     {
750         HttpSession session = request.getSession( true );
751         String strPrefix = SharedConstants.SESSION_PREFIX + "_" + this.getName( ) + "_";
752         String strSessionAttribute = strPrefix + strAttributeName.trim( );
753         strSessionAttribute = strSessionAttribute.toUpperCase( );
754         session.setAttribute( strSessionAttribute, attribute );
755     }
756 
757     /**
758      * 
759      * @param request the HTTP request
760      * @param strAttributeName the name of attribute
761      * @return the object associated to attribute in session
762      */
763     public Object getSessionAttribute( HttpServletRequest request, String strAttributeName )
764     {
765         HttpSession session = request.getSession( true );
766         String strPrefix = SharedConstants.SESSION_PREFIX + "_" + this.getName( ) + "_";
767         String strSessionAttribute = strPrefix + strAttributeName.trim( );
768         strSessionAttribute = strSessionAttribute.toUpperCase( );
769 
770         return session.getAttribute( strSessionAttribute );
771     }
772 
773     /**
774      * 
775      * @param request the HTTP request
776      * @param strAttributeName the name of attribute
777      */
778     public void removeSessionAttribute( HttpServletRequest request, String strAttributeName )
779     {
780         HttpSession session = request.getSession( true );
781         String strPrefix = SharedConstants.SESSION_PREFIX + "_" + this.getName( ) + "_";
782         String strSessionAttribute = strPrefix + strAttributeName.trim( );
783         strSessionAttribute = strSessionAttribute.toUpperCase( );
784         session.removeAttribute( strSessionAttribute );
785     }
786 
787     /**
788      * Invalidate the session.
789      * The main use should be to close the session
790      * when the form has been processed
791      * @param request the HTTP request
792      */
793     public void flushSession( HttpServletRequest request )
794     {
795         HttpSession session = request.getSession( true );
796 
797         String strPrefix = SharedConstants.SESSION_PREFIX + "_" + this.getName( ) + "_";
798         strPrefix = strPrefix.toUpperCase( );
799 
800         Enumeration names = session.getAttributeNames( );
801         Collection<String> luteceNamesCol = new ArrayList<String>( );
802 
803         while ( names.hasMoreElements( ) )
804         {
805             String strName = (String) names.nextElement( );
806 
807             if ( strName.startsWith( strPrefix ) )
808             {
809                 luteceNamesCol.add( strName );
810             }
811         }
812 
813         for ( String strName : luteceNamesCol )
814         {
815             session.removeAttribute( strName );
816         }
817     }
818 
819     /**
820      * Sets the Draft Backup Service
821      * @param service he Draft Backup Service
822      */
823     public void setDraftBackupService( DraftBackupService service )
824     {
825         _draftBackupService = service;
826     }
827 
828     /**
829      * Save the document as a draft
830      * @param request The HTTP request
831      */
832     public void saveDraft( HttpServletRequest request )
833     {
834         if ( _draftBackupService != null )
835         {
836             _draftBackupService.saveDraft( request, this );
837         }
838     }
839 
840     /**
841      * Validate a draft
842      * @param request The HTTP request
843      * @param form The form
844      */
845     public void validateDraft( HttpServletRequest request, Form form )
846     {
847         if ( _draftBackupService != null )
848         {
849             _draftBackupService.validateDraft( request, form );
850         }
851     }
852 
853     /**
854      * Get fields data as a blob object
855      * @param request The HTTP request
856      * @return A blob object
857      */
858     public byte[] getBlob( HttpServletRequest request )
859     {
860         return JSONUtils.buildJson( this, request ).getBytes( );
861     }
862 
863     /**
864      * Check whether the form is open or not
865      * @param locale the Locale
866      * @return true if the form is open, false otherwise
867      */
868     public boolean isOpen( Locale locale )
869     {
870         boolean bIsDateBeginCorrect = false;
871         boolean bIsDateEndCorrect = false;
872         ReferenceItem itemDateBegin = FormEngineParameterService.getService( ).getParamDefaultValue(
873                 getName( ) + PARAMETER_DATE_BEGIN );
874         ReferenceItem itemDateEnd = FormEngineParameterService.getService( ).getParamDefaultValue(
875                 getName( ) + PARAMETER_DATE_END );
876 
877         java.util.Date dateBegin = null;
878         java.util.Date dateEnd = null;
879         java.util.Date dateToday = new java.util.Date( );
880 
881         if ( itemDateBegin != null )
882         {
883             String strDateBegin = itemDateBegin.getName( );
884             dateBegin = DateUtil.formatDateLongYear( strDateBegin, locale );
885 
886             if ( dateBegin != null )
887             {
888                 if ( dateBegin.before( dateToday ) )
889                 {
890                     bIsDateBeginCorrect = true;
891                 }
892             }
893             else
894             {
895                 bIsDateBeginCorrect = true;
896             }
897         }
898         else
899         {
900             bIsDateBeginCorrect = true;
901         }
902 
903         if ( itemDateEnd != null )
904         {
905             String strDateEnd = itemDateEnd.getName( );
906             dateEnd = DateUtil.formatDateLongYear( strDateEnd, locale );
907 
908             if ( dateEnd != null )
909             {
910                 if ( dateEnd.after( dateToday ) )
911                 {
912                     bIsDateEndCorrect = true;
913                 }
914             }
915             else
916             {
917                 bIsDateEndCorrect = true;
918             }
919         }
920         else
921         {
922             bIsDateEndCorrect = true;
923         }
924 
925         return bIsDateBeginCorrect && bIsDateEndCorrect;
926     }
927 
928     /**
929      * Check whether the form is closed or not
930      * @param locale the Locale
931      * @return true if the form is closed, false otherwise
932      */
933     public boolean isClosed( Locale locale )
934     {
935         return !isOpen( locale );
936     }
937 
938     /**
939      * Pre process request
940      * @param request The Http request
941      * @return True if the request has been processed, no need to
942      *         follow.Otherwise false
943      * @throws SiteMessageException If an error occurs
944      */
945     boolean preprocessRequest( HttpServletRequest request ) throws SiteMessageException
946     {
947         if ( _draftBackupService != null )
948         {
949             return _draftBackupService.preProcessRequest( request, this );
950         }
951 
952         return false;
953     }
954 
955     /**
956      * Removes a session from temporary asynchronous uploads
957      * @param strSessionId the session id
958      */
959     public void removeSession( String strSessionId )
960     {
961         for ( Map<String, Map<String, List<FileItem>>> mapAsynchonousUploadsSubForm : _mapAsynchronousUploads.values( ) )
962         {
963             // delete temporary files
964             Map<String, List<FileItem>> map = mapAsynchonousUploadsSubForm.remove( strSessionId );
965 
966             if ( map != null )
967             {
968                 for ( List<FileItem> listFiles : map.values( ) )
969                 {
970                     for ( FileItem fileItem : listFiles )
971                     {
972                         fileItem.delete( );
973                     }
974                 }
975             }
976         }
977     }
978 
979     /**
980      * For asynchronous usage - adds the fileitem to the underlying file items
981      * map
982      * @param strIdSession the session id
983      * @param strFieldName the field name
984      * @param fileItem the file item
985      */
986     public final void addFileItem( String strSubForm, String strIdSession, String strFieldName, FileItem fileItem )
987     {
988         // Build the attribute name and instantiate the object if none exists yet
989         String strAttributeName = SharedConstants.FILELIST_PREFIX + strFieldName;
990         Map<String, Map<String, List<FileItem>>> mapAsynchronousUploadedFilesSubForm = _mapAsynchronousUploads
991                 .get( strSubForm );
992 
993         if ( mapAsynchronousUploadedFilesSubForm == null )
994         {
995             mapAsynchronousUploadedFilesSubForm = new HashMap<String, Map<String, List<FileItem>>>( );
996             _mapAsynchronousUploads.put( strSubForm, mapAsynchronousUploadedFilesSubForm );
997         }
998 
999         Map<String, List<FileItem>> mapUploadAttributes = mapAsynchronousUploadedFilesSubForm.get( strIdSession );
1000 
1001         if ( mapUploadAttributes == null )
1002         {
1003             mapUploadAttributes = new HashMap<String, List<FileItem>>( );
1004             mapAsynchronousUploadedFilesSubForm.put( strIdSession, mapUploadAttributes );
1005         }
1006 
1007         List<FileItem> listFiles = mapUploadAttributes.get( strAttributeName );
1008 
1009         if ( listFiles == null )
1010         {
1011             listFiles = new ArrayList<FileItem>( );
1012             mapUploadAttributes.put( strAttributeName, listFiles );
1013         }
1014 
1015         listFiles.add( fileItem );
1016     }
1017 
1018     /**
1019      * Gets the file item list for the session id
1020      * @param strSubForm the subform
1021      * @param strSessionId the session id
1022      * @param strFieldName the field name
1023      * @return the file items found, <code>Collections.emptyList()</code>
1024      *         otherwise.
1025      */
1026     public List<FileItem> getAsynchronousUploadedFiles( String strSubForm, String strSessionId, String strFieldName )
1027     {
1028         List<FileItem> listFileItems;
1029         String strAttributeName = SharedConstants.FILELIST_PREFIX + strFieldName;
1030         Map<String, Map<String, List<FileItem>>> mapAsynchronousUploadedFilesSubForm = _mapAsynchronousUploads
1031                 .get( strSubForm );
1032 
1033         if ( mapAsynchronousUploadedFilesSubForm != null )
1034         {
1035             Map<String, List<FileItem>> mapSessionUploadedFiles = mapAsynchronousUploadedFilesSubForm
1036                     .get( strSessionId );
1037 
1038             if ( mapSessionUploadedFiles != null )
1039             {
1040                 listFileItems = mapSessionUploadedFiles.get( strAttributeName );
1041 
1042                 if ( listFileItems == null )
1043                 {
1044                     listFileItems = Collections.emptyList( );
1045                 }
1046             }
1047             else
1048             {
1049                 listFileItems = Collections.emptyList( );
1050             }
1051         }
1052         else
1053         {
1054             listFileItems = Collections.emptyList( );
1055         }
1056 
1057         return listFileItems;
1058     }
1059 }