View Javadoc

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