View Javadoc

1   /**
2    * - Digitalis Internal Framework v2.0 - (C) 2007, Digitalis Informatica. Distribuicao e Gestao de Informatica, Lda.
3    * Estrada de Paco de Arcos num.9 - Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21 4408999
4    * http://www.digitalis.pt
5    */
6   package pt.digitalis.dif.dem.objects.parameters.types;
7   
8   import java.util.ArrayList;
9   import java.util.HashMap;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.Map.Entry;
13  
14  import pt.digitalis.dif.controller.http.HTTPConstants;
15  import pt.digitalis.dif.controller.interfaces.IDIFContext;
16  import pt.digitalis.dif.controller.interfaces.IDIFSession;
17  import pt.digitalis.dif.controller.security.objects.IDIFUser;
18  import pt.digitalis.dif.dem.Entity;
19  import pt.digitalis.dif.dem.annotations.parameter.Rule;
20  import pt.digitalis.dif.dem.interfaces.IStageInstance;
21  import pt.digitalis.dif.dem.managers.IMessageManager;
22  import pt.digitalis.dif.dem.objects.messages.MessageList;
23  import pt.digitalis.dif.dem.objects.parameters.IEditableParameter;
24  import pt.digitalis.dif.dem.objects.parameters.IParameter;
25  import pt.digitalis.dif.dem.objects.parameters.ParameterScope;
26  import pt.digitalis.dif.dem.objects.parameters.constraints.IParameterConstraint;
27  import pt.digitalis.dif.dem.objects.parameters.constraints.ParameterConstraintResult;
28  import pt.digitalis.dif.dem.objects.parameters.errors.ParameterError;
29  import pt.digitalis.dif.dem.objects.parameters.errors.ParameterErrorList;
30  import pt.digitalis.dif.dem.objects.parameters.errors.ParameterErrorType;
31  import pt.digitalis.dif.dem.objects.parameters.rules.IParameterRule;
32  import pt.digitalis.dif.dem.objects.parameters.rules.ParameterRuleResult;
33  import pt.digitalis.dif.dem.objects.parameters.validators.IParameterValidator;
34  import pt.digitalis.dif.exception.objects.ParameterException;
35  import pt.digitalis.dif.ioc.DIFIoCRegistry;
36  import pt.digitalis.dif.startup.DIFGeneralConfigurationParameters;
37  import pt.digitalis.dif.utils.ObjectFormatter;
38  import pt.digitalis.dif.utils.extensions.document.DocumentRepositoryEntry;
39  import pt.digitalis.dif.utils.logging.DIFLogger;
40  import pt.digitalis.log.ILogWrapper;
41  import pt.digitalis.utils.common.StringUtils;
42  
43  /**
44   * This class will define a Parameter.
45   * <p>
46   * It will hold information relative to the Parameter value, ID key and validation constraints.
47   * 
48   * @param <T>
49   *            generic type of the parameter
50   * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a><br/>
51   * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a>
52   * @created 2007/05/04
53   */
54  abstract public class AbstractParameter<T> implements IParameter<T>, IEditableParameter {
55  
56      /** Logger for specific logging needs */
57      static private ILogWrapper logger = DIFLogger.getLogger();
58  
59      /** The message manager to get class messages */
60      static IMessageManager messageManager;
61  
62      /** Messages cache for all constraints */
63      static private MessageList messages;
64  
65      /**
66       * Get's the Message Manager from the IoC
67       * 
68       * @return the message manager instance
69       */
70      static private IMessageManager getMessageManager()
71      {
72          if (messageManager == null)
73              messageManager = DIFIoCRegistry.getRegistry().getImplementation(IMessageManager.class);
74  
75          return messageManager;
76      }
77  
78      /**
79       * Lazy loading getter of messages
80       * 
81       * @return the messages
82       */
83      public static MessageList getMessages()
84      {
85          // If the messages have not yet been loaded do it now
86          if (messages == null)
87          {
88              messages = getMessageManager().collectEntityMessagesFromRepository(AbstractParameter.class);
89          }
90  
91          return messages;
92      }
93  
94      /** If the USER scoped parameter can be accessed by anonymous access without reporting an error */
95      private boolean allowAnonymous = false;
96  
97      /** A list of constraints to validate on parameter setting */
98      private Map<String, IParameterConstraint> constraints = new HashMap<String, IParameterConstraint>();
99  
100     /** The parameter default value */
101     private T defaultValue;
102 
103     /**
104      * used to determine if it is the first run for static parameters first tme only initialization (default value
105      * setting)
106      */
107     private Boolean firstInitialization = true;
108 
109     /** if T allows the form parameter to be configured (thus declaring the form as configurable) */
110     private Boolean formConfigurable = false;
111 
112     /** The form the parameter is linked to if available */
113     private String formLinked = null;
114 
115     /** The id of the parameter */
116     private String id;
117 
118     /** The parameter scope */
119     private ParameterScope parameterScope;
120 
121     /** The id of the parent entity that owns the parameter */
122     private String parentID;
123 
124     /** The entity type of the parent entity that owns the parameter */
125     private Entity parentType;
126 
127     /** Persist to the persistent repository. Persist between JVM restarts */
128     private Boolean persistToRepository = false;
129 
130     /** If the parameter cannot be modified after initialization */
131     private Boolean readonly = false;
132 
133     /** If this parameter is referenced in a {@link Rule} used in another {@link IParameter} */
134     private Boolean referencedInARuleFromAnotherParameter = false;
135 
136     /** If the parameter must always be passed a value. Only for REQUEST scoped parameters */
137     private Boolean required = false;
138 
139     /** The parameter rules */
140     private List<IParameterRule<T>> rules = new ArrayList<IParameterRule<T>>();
141 
142     /** A list of associated validators to validate on parameter setting */
143     private Map<String, IParameterValidator> validators = new HashMap<String, IParameterValidator>();
144 
145     /** The parameter current value */
146     private T value;
147 
148     /**
149      * Modifier for the 'rules' attribute.
150      * 
151      * @param rule
152      *            the new rule to add
153      */
154     public void addRule(IParameterRule<T> rule)
155     {
156         this.rules.add(rule);
157     }
158 
159     /**
160      * To override in each parameter type class as needed
161      * 
162      * @return the list of automatic constraints that each parameter type adds
163      */
164     protected String automaticConstraints()
165     {
166         return "";
167     }
168 
169     /**
170      * @see java.lang.Object#clone()
171      */
172     @Override
173     @SuppressWarnings("unchecked")
174     public IParameter<T> clone() throws CloneNotSupportedException
175     {
176         try
177         {
178             IParameter<T> parameter;
179 
180             parameter = this.getClass().newInstance();
181             parameter.forceInitialize(this.allowAnonymous, this.constraints, this.defaultValue, this.formLinked,
182                     this.id, this.parameterScope, this.parentID, this.parentType, this.persistToRepository,
183                     this.readonly, this.referencedInARuleFromAnotherParameter, this.required, this.formConfigurable,
184                     this.rules, this.validators, this.value);
185 
186             return parameter;
187         }
188         catch (InstantiationException e)
189         {
190             throw new CloneNotSupportedException(e.getMessage());
191         }
192         catch (IllegalAccessException e)
193         {
194             throw new CloneNotSupportedException(e.getMessage());
195         }
196     }
197 
198     /**
199      * Converts an object to strong format, according to any rules necessary in conversion of the given parameter type
200      * 
201      * @param obj
202      *            the object to convert
203      * @return the object in a string representation
204      */
205     protected String convertObjectToString(Object obj)
206     {
207         return StringUtils.toStringOrNull(obj);
208     }
209 
210     /**
211      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#forceInitialize(boolean, java.util.Map, java.lang.Object,
212      *      java.lang.String, java.lang.String, pt.digitalis.dif.dem.objects.parameters.ParameterScope,
213      *      java.lang.String, pt.digitalis.dif.dem.Entity, boolean, boolean, boolean, boolean, boolean, java.util.List,
214      *      java.util.Map, java.lang.Object)
215      */
216     public void forceInitialize(boolean allowAnonymous, Map<String, IParameterConstraint> constraints, T defaultValue,
217             String formLinked, String id, ParameterScope parameterScope, String parentID, Entity parentType,
218             boolean persistToRepository, boolean readonly, boolean referencedInARuleFromAnotherParameter,
219             boolean required, boolean formConfigurable, List<IParameterRule<T>> rules,
220             Map<String, IParameterValidator> validators, T value)
221     {
222         this.allowAnonymous = allowAnonymous;
223         this.defaultValue = defaultValue;
224         this.formLinked = formLinked;
225         this.id = id;
226         this.parameterScope = parameterScope;
227         this.parentID = parentID;
228         this.parentType = parentType;
229         this.persistToRepository = persistToRepository;
230         this.readonly = readonly;
231         this.referencedInARuleFromAnotherParameter = referencedInARuleFromAnotherParameter;
232         this.required = required;
233         this.formConfigurable = formConfigurable;
234 
235         this.constraints = new HashMap<String, IParameterConstraint>();
236         this.constraints.putAll(constraints);
237 
238         this.rules = new ArrayList<IParameterRule<T>>();
239         this.rules.addAll(rules);
240 
241         this.validators = new HashMap<String, IParameterValidator>();
242         this.validators.putAll(validators);
243 
244         this.value = value;
245     }
246 
247     /**
248      * @return the constraints
249      */
250     public Map<String, IParameterConstraint> getConstraints()
251     {
252         return constraints;
253     }
254 
255     /**
256      * Return a common debug prefix
257      * 
258      * @return the prefix
259      */
260     private String getDebugPrefix()
261     {
262         return "[" + getParameterScope().toString() + " parameter \"" + getId() + "\"] ";
263     }
264 
265     /**
266      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#getFormLinked()
267      */
268     public String getFormLinked()
269     {
270         return formLinked;
271     }
272 
273     /**
274      * @return the id
275      */
276     public String getId()
277     {
278         return id;
279     }
280 
281     /**
282      * Return the language from the context of the default if not available
283      * 
284      * @param context
285      *            the context
286      * @return the language
287      */
288     protected String getLanguage(IDIFContext context)
289     {
290         // If a session is available get the current language, else, the default will be used
291         if (context != null && context.getSession() != null && context.getSession().getLanguage() != null)
292         {
293             return context.getSession().getLanguage().toLowerCase();
294         }
295         else
296             return DIFGeneralConfigurationParameters.getInstance().getDefaultLanguage();
297     }
298 
299     /**
300      * @return the parameterScope
301      */
302     public ParameterScope getParameterScope()
303     {
304         return parameterScope;
305     }
306 
307     /**
308      * @return the parentID
309      */
310     public String getParentID()
311     {
312         return parentID;
313     }
314 
315     /**
316      * @return the parentType
317      */
318     public Entity getParentType()
319     {
320         return parentType;
321     }
322 
323     /**
324      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#getRules()
325      */
326     public List<IParameterRule<T>> getRules()
327     {
328         return rules;
329     }
330 
331     /**
332      * @return the validators
333      */
334     public Map<String, IParameterValidator> getValidators()
335     {
336         return validators;
337     }
338 
339     /**
340      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#getValue(IDIFContext)
341      */
342     @SuppressWarnings("unchecked")
343     public T getValue(IDIFContext context) throws ParameterException
344     {
345 
346         if (parameterScope == ParameterScope.SESSION)
347         {
348             if (context == null || context.getSession() == null)
349             {
350                 String message;
351 
352                 if (context == null)
353                     message = getMessages().getMessages().get("noSession");
354                 else
355                     message = getMessages().getMessages(context.getLanguage()).get("noSession");
356 
357                 throw new ParameterException(getDebugPrefix() + message, this);
358             }
359 
360             return (T) context.getSession().getAttribute(getId());
361 
362         }
363         else if (parameterScope == ParameterScope.USER)
364         {
365             if (context == null || context.getSession() == null || context.getSession().getUser() == null)
366                 if (allowAnonymous)
367                 {
368                     logWarning("Can't process a USER scoped parameter without a user authenticated in session. Returning null.");
369                     return null;
370                 }
371                 else
372                 {
373                     String language = (context == null ? DIFGeneralConfigurationParameters.getInstance()
374                             .getDefaultLanguage() : context.getLanguage());
375 
376                     throw new ParameterException(getDebugPrefix() + getMessages().getMessages(language).get("noUser"),
377                             this);
378                 }
379 
380             // FIXME: This will fail since the value is not kept through all user instances
381             return (T) context.getSession().getUser().getParameter(getId());
382 
383         }
384         else
385             return this.value;
386     }
387 
388     /**
389      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#getValueAsDocument(pt.digitalis.dif.controller.interfaces.IDIFContext)
390      */
391     public DocumentRepositoryEntry getValueAsDocument(IDIFContext context) throws ParameterException
392     {
393         // Normally a parameter does not implement this mathod...
394         throw new ParameterException(getMessages().getMessages(context.getLanguage()).get("invalidUsage"), this);
395     }
396 
397     /**
398      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#getValueAsString(IDIFContext)
399      */
400     public String getValueAsString(IDIFContext context) throws ParameterException
401     {
402         T currentValue = getValue(context);
403 
404         if (currentValue == null)
405             return null;
406         else
407             return currentValue.toString();
408     }
409 
410     /**
411      * @param context
412      *            the current stage context
413      * @return T if the linked form has been submitted
414      */
415     protected boolean hasFormBeenSubmited(IDIFContext context)
416     {
417         if (getFormLinked() == null)
418             return false;
419         else
420         {
421 
422             Object submitStage = context.getRequest().getParameter(HTTPConstants.FORM_SUBMIT_STAGE);
423             Object submitForm = context.getRequest().getParameter(HTTPConstants.FORM_SUBMIT_NAME);
424 
425             return (submitStage != null && submitForm != null && context.getStage().equals(submitStage) && getFormLinked()
426                     .equals(submitForm.toString()));
427         }
428     }
429 
430     /**
431      * @return T when the parameter has a value set
432      */
433     protected boolean hasValue()
434     {
435         return this.value != null;
436     }
437 
438     /**
439      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#initialize(java.lang.String, pt.digitalis.dif.dem.Entity,
440      *      java.lang.String, boolean, boolean, boolean, pt.digitalis.dif.dem.objects.parameters.ParameterScope,
441      *      java.lang.String, java.lang.String, java.util.Map, java.util.List)
442      */
443     public void initialize(String id, Entity parentType, String parentID, boolean formConfigurable,
444             boolean persistToRepository, boolean allowAnonymousAccess, ParameterScope parameterScope,
445             String defaultValue, String constraintDefinition, Map<String, IParameterValidator> validators,
446             List<IParameterRule<T>> rules) throws ParameterException
447     {
448 
449         this.id = id.toLowerCase();
450         this.parentID = parentID.toLowerCase();
451         this.parentType = parentType;
452         this.allowAnonymous = allowAnonymousAccess;
453         this.persistToRepository = persistToRepository;
454         this.parameterScope = parameterScope;
455         this.formConfigurable = formConfigurable;
456 
457         if (validators == null)
458             this.validators = new HashMap<String, IParameterValidator>();
459         else
460             this.validators = validators;
461 
462         if (rules == null)
463             this.rules = new ArrayList<IParameterRule<T>>();
464         else
465             this.rules = rules;
466 
467         this.constraints = new HashMap<String, IParameterConstraint>();
468 
469         // Add automatic constraints
470         if (!"".equals(automaticConstraints()))
471         {
472             if (constraintDefinition == null || "".equals(constraintDefinition))
473                 constraintDefinition = automaticConstraints();
474             else
475                 constraintDefinition = automaticConstraints() + "," + constraintDefinition;
476         }
477 
478         // If there are constraints defined...
479         if (constraintDefinition != null && !"".equals(constraintDefinition))
480         {
481 
482             String[] constraintStrings = constraintDefinition.split(",");
483 
484             // For each declared constraint
485             for (String constraintString: constraintStrings)
486             {
487                 String constraintID;
488                 int posEqual = constraintString.indexOf("=");
489 
490                 constraintID = (posEqual == -1 ? constraintString : constraintString.substring(0, posEqual));
491                 constraintID = constraintID.trim().toLowerCase();
492 
493                 // Readonly is a constraint with special treatment in the
494                 // Parameter class itself. Does not have an
495                 // IParameterConstraint implementation. No need.
496                 if (constraintID.equals("readonly"))
497                     this.readonly = true;
498                 else if (constraintID.equals("required"))
499                     // Required only for REQUEST parameters
500                     this.required = true;
501                 else
502                 {
503                     IParameterConstraint constraint = DIFIoCRegistry.getRegistry().getImplementation(
504                             IParameterConstraint.class, constraintID);
505 
506                     if (constraint == null)
507                     {
508                         // Bad constraint name. Report error
509                         throw new ParameterException("Inexistant constraint \"" + constraintID + "\"", this);
510                     }
511                     else
512                     {
513                         constraint.configureConstraint(constraintString);
514                         constraints.put(constraintID, constraint);
515                     }
516                 }
517             }
518         }
519 
520         if (defaultValue != null && !"".equals(defaultValue))
521         {
522             setValueFromString(defaultValue, null);
523             this.defaultValue = value;
524         }
525 
526         if (persistToRepository)
527         {
528             // TODO: Implement persistence. Should read the value if available from the repository.
529         }
530     }
531 
532     /**
533      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#isAllowAnonymous()
534      */
535     public boolean isAllowAnonymous()
536     {
537         return allowAnonymous;
538     }
539 
540     /**
541      * Inspector for the 'firstInitialization' attribute.
542      * 
543      * @return the firstInitialization value
544      */
545     public boolean isFirstInitialization()
546     {
547         return firstInitialization;
548     }
549 
550     /**
551      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#isFormConfigurable()
552      */
553     public boolean isFormConfigurable()
554     {
555         return formConfigurable && StringUtils.isNotBlank(this.getFormLinked());
556     }
557 
558     /**
559      * @return the persistToRepository
560      */
561     public boolean isPersistToRepository()
562     {
563         return persistToRepository;
564     }
565 
566     /**
567      * @return the readonly
568      */
569     public boolean isReadonly()
570     {
571         return readonly;
572     }
573 
574     /**
575      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#isReferencedInARuleFromAnotherParameter()
576      */
577     public boolean isReferencedInARuleFromAnotherParameter()
578     {
579         return referencedInARuleFromAnotherParameter;
580     }
581 
582     /**
583      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#isRequired()
584      */
585     public boolean isRequired()
586     {
587         return required;
588     }
589 
590     /**
591      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#isStringSetterSupported()
592      */
593     public boolean isStringSetterSupported()
594     {
595         return true;
596     }
597 
598     /**
599      * Logs a warning
600      * 
601      * @param warning
602      *            the warning message to log
603      */
604     protected void logWarning(String warning)
605     {
606 
607         if (DIFLogger.getLogger().isDebugEnabled())
608             DIFLogger.getLogger().warn(getDebugPrefix() + warning + "\n" + this.toString());
609         else
610             DIFLogger.getLogger().warn(getDebugPrefix() + warning);
611     }
612 
613     /**
614      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#refreshParameterValue(pt.digitalis.dif.dem.interfaces.IStageInstance)
615      */
616     @SuppressWarnings("unchecked")
617     public ParameterErrorList refreshParameterValue(IStageInstance stageInstance)
618     {
619         IDIFContext context = (stageInstance == null ? null : stageInstance.getContext());
620 
621         if (context == null)
622             return new ParameterErrorList(this, null);
623         else
624         {
625             String language = context.getLanguage();
626             ParameterErrorList list = new ParameterErrorList(this, null);
627 
628             // Read the value from the request
629             Object requestValue = context.getRequest().getParameter(getId());
630             boolean parameterExistsInRequest = context.getRequest().getParameters().containsKey(getId());
631 
632             // IMPLEMENTATION NOTE:
633             //
634             // The parameter will be updated based on the following conditions:
635             // - Parameter Scope: REQUEST, STATIC, SESSION, USER
636             // - Persist the value: Read it from a persistent repository on initialization
637             // - Default present: If no previous value a default value may be used
638             // - Context: The context may be a source for values for REQUEST, USER or SESSION scopes
639             // - Form submission for parameters that are linkedToForm's
640 
641             if (requestValue == null && !parameterExistsInRequest)
642             {
643                 if (getParameterScope().equals(ParameterScope.SESSION))
644                 {
645                     // No value passed, read the value from the session
646                     // Gets the session from the context
647                     IDIFSession session = context.getSession();
648 
649                     if (session == null)
650                     {
651                         ParameterError error = new ParameterError(getMessages().getMessages(language).get("noSession"),
652                                 ParameterErrorType.NO_SESSION);
653                         list.addError(error);
654                     }
655                     else if (session.containsAttribute(getId()))
656                     {
657                         // If the parameter already exists in session
658                         Object sessionValue = session.getAttribute(getId());
659 
660                         // Recover value in session
661                         logger.debug(getDebugPrefix() + "Setting to \"" + sessionValue + "\" (read from Session)");
662 
663                         requestValue = sessionValue;
664                     }
665                 }
666                 else if (getParameterScope().equals(ParameterScope.USER))
667                 {
668                     // TODO: Check the problem of several copies of the same user so the parameter is not kept between
669                     // requests
670 
671                     IDIFSession session = context.getSession();
672 
673                     if (session == null)
674                     {
675                         ParameterError error = new ParameterError(getMessages().getMessages(language).get("noSession"),
676                                 ParameterErrorType.NO_SESSION);
677                         list.addError(error);
678                     }
679                     else
680                     {
681                         // Gets the user from the context
682                         IDIFUser user = session.getUser();
683 
684                         if (user == null && !allowAnonymous)
685                         {
686                             ParameterError error = new ParameterError(
687                                     getMessages().getMessages(language).get("noUser"), ParameterErrorType.NO_USER);
688                             list.addError(error);
689                         }
690                         else if (user != null && user.containsParameter(getId()))
691                         {
692                             // If the parameter already exists in the user
693                             requestValue = user.getParameter(getId());
694 
695                             logger.debug(getDebugPrefix() + "Setting to \"" + requestValue + "\" (read from User)");
696                         }
697                     }
698                 }
699             }
700 
701             // IMPLEMENTATION NOTE:
702             // If the Scope is Static there is nothing to do since the initializations have already taken care of it in
703             // the CodeGen and this value will persist through all the JVM life BUT we must check the REQUEST for value
704             // setting
705 
706             // All validations and initializations have taken place. Set the value now if existent
707             // If no value present in the request (omitted or passed as null)...
708             if (requestValue == null)
709             {
710 
711                 if (isRequired() && !isReferencedInARuleFromAnotherParameter())
712                 {
713 
714                     // Request parameters with required must be set!
715                     ParameterError error = new ParameterError(getMessages().getMessages(language).get("required"),
716                             ParameterErrorType.MISSING);
717                     list.addError(error);
718                     list.addErrorList(setValue(null, stageInstance, true).getErrorList());
719                 }
720                 else
721                 {
722                     if (!parameterExistsInRequest
723                             && (this.getParameterScope() != ParameterScope.STATIC || this.isFirstInitialization()))
724                     {
725                         // Set if to the default value (or null if none is set)...
726                         logger.debug(getDebugPrefix() + "No value passed - Setting to "
727                                 + (defaultValue == null ? "null" : "default \"" + defaultValue.toString() + "\""));
728                         list.addErrorList(setDefaultValue(stageInstance, true).getErrorList());
729                     }
730 
731                     this.setFirstInitialization(false);
732                 }
733             }
734             else
735             {
736                 logger.debug(getDebugPrefix() + "Setting to \"" + requestValue + "\" (read from request)");
737 
738                 if (isStringSetterSupported())
739                     list.addErrorList(setValueFromString(this.convertObjectToString(requestValue), stageInstance, true)
740                             .getErrorList());
741                 else
742                     list.addErrorList(setValue((T) requestValue, stageInstance, true).getErrorList());
743             }
744 
745             return list;
746         }
747     }
748 
749     /**
750      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#setDefaultValue(pt.digitalis.dif.dem.interfaces.IStageInstance)
751      */
752     public ParameterErrorList setDefaultValue(IStageInstance stageInstance)
753     {
754         return setDefaultValue(stageInstance, false);
755     }
756 
757     /**
758      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#setDefaultValue(pt.digitalis.dif.dem.interfaces.IStageInstance,
759      *      boolean)
760      */
761     public ParameterErrorList setDefaultValue(IStageInstance stageInstance, boolean initializationInProgress)
762     {
763         return setValue(defaultValue, stageInstance, initializationInProgress);
764     }
765 
766     /**
767      * Modifier for the 'firstInitialization' attribute.
768      * 
769      * @param firstInitialization
770      *            the new firstInitialization value to set
771      */
772     public void setFirstInitialization(boolean firstInitialization)
773     {
774         this.firstInitialization = firstInitialization;
775     }
776 
777     /**
778      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#setFormConfigurable(boolean)
779      */
780     public void setFormConfigurable(boolean formConfigurable)
781     {
782         this.formConfigurable = formConfigurable;
783     }
784 
785     /**
786      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#setFormLinked(java.lang.String)
787      */
788     public void setFormLinked(String formLinked)
789     {
790         this.formLinked = formLinked;
791     }
792 
793     /**
794      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#setReferencedInARuleFromAnotherParameter(boolean)
795      */
796     public void setReferencedInARuleFromAnotherParameter(boolean referencedInARuleFromAnotherParameter)
797     {
798         this.referencedInARuleFromAnotherParameter = referencedInARuleFromAnotherParameter;
799     }
800 
801     /**
802      * @see pt.digitalis.dif.dem.objects.parameters.IEditableParameter#setRequired(boolean)
803      */
804     public void setRequired(boolean required)
805     {
806         this.required = required;
807     }
808 
809     /**
810      * Sets the value of the parameter and runs all constraints and validations
811      * 
812      * @param value
813      *            the value to set
814      * @param stageInstance
815      *            the DIF stage to read if needed. WARNING: If null is interpreted like an initialization and no scope
816      *            repositories will be accessed/updated.
817      * @return return the error messages if the validation fails
818      */
819     public ParameterErrorList setValue(T value, IStageInstance stageInstance)
820     {
821         return setValue(value, stageInstance, false);
822     }
823 
824     /**
825      * Sets the value of the parameter and runs all constraints and validations
826      * 
827      * @param value
828      *            the value to set
829      * @param stageInstance
830      *            the DIF stage to read if needed. WARNING: If null is interpreted like an initialization and no scope
831      *            repositories will be accessed/updated.
832      * @param initializationInProgress
833      *            T if called within the dif parameter initialization
834      * @return return the error messages if the validation fails
835      */
836     public ParameterErrorList setValue(T value, IStageInstance stageInstance, boolean initializationInProgress)
837     {
838 
839         ParameterErrorList list = new ParameterErrorList(this, value);
840         IDIFContext context;
841 
842         if (stageInstance == null)
843             context = null;
844         else
845             context = stageInstance.getContext();
846 
847         // Perform validation. Will create the error list if not valid
848         list = validateParameterValue(value, stageInstance, initializationInProgress);
849 
850         if (context == null)
851             // Null context is interpreted like an initialization so it will not try to update the repositories defined
852             // by it's scope
853             this.value = value;
854 
855         else
856         {
857             if (parameterScope == ParameterScope.SESSION)
858             {
859                 if (context.getSession() == null)
860                 {
861                     list.addError(new ParameterError(getMessages().getMessages(context.getLanguage()).get("noSession"),
862                             ParameterErrorType.NO_SESSION));
863 
864                     this.value = null;
865                 }
866                 else
867                 {
868                     context.getSession().addAttribute(getId(), value);
869                 }
870 
871             }
872             else if (parameterScope == ParameterScope.USER)
873             {
874                 if (context.getSession() == null || context.getSession().getUser() == null)
875                 {
876                     if (!allowAnonymous)
877                         list.addError(new ParameterError(
878                                 getMessages().getMessages(context.getLanguage()).get("noUser"),
879                                 ParameterErrorType.NO_USER));
880 
881                     this.value = null;
882                 }
883                 else
884                 {
885                     // FIXME: This will fail since the value is not kept through all user instances
886                     context.getSession().getUser().setParameter(getId(), value);
887                 }
888 
889             }
890             else if (parameterScope == ParameterScope.REQUEST)
891             {
892                 // The parameter will be thrown away after the request is processed
893                 this.value = value;
894 
895             }
896             else if (parameterScope == ParameterScope.STATIC)
897                 // Static values are kept in the inner value attribute. The only ones that keep it here.
898                 this.value = value;
899 
900             if (isPersistToRepository())
901             {
902                 // TODO: Persist to persistent repository
903             }
904         }
905 
906         return list;
907     }
908 
909     /**
910      * @see pt.digitalis.dif.dem.objects.parameters.IParameter#setValueFromString(java.lang.String,
911      *      pt.digitalis.dif.dem.interfaces.IStageInstance)
912      */
913     public final ParameterErrorList setValueFromString(String value, IStageInstance stageInstance)
914     {
915 
916         return this.setValueFromString(value, stageInstance, false);
917     }
918 
919     /**
920      * @see java.lang.Object#toString()
921      */
922     @Override
923     public String toString()
924     {
925         ObjectFormatter formatter = new ObjectFormatter();
926         formatter.addItem("ID", this.id);
927         formatter.addItem("Value", value);
928         formatter.addItem("Value Type", this.value == null ? "n/a" : this.value.getClass().getCanonicalName());
929         formatter.addItem("Parent", "(" + this.parentType + ") " + this.parentID);
930         formatter.addItem("Scope", this.parameterScope);
931         formatter.addItem("Persist", this.persistToRepository);
932         formatter.addItem("Readonly", this.readonly);
933         formatter.addItem("Required", this.required);
934         formatter.addItem("Default Value", this.defaultValue);
935         formatter.addItem("Link to Form", this.formLinked);
936         formatter.addItem("Form Configurable", this.formConfigurable);
937         formatter.addItem("Constraints", this.constraints);
938         formatter.addItem("Validators", this.validators);
939         formatter.addItem("Rules", this.rules);
940         formatter.addItem("Referenced in a rule from another parameter", this.referencedInARuleFromAnotherParameter);
941 
942         return formatter.getFormatedObject();
943     }
944 
945     /**
946      * Validate a parameter value on type, constraints, validators and rules, if applied.
947      * 
948      * @param value
949      *            the value to validate
950      * @param stageInstance
951      *            the stage where the parameter is being validated
952      * @param initializationInProgress
953      *            T if called within the dif parameter initialization
954      * @return the list of errors found upon validation
955      */
956     protected ParameterErrorList validateParameterValue(T value, IStageInstance stageInstance,
957             boolean initializationInProgress)
958     {
959         ParameterErrorList list = new ParameterErrorList(this, value);
960         IDIFContext context;
961 
962         if (stageInstance == null)
963             context = null;
964         else
965             context = stageInstance.getContext();
966 
967         // Validate all constraints
968         for (Entry<String, IParameterConstraint> constraintEntry: getConstraints().entrySet())
969         {
970 
971             ParameterConstraintResult constraintResult = constraintEntry.getValue().getValidationResult(value,
972                     stageInstance);
973             if (!constraintResult.isValid())
974             {
975                 list.addError(new ParameterError(constraintEntry.getKey(), constraintResult));
976             }
977         }
978 
979         // Validate all validators
980         for (Entry<String, IParameterValidator> validatorEntry: getValidators().entrySet())
981         {
982             if (!validatorEntry.getValue().validate(value, context))
983             {
984                 ParameterError error = new ParameterError(validatorEntry.getValue().validationErrorMessage(
985                         getLanguage(context)), ParameterErrorType.VALIDATOR);
986                 error.setValidator(validatorEntry.getKey(), validatorEntry.getValue());
987 
988                 list.addError(error);
989             }
990         }
991 
992         // Validate all rules
993         for (IParameterRule<T> rule: getRules())
994         {
995             ParameterRuleResult result;
996             try
997             {
998                 result = rule.getValidationResult(stageInstance, value, initializationInProgress, this);
999 
1000                 if (!result.isValid())
1001                 {
1002                     ParameterError error = new ParameterError(result.getErrorMessage(), ParameterErrorType.RULE);
1003                     error.setRule(rule);
1004 
1005                     list.addError(error);
1006                 }
1007             }
1008             catch (ParameterException e)
1009             {
1010                 ParameterError error = new ParameterError(e.getMessage(), ParameterErrorType.RULE);
1011                 error.setRule(rule);
1012 
1013                 list.addError(error);
1014             }
1015 
1016         }
1017 
1018         return list;
1019     }
1020 }