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