View Javadoc

1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.web.form;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.CoreApiServiceLocator;
20  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
21  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
22  import org.kuali.rice.krad.uif.util.SessionTransient;
23  import org.kuali.rice.krad.util.ObjectUtils;
24  
25  import java.io.Serializable;
26  import java.lang.annotation.Annotation;
27  import java.lang.reflect.Field;
28  import java.util.ArrayList;
29  import java.util.HashMap;
30  import java.util.HashSet;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Set;
34  import java.util.Vector;
35  
36  /**
37   * Manages Uif form objects for a session
38   *
39   * @author Kuali Rice Team (rice.collab@kuali.org)
40   */
41  public class UifFormManager implements Serializable {
42      private static final long serialVersionUID = -6323378881342207080L;
43  
44      private int maxNumberOfSessionForms = 5;
45  
46      private Vector accessedFormKeys;
47  
48      private Map<String, UifFormBase> sessionForms;
49  
50      /**
51       * Create a new form manager with an empty list of forms for the session.
52       */
53      public UifFormManager() {
54          this.accessedFormKeys = new Vector();
55          this.sessionForms = new HashMap<String, UifFormBase>();
56  
57          String maxNumberOfSessionFormsConfig =
58                  CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString("maxNumberOfSessionForms");
59          if (StringUtils.isNotBlank(maxNumberOfSessionFormsConfig)) {
60              maxNumberOfSessionForms = Integer.parseInt(maxNumberOfSessionFormsConfig);
61          }
62      }
63  
64      /**
65       * Add a form to the session
66       *
67       * @param form to be added to the session
68       */
69      public synchronized void addSessionForm(UifFormBase form) {
70          if (form == null || StringUtils.isBlank(form.getFormKey())) {
71              throw new RiceIllegalArgumentException("Form or form key was null");
72          }
73  
74          sessionForms.put(form.getFormKey(), form);
75  
76          // add form key to top of vector indicating it is most recent
77          if (accessedFormKeys.contains(form.getFormKey())) {
78              accessedFormKeys.removeElement(form.getFormKey());
79          }
80          accessedFormKeys.add(form.getFormKey());
81  
82          // check if we have too many forms and need to remove an old one
83          if (sessionForms.size() > maxNumberOfSessionForms) {
84              // clear all inquiry forms first, temp solution until inquiry forms are not stored in session
85              // TODO: remove once inquiry forms are not required to be in session
86              Set<String> formKeys = new HashSet<String>(sessionForms.keySet());
87              for (String formKey : formKeys) {
88                  UifFormBase sessionForm = sessionForms.get(formKey);
89                  if ((sessionForm instanceof InquiryForm) && (!formKey.equals(form.getFormKey()))) {
90                      sessionForms.remove(formKey);
91                      accessedFormKeys.remove(formKey);
92                  }
93              }
94          }
95  
96          // if we still have too many forms clear the oldest form
97          if (sessionForms.size() > maxNumberOfSessionForms) {
98              // get the oldest form we have
99              String removeFormKey = (String) accessedFormKeys.get(0);
100             if (sessionForms.containsKey(removeFormKey)) {
101                 sessionForms.remove(removeFormKey);
102             }
103             accessedFormKeys.removeElementAt(0);
104         }
105     }
106 
107     /**
108      * Retrieve a form from the session
109      *
110      * @param formKey of the form to retrieve from the session
111      * @return UifFormBase
112      */
113     public UifFormBase getSessionForm(String formKey) {
114         if (sessionForms.containsKey(formKey)) {
115             return sessionForms.get(formKey);
116         }
117 
118         return null;
119     }
120 
121     /**
122      * Removes the stored form data and the forms from the breadcrumb history from the session
123      *
124      * @param form to be removed
125      */
126     public void removeSessionForm(UifFormBase form) {
127         if (form == null || StringUtils.isBlank(form.getFormKey())) {
128             return;
129         }
130 
131         removeSessionFormByKey(form.getFormKey());
132     }
133 
134     /**
135      * Removes the stored form data and the forms from the breadcrumb history from the session
136      *
137      * @param formKey of the form to be removed
138      */
139     public void removeFormWithHistoryFormsByKey(String formKey) {
140         if (sessionForms.containsKey(formKey)) {
141             removeSessionFormByKey(formKey);
142         }
143     }
144 
145     /**
146      * Removes the stored form data from the session
147      *
148      * @param formKey of the form to be removed
149      */
150     public void removeSessionFormByKey(String formKey) {
151         if (accessedFormKeys.contains(formKey)) {
152             accessedFormKeys.removeElement(formKey);
153         }
154 
155         if (sessionForms.containsKey(formKey)) {
156             sessionForms.remove(formKey);
157         }
158     }
159 
160     /**
161      * Indicates whether the form manager has a session form with the given key
162      *
163      * @param formKey key of the form in session to check for
164      * @return true if the manager contains the session form, false if not
165      */
166     public boolean hasSessionForm(String formKey) {
167         return sessionForms.containsKey(formKey);
168     }
169 
170     /**
171      * Retrieves the session form based on the formkey and updates the non session transient
172      * variables on the request form from the session form
173      *
174      * @param requestForm
175      * @param formKey
176      */
177     public void updateFormWithSession(UifFormBase requestForm, String formKey) {
178         UifFormBase sessionForm = sessionForms.get(formKey);
179         if (sessionForm == null) {
180             return;
181         }
182 
183         if (!sessionForm.getClass().isAssignableFrom(requestForm.getClass())) {
184             throw new RuntimeException(
185                     "Session form mismatch, session form class not assignable from request form class");
186         }
187 
188         List<Field> fields = new ArrayList<Field>();
189         fields = ObjectUtils.getAllFields(fields, sessionForm.getClass(), UifFormBase.class);
190         for (Field field : fields) {
191             boolean copyValue = true;
192             for (Annotation an : field.getAnnotations()) {
193                 if (an instanceof SessionTransient) {
194                     copyValue = false;
195                 }
196             }
197 
198             if (copyValue && ObjectPropertyUtils.isReadableProperty(sessionForm, field.getName()) && ObjectPropertyUtils
199                     .isWritableProperty(sessionForm, field.getName())) {
200                 Object fieldValue = ObjectPropertyUtils.getPropertyValue(sessionForm, field.getName());
201                 ObjectPropertyUtils.setPropertyValue(requestForm, field.getName(), fieldValue);
202             }
203         }
204     }
205 
206     /**
207      * Removes the values that are marked @SessionTransient from the form.
208      *
209      * @param form - the form from which the session transient values have been purged
210      */
211     public void purgeForm(UifFormBase form) {
212         List<Field> fields = new ArrayList<Field>();
213         fields = ObjectUtils.getAllFields(fields, form.getClass(), UifFormBase.class);
214         for (Field field : fields) {
215             boolean purgeValue = false;
216 
217             if (!field.getType().isPrimitive()) {
218                 for (Annotation an : field.getAnnotations()) {
219                     if (an instanceof SessionTransient) {
220                         purgeValue = true;
221                     }
222                 }
223             }
224 
225             if (purgeValue && ObjectPropertyUtils.isWritableProperty(form, field.getName())) {
226                 ObjectPropertyUtils.setPropertyValue(form, field.getName(), null);
227             }
228         }
229     }
230 
231     /**
232      * Internal vector maintained to keep track of accessed form and the order in which they were accessed
233      *
234      * <p>
235      * Used for the form clearing process. When forms are added to the manager their key is added to the top of
236      * the vector. When a form needs to be cleared, the form identified by the key at the botton of this vector
237      * is removed
238      * </p>
239      *
240      * @return Vector instance holding form key strings
241      */
242     protected Vector getAccessedFormKeys() {
243         return accessedFormKeys;
244     }
245 
246     /**
247      * Maximum number of forms that can be stored at one time by the manager
248      *
249      * @return int max number of forms
250      */
251     public int getMaxNumberOfSessionForms() {
252         return maxNumberOfSessionForms;
253     }
254 
255     /**
256      * Setter for the maximum number of forms
257      *
258      * @param maxNumberOfSessionForms
259      */
260     public void setMaxNumberOfSessionForms(int maxNumberOfSessionForms) {
261         this.maxNumberOfSessionForms = maxNumberOfSessionForms;
262     }
263 
264 }