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