View Javadoc

1   /**
2    * Copyright 2005-2013 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.datadictionary.validator;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  import org.kuali.rice.krad.datadictionary.uif.UifDictionaryBean;
21  import org.kuali.rice.krad.uif.component.Component;
22  import org.kuali.rice.krad.uif.component.DataBinding;
23  import org.springframework.core.io.ResourceLoader;
24  import org.w3c.dom.Document;
25  import org.w3c.dom.NodeList;
26  
27  import javax.xml.parsers.DocumentBuilder;
28  import javax.xml.parsers.DocumentBuilderFactory;
29  import java.util.ArrayList;
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.Map;
33  
34  /**
35   * Linear collection of identifiers for individual Spring Beans starting with the base bean and ending with the most
36   * recent.  Has the ability to located xml files related to the trace.
37   *
38   * @author Kuali Rice Team (rice.collab@kuali.org)
39   */
40  public class ValidationTrace {
41      private static final Log LOG = LogFactory.getLog(ValidationTrace.class);
42  
43      // Constant identifer for a trace entry where the bean has no identifier itself
44      public static final String NO_BEAN_ID = "NOBEANID";
45  
46      // Constant identifier for a trace during startup
47      public static final int START_UP = 0;
48  
49      // Constant identifier for a trace during render
50      public static final int BUILD = 1;
51  
52      private ArrayList<String> beanIds;
53      private ArrayList<String> beanTypes;
54      private Map<String, Document> beanMap;
55      private int validationStage;
56  
57      /**
58       * Constructor for an empty token to start a trace
59       */
60      public ValidationTrace() {
61          beanIds = new ArrayList<String>();
62          beanTypes = new ArrayList<String>();
63          beanMap = new HashMap<String, Document>();
64      }
65  
66      /**
67       * Constructor for an empty token to start a trace
68       */
69      public ValidationTrace(String[] files, ResourceLoader loader) {
70          beanIds = new ArrayList<String>();
71          beanTypes = new ArrayList<String>();
72          beanMap = new HashMap<String, Document>();
73          loadFiles(files, loader);
74      }
75  
76      /**
77       * Adds a single entry into the trace
78       *
79       * @param beanId - An identifier for the bean
80       * @param beanType - The type of bean
81       */
82      public void addBean(String beanType, String beanId) {
83          beanIds.add(beanId);
84          beanTypes.add(beanType);
85      }
86  
87      /**
88       * Adds a UIF Component to the trace
89       *
90       * @param component - The object to be added
91       */
92      public void addBean(Component component) {
93          String beanId = NO_BEAN_ID;
94          String beanType = component.getClass().getSimpleName();
95          if (component.getId() != null) {
96              if (component.getId().compareTo("null") != 0) {
97                  beanId = component.getId();
98              } else {
99                  try {
100                     beanId = ((DataBinding) component).getPropertyName();
101 
102                 } catch (Exception e) {
103                     beanId = NO_BEAN_ID;
104                 }
105             }
106         } else {
107             try {
108                 beanId = ((DataBinding) component).getPropertyName();
109             } catch (Exception e) {
110                 beanId = NO_BEAN_ID;
111             }
112         }
113         addBean(beanType, beanId);
114     }
115 
116     /**
117      * Adds a UIF Configurable to the trace
118      *
119      * @param configurable - The object to be added
120      */
121     public void addBean(UifDictionaryBean configurable) {
122         String beanId = "configurable";
123         String beanType = configurable.getClass().getSimpleName();
124         addBean(beanType, beanId);
125     }
126 
127     /**
128      * Removes an entry from the trace
129      *
130      * @param index
131      */
132     public void removeBean(int index) {
133         beanIds.remove(index);
134         beanTypes.remove(index);
135     }
136 
137     /**
138      * Replaces a trace entry's information
139      *
140      * @param index - The location of the bean
141      * @param beanId - An identifier for the bean
142      * @param beanType - The type of bean
143      */
144     public void modifyBean(int index, String beanId, String beanType) {
145         beanIds.set(index, beanId);
146         beanTypes.set(index, beanType);
147     }
148 
149     /**
150      * Creates a copy of the ValidationTrace
151      *
152      * @return A complete copy of the current token
153      */
154     public ValidationTrace getCopy() {
155         ValidationTrace copy = new ValidationTrace();
156 
157         for (int i = 0; i < getTraceSize(); i++) {
158             copy.addBean(getBeanType(i), getBeanId(i));
159         }
160         copy.setValidationStage(getValidationStage());
161         copy.setBeanMap(beanMap);
162         return copy;
163     }
164 
165     /**
166      * Loads the xmlFiles of the data objects being validated into a list of Documents that can be parsed to find the
167      * xmls related to the error.
168      *
169      * @param beanFiles - The list of file paths used in the creation of the beans
170      * @param loader - The source that was used to load the beans
171      */
172     private void loadFiles(String[] beanFiles, ResourceLoader loader) {
173         LOG.debug("Started Loading Parser Files");
174 
175         for (int i = 0; i < beanFiles.length; i++) {
176             try {
177                 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
178                 DocumentBuilder builder = factory.newDocumentBuilder();
179                 Document document;
180                 String file = beanFiles[i];//.substring(0,10)+"/"+beanFiles[i].substring(10);
181                 LOG.debug("Loading file: " + file);
182                 document = builder.parse(loader.getResource(file).getInputStream());
183                 beanMap.put(file, document);
184             } catch (Exception e) {
185                 LOG.error("Not Found: " + beanFiles[i]);
186                 //System.exit(1);
187             }
188         }
189         LOG.debug("Finished Loading Parser Files");
190     }
191 
192     /**
193      * Parse the the Documents contained in the Map an finding the map entries whos documents contain the passed in Id
194      * in a bean element's attributes. All attributes are checked because the id used in the trace can be from
195      * different
196      * properties on different beans and not just the id attribute.
197      *
198      * @param id - The attribute value to be found
199      * @param beans - A Map containing the Documents to be looked through
200      * @return - A sub set of maps from the past in list that contains the value being looked for
201      */
202     private Map<String, Document> findBeanById(String id, Map<String, Document> beans) {
203         Map<String, Document> result = new HashMap<String, Document>();
204         LOG.debug("Searching for bean of Id: " + id);
205 
206         Iterator iter = beans.entrySet().iterator();
207 
208         while (iter.hasNext()) {
209             Map.Entry entry = (Map.Entry) iter.next();
210             Document document = (Document) entry.getValue();
211             NodeList nodes = document.getElementsByTagName("bean");
212 
213             for (int i = 0; i < nodes.getLength(); i++) {
214                 if (nodes.item(i).hasAttributes()) {
215                     for (int j = 0; j < nodes.item(i).getAttributes().getLength(); j++) {
216                         if (nodes.item(i).getAttributes().item(j).getNodeValue().toLowerCase().compareTo(
217                                 id.toLowerCase()) == 0) {
218                             LOG.debug("Found bean of Id = " + id);
219 
220                             result.put((String) entry.getKey(), (Document) entry.getValue());
221 
222                             break;
223                         }
224                     }
225                 }
226             }
227         }
228 
229         return result;
230     }
231 
232     /**
233      * Finds related xml files to an error by searching for files that contain beans that have been encountered in the
234      * validation.  The file path and Document version of the xmls are paired and stored in a Map.  This allows for
235      * returning the file paths easy when searching through the Documents.
236      *
237      * @return A list of file paths to the xmls in which the beans were found
238      */
239     public ArrayList<String> findXmlFiles() {
240         Map<String, Document> result = new HashMap<String, Document>();
241         LOG.debug("Looking for Xml files");
242 
243         for (int i = 0; i < getTraceSize(); i++) {
244             if (getBeanId(i) != null) {
245                 if (getBeanId(i).compareTo(NO_BEAN_ID) != 0) {
246                     result.putAll(findBeanById(getBeanId(i), beanMap));
247                 }
248             }
249         }
250 
251         ArrayList<String> files = new ArrayList<String>();
252         Iterator iter = result.entrySet().iterator();
253         while (iter.hasNext()) {
254             Map.Entry entry = (Map.Entry) iter.next();
255             files.add((String) entry.getKey());
256         }
257 
258         return files;
259     }
260 
261     /**
262      * Sets the stage of the validation where the trace is taking place
263      *
264      * @param stage - The stage of the validation
265      */
266     public void setValidationStage(int stage) {
267         validationStage = stage;
268     }
269 
270     /**
271      * Sets the beanMap for when copying the tracer
272      *
273      * @param newMap - The map to be stored
274      */
275     private void setBeanMap(Map<String, Document> newMap) {
276         beanMap = newMap;
277     }
278 
279     /**
280      * Creates a new error report as an Error and adds it to the global list.
281      *
282      * @param validation - The validation that fails.
283      * @param values - The values involved.
284      */
285     public void createError(String validation, String values[]) {
286         ErrorReport report = new ErrorReport(ErrorReport.ERROR, validation, this, values);
287         Validator.addErrorReport(report);
288 
289     }
290 
291     /**
292      * Creates a new error report as a Warning and adds it to the global list.
293      *
294      * @param validation - The validation that fails.
295      * @param values - The values involved.
296      */
297     public void createWarning(String validation, String values[]) {
298         ErrorReport report = new ErrorReport(ErrorReport.WARNING, validation, this, values);
299         Validator.addErrorReport(report);
300 
301     }
302 
303     /**
304      * Retrieves a single entry in the BeanId trace list, a collection identifiers for the traced beans
305      *
306      * @param index - The location of the bean
307      * @return String Identifier for the bean at the provided index of the trace
308      */
309     public String getBeanId(int index) {
310         return beanIds.get(index);
311     }
312 
313     /**
314      * Retrieves a single entry in the BeanType trace list, a collection of types for the traced beansa collection
315      * identifiers for the traced beans
316      *
317      * @param index - The location of the bean type
318      * @return String Type for the bean at the provided index of the trace
319      */
320     public String getBeanType(int index) {
321         return beanTypes.get(index);
322     }
323 
324     /**
325      * Retrieves the stage when the trace is taking place
326      * The stage is the time frame when the validation is taking place in the application
327      *
328      * @return Returns the stage of the validation.
329      */
330     public int getValidationStage() {
331         return validationStage;
332     }
333 
334     /**
335      * Retrieves the number of beans in the trace list
336      *
337      * @return Number of beans stored in the trace
338      */
339     public int getTraceSize() {
340         return beanIds.size();
341     }
342 
343     /**
344      * Retrieves the complete trace path with each bean shown in the form beanId(BeanType)
345      *
346      * @return The String path of the trace
347      */
348     public String getBeanLocation() {
349         String path = "";
350 
351         for (int i = 0; i < beanTypes.size() - 1; i++) {
352             path = path + beanTypes.get(i) + "(" + beanIds.get(i) + ")" + ".";
353         }
354 
355         if (getTraceSize() > 0) {
356             path = path + beanTypes.get(beanTypes.size() - 1) + "(" + beanIds.get(beanTypes.size() - 1) + ")";
357         }
358 
359         return path;
360     }
361 
362     /**
363      * Retrieves the list of xmls file paths found to be related to error
364      *
365      * @return A list of file paths to the related xmls
366      */
367     public ArrayList<String> getRelatedXmls() {
368         return findXmlFiles();
369     }
370 }