View Javadoc

1   /**
2    * Copyright 2005-2011 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.edl.impl;
17  
18  import java.util.Date;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  
23  import javax.xml.parsers.DocumentBuilder;
24  import javax.xml.parsers.DocumentBuilderFactory;
25  import javax.xml.parsers.ParserConfigurationException;
26  
27  import org.apache.log4j.Logger;
28  import org.kuali.rice.edl.impl.components.MatchingParam;
29  import org.kuali.rice.kew.api.WorkflowRuntimeException;
30  import org.w3c.dom.Document;
31  import org.w3c.dom.Element;
32  import org.w3c.dom.Node;
33  import org.w3c.dom.NodeList;
34  
35  
36  /**
37   * Contains a bunch of dom utility methods.
38   *
39   * @author Kuali Rice Team (rice.collab@kuali.org)
40   *
41   */
42  public final class EDLXmlUtils {
43  
44  	private static final Logger LOG = Logger.getLogger(EDLXmlUtils.class);
45  
46  	public static final String EDL_E = "edl";
47  	public static final String EDLCONTENT_E = "edlContent";
48  	public static final String DATA_E = "data";
49  	public static final String TYPE_E = "type";
50  	public static final String VALIDATION_E = "validation";
51  	public static final String VERSION_E = "version";
52  	public static final String DOCID_E = "docId";
53  
54      private static ThreadLocal DOCUMENT_BUILDER = new ThreadLocal() {
55          protected Object initialValue() {
56              try {
57                  return DocumentBuilderFactory.newInstance().newDocumentBuilder();
58              } catch (ParserConfigurationException pce) {
59                  // well folks, there is not much we can do if we get a ParserConfigurationException
60                  // so might as well isolate the evilness here, and just balk if this occurs
61                  String message = "Error obtaining document builder";
62                  LOG.error(message, pce);
63                  return new RuntimeException(message, pce);
64              }
65          }
66      };
67      
68  	private EDLXmlUtils() {
69  		throw new UnsupportedOperationException("do not call");
70  	}
71  
72      /**
73       * Returns a valid DocumentBuilder
74       * @return a valid DocumentBuilder
75       */
76      public static DocumentBuilder getDocumentBuilder() {
77          return (DocumentBuilder) DOCUMENT_BUILDER.get();
78      }
79  
80  
81  	public static Element createFieldDataElement(Element parentVersionElement, MatchingParam matchingParam) {
82  		Element fieldData = createChildElement(parentVersionElement, "field");
83  		fieldData.setAttribute("name", matchingParam.getParamName());
84  		if (matchingParam.getError().booleanValue()) {
85  			fieldData.setAttribute("invalid", "true");
86  			Element errorMessage = getOrCreateChildElement(fieldData, "errorMessage", true);
87  			placeTextInElement(errorMessage, matchingParam.getErrorMessage());
88  		}
89  		Element fieldValue = getOrCreateChildElement(fieldData, "value", true);
90  		placeTextInElement(fieldValue, matchingParam.getParamValue());
91  		return fieldData;
92  	}
93  
94  	public static Element createChildElement(Element parentElement, String elementName) {
95  		Element child = parentElement.getOwnerDocument().createElement(elementName);
96  		parentElement.appendChild(child);
97  		return child;
98  	}
99  
100 	public static Element getDocumentStateElement(Document dom) {
101 		return EDLXmlUtils.getOrCreateChildElement(dom.getDocumentElement(), "documentState", true);
102 	}
103 
104 
105 	public static void addGlobalErrorMessage(Document dom, String errorMessage) {
106 		Element documentState = getDocumentStateElement(dom);
107 		createTextElementOnParent(documentState, "error", errorMessage);
108 	}
109 
110 	private static void placeTextInElement(Element element, String text) {
111 		if (element.getOwnerDocument() == null) {
112 			throw new WorkflowRuntimeException("The element must have an owner document in order to add text");
113 		}
114 		element.appendChild(element.getOwnerDocument().createTextNode(text));
115 	}
116 
117 	public static Element createTextElementOnParent(Element parent, String childElementName, String text) {
118 		if (text == null) {
119 			throw new WorkflowRuntimeException("The text placed in an Element cannot be null");
120 		}
121 		Element childElement = parent.getOwnerDocument().createElement(childElementName);
122 		parent.appendChild(childElement);
123 		childElement.appendChild(parent.getOwnerDocument().createTextNode(text));
124 		return childElement;
125 	}
126 
127 	public static Element getVersionFromData(Element dataElement, Integer versionCount) {
128 		if (dataElement == null) {
129 			throw new WorkflowRuntimeException("Attempting to put version element inside null data Element");
130 		}
131 		if (!dataElement.getTagName().equals(DATA_E)) {
132 			throw new WorkflowRuntimeException("Attempting to put version element inside a parent that is not a data element " + dataElement.getTagName());
133 		}
134 		Element version = createChildElement(dataElement, VERSION_E);
135 		version.setAttribute("current", "true");
136 		version.setAttribute("date", new Date().toString());
137 		version.setAttribute("version", versionCount.toString());
138 		return version;
139 	}
140 
141 	public static Element getDataFromEDLDocument(Element edlContent, boolean create) {
142         return getOrCreateChildElement(edlContent, DATA_E, create);
143     }
144 
145     public static Element getEDLContent(Document displayDoc, boolean create) {
146         return getOrCreateChildElement(displayDoc.getDocumentElement(), EDLCONTENT_E, create);
147     }
148 
149     /**
150      * Returns, and creates if absent, a child element
151      * @param parent the parent element
152      * @param name the name of the child element to create and/or return
153      * @return reference to the child element
154      */
155     public static Element getOrCreateChildElement(Element parent, String name, boolean create) {
156         if (parent == null) {
157         	throw new WorkflowRuntimeException("Passed in null parent element attempting to create child element '" + name + "'");
158         }
159         Element child = getChildElement(parent, name);
160         if (child == null && create) {
161             LOG.debug("Creating child element '" + name + "' of parent: " + parent);
162             child = parent.getOwnerDocument().createElement(name);
163             parent.appendChild(child);
164         }
165         return child;
166     }
167 
168     /**
169      * Returns a node child with the specified tag name of the specified parent node,
170      * or null if no such child node is found.
171      * @param parent the parent node
172      * @param name the name of the child node
173      * @return child node if found, null otherwise
174      */
175     public static Element getChildElement(Node parent, String name) {
176         NodeList childList = parent.getChildNodes();
177         for (int i = 0; i < childList.getLength(); i++) {
178             Node node = childList.item(i);
179             // we must test against NodeName, not just LocalName
180             // LocalName seems to be null - I am guessing this is because
181             // the DocumentBuilderFactory is not "namespace aware"
182             // although I would have expected LocalName to default to
183             // NodeName
184             if (node.getNodeType() == Node.ELEMENT_NODE
185                 && (name.equals(node.getLocalName())
186                    || name.equals(node.getNodeName()))) {
187                 return (Element) node;
188             }
189         }
190         return null;
191     }
192 
193     /**
194      * Returns the text value of a child element with the given name, of the given parent element,
195      * or null if the child does not exist or does not have a child text node
196      * @param parent parent element
197      * @param name name of child element
198      * @return the text value of a child element with the given name, of the given parent element,
199      * or null if the child does not exist or does not have a child text node
200      */
201     public static String getChildElementTextValue(Node parent, String name) {
202         Element child = getChildElement(parent, name);
203         if (child == null) {
204             return null;
205         }
206         Node textNode = child.getFirstChild();
207         if (textNode == null) {
208             return null;
209         }
210         return textNode.getNodeValue();
211     }
212 
213 
214 
215     /**
216      * Adds the specified errors and messages to the &lt;documentState&gt; element of the
217      * given EDL doc
218      * @param doc the EDL doc
219      * @param errors the list of error Strings
220      * @param messages the list of message Strings
221      */
222     public static void addErrorsAndMessagesToDocument(Document doc, List errors, List messages, Map<String, String> fieldErrors) {
223         Node documentState = EDLXmlUtils.getDocumentStateElement(doc);
224         Iterator it = errors.iterator();
225         while (it.hasNext()) {
226             Element error = doc.createElement("error");
227             error.appendChild(doc.createTextNode(it.next().toString()));
228             documentState.appendChild(error);
229         }
230         it = messages.iterator();
231         while (it.hasNext()) {
232             Element error = doc.createElement("message");
233             error.appendChild(doc.createTextNode(it.next().toString()));
234             documentState.appendChild(error);
235         }
236         for (String errorKey : fieldErrors.keySet()) {
237         	Element error = doc.createElement("fieldError");
238         	error.setAttribute("key", errorKey);
239         	error.appendChild(doc.createTextNode(fieldErrors.get(errorKey)));
240         	documentState.appendChild(error);
241         }
242     }
243 
244 }
245 
246