001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.xml;
018:
019: import java.io.InputStream;
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.Iterator;
023:
024: import javax.xml.parsers.DocumentBuilder;
025: import javax.xml.transform.TransformerException;
026: import javax.xml.xpath.XPath;
027: import javax.xml.xpath.XPathConstants;
028: import javax.xml.xpath.XPathExpressionException;
029: import javax.xml.xpath.XPathFactory;
030:
031: import org.apache.log4j.Logger;
032: import org.w3c.dom.Document;
033: import org.w3c.dom.Element;
034: import org.w3c.dom.Node;
035: import org.w3c.dom.NodeList;
036:
037: import edu.iu.uis.eden.EdenConstants;
038: import edu.iu.uis.eden.KEWServiceLocator;
039: import edu.iu.uis.eden.WorkflowServiceErrorException;
040: import edu.iu.uis.eden.WorkflowServiceErrorImpl;
041: import edu.iu.uis.eden.edl.EDLXmlUtils;
042: import edu.iu.uis.eden.edl.EDocLiteAssociation;
043: import edu.iu.uis.eden.edl.EDocLiteDefinition;
044: import edu.iu.uis.eden.edl.EDocLiteService;
045: import edu.iu.uis.eden.edl.EDocLiteStyle;
046: import edu.iu.uis.eden.routetemplate.RuleAttribute;
047: import edu.iu.uis.eden.user.WorkflowUser;
048: import edu.iu.uis.eden.util.XmlHelper;
049:
050: /**
051: * An XML parser which parses EDocLite definitions.
052: *
053: * @author rkirkend
054: */
055: public class EDocLiteXmlParser {
056:
057: private static final Logger LOG = Logger
058: .getLogger(EDocLiteXmlParser.class);
059:
060: public static void loadXml(InputStream inputStream,
061: WorkflowUser user) {
062: DocumentBuilder db = EDLXmlUtils.getDocumentBuilder();
063: XPath xpath = XPathFactory.newInstance().newXPath();
064: Document doc;
065: // parse and save EDocLiteDefinition, EDocLiteStyle, or EDocLiteAssociation xml from to-be-determined XML format
066: //try {
067: try {
068: doc = db.parse(inputStream);
069: } catch (Exception e) {
070: throw generateException("Error parsing EDocLite XML file",
071: e);
072: }
073: /*try {
074: LOG.info(XmlHelper.writeNode(doc.getFirstChild(), true));
075: } catch (TransformerException e) {
076: LOG.warn("Error displaying document");
077: }*/
078:
079: NodeList edls;
080: try {
081: edls = (NodeList) xpath.evaluate("//edoclite", doc
082: .getFirstChild(), XPathConstants.NODESET);
083: } catch (XPathExpressionException e) {
084: throw generateException(
085: "Error evaluating XPath expression", e);
086: }
087:
088: for (int i = 0; i < edls.getLength(); i++) {
089: Node edl = edls.item(i);
090: NodeList children = edl.getChildNodes();
091: for (int j = 0; j < children.getLength(); j++) {
092: Node node = children.item(j);
093: /*try {
094: LOG.info(XmlHelper.writeNode(node, true));
095: } catch (TransformerException te) {
096: LOG.warn("Error displaying node");
097: }*/
098: if (node.getNodeType() == Node.ELEMENT_NODE) {
099: Element e = (Element) node;
100: if ("style".equals(node.getNodeName())) {
101: LOG.debug("Digesting EDocLiteStyle: "
102: + e.getAttribute("name"));
103: EDocLiteStyle style = parseEDocLiteStyle(e);
104: getEDLService().saveEDocLiteStyle(style);
105: } else if ("edl".equals(node.getNodeName())) {
106: LOG.debug("Digesting EDocLiteDefinition: "
107: + e.getAttribute("name"));
108: EDocLiteDefinition def = parseEDocLiteDefinition(e);
109: getEDLService().saveEDocLiteDefinition(def);
110: } else if ("association".equals(node.getNodeName())) {
111: LOG.debug("Digesting EDocLiteAssociation: "
112: + e.getAttribute("name"));
113: EDocLiteAssociation assoc = parseEDocLiteAssociation(e);
114: getEDLService().saveEDocLiteAssociation(assoc);
115: } else {
116: // LOG.debug("Unrecognized element '" + node.getNodeName() + "' in EDocLite XML doc");
117: }
118: }
119: }
120: }
121: //} catch (Exception e) {
122: // throw generateException("Error parsing EDocLite XML file", e);
123: //}
124: }
125:
126: private static WorkflowServiceErrorException generateException(
127: String error, Throwable cause) {
128: WorkflowServiceErrorException wsee = new WorkflowServiceErrorException(
129: error, new WorkflowServiceErrorImpl(error,
130: EdenConstants.XML_FILE_PARSE_ERROR));
131: if (cause != null) {
132: wsee.initCause(cause);
133: }
134: return wsee;
135: }
136:
137: /**
138: * Parses an EDocLiteAssocation
139: *
140: * @param e
141: * element to parse
142: * @return an EDocLiteAssocation
143: */
144: private static EDocLiteAssociation parseEDocLiteAssociation(
145: Element e) {
146: String docType = EDLXmlUtils.getChildElementTextValue(e,
147: "docType");
148: if (docType == null) {
149: throw generateMissingChildException("association",
150: "docType");
151: }
152: EDocLiteAssociation assoc = new EDocLiteAssociation();
153: assoc.setEdlName(docType);
154: assoc.setDefinition(EDLXmlUtils.getChildElementTextValue(e,
155: "definition"));
156: assoc
157: .setStyle(EDLXmlUtils.getChildElementTextValue(e,
158: "style"));
159: assoc.setActiveInd(Boolean.valueOf(EDLXmlUtils
160: .getChildElementTextValue(e, "active")));
161: return assoc;
162: }
163:
164: /**
165: * Parses an EDocLiteStyle
166: *
167: * @param e
168: * element to parse
169: * @return an EDocLiteStyle
170: */
171: private static EDocLiteStyle parseEDocLiteStyle(Element e) {
172: String name = e.getAttribute("name");
173: if (name == null || name.length() == 0) {
174: throw generateMissingAttribException("style", "name");
175: }
176: EDocLiteStyle style = new EDocLiteStyle();
177: style.setName(name);
178: Element stylesheet = null;
179: NodeList children = e.getChildNodes();
180: for (int i = 0; i < children.getLength(); i++) {
181: Node child = children.item(i);
182: /*
183: * LOG.debug("NodeName: " + child.getNodeName()); LOG.debug("LocalName: " + child.getLocalName()); LOG.debug("Prefix: " + child.getPrefix()); LOG.debug("NS URI: " + child.getNamespaceURI());
184: */
185: if (child.getNodeType() == Node.ELEMENT_NODE
186: && "xsl:stylesheet".equals(child.getNodeName())) {
187: stylesheet = (Element) child;
188: break;
189: }
190: }
191: if (stylesheet == null) {
192: throw generateMissingChildException("style",
193: "xsl:stylesheet");
194: }
195: try {
196: style.setXmlContent(XmlHelper.writeNode(stylesheet, true));
197: } catch (TransformerException te) {
198: throw generateSerializationException("style", te);
199: }
200: return style;
201: }
202:
203: /**
204: * Parses an EDocLiteDefinition
205: *
206: * @param e
207: * element to parse
208: * @return an EDocLiteDefinition
209: */
210: private static EDocLiteDefinition parseEDocLiteDefinition(Element e) {
211: EDocLiteDefinition def = new EDocLiteDefinition();
212: String name = e.getAttribute("name");
213: if (name == null || name.length() == 0) {
214: throw generateMissingAttribException(EDLXmlUtils.EDL_E,
215: "name");
216: }
217: def.setName(name);
218:
219: // do some validation to ensure that any attributes referenced actually exist
220: // blow up if there is a problem
221:
222: XPath xpath = XPathFactory.newInstance().newXPath();
223: NodeList fields;
224: try {
225: fields = (NodeList) xpath.evaluate("fieldDef", e,
226: XPathConstants.NODESET);
227: } catch (XPathExpressionException xpee) {
228: throw new RuntimeException("Invalid EDocLiteDefinition",
229: xpee);
230: }
231:
232: if (fields != null) {
233: Collection invalidAttributes = new ArrayList(5);
234: for (int i = 0; i < fields.getLength(); i++) {
235: Node node = (Node) fields.item(i);
236: // they should all be Element...
237: if (node instanceof Element) {
238: Element field = (Element) node;
239: // rely on XML validation to ensure this is present
240: String fieldName = field.getAttribute("name");
241: String attribute = field
242: .getAttribute("attributeName");
243: if (attribute != null && attribute.length() > 0) {
244: RuleAttribute ruleAttrib = KEWServiceLocator
245: .getRuleAttributeService().findByName(
246: attribute);
247: if (ruleAttrib == null) {
248: LOG
249: .error("Invalid attribute referenced in EDocLite definition: "
250: + attribute);
251: invalidAttributes.add("Attribute '"
252: + attribute
253: + "' referenced in field '"
254: + fieldName + "' not found");
255: }
256: }
257: }
258: }
259: if (invalidAttributes.size() > 0) {
260: LOG
261: .error("Invalid attributes referenced in EDocLite definition");
262: StringBuffer message = new StringBuffer(
263: "EDocLite definition contains references to non-existent attributes;\n");
264: Iterator it = invalidAttributes.iterator();
265: while (it.hasNext()) {
266: message.append(it.next());
267: message.append("\n");
268: }
269: throw new RuntimeException(message.toString());
270: }
271: }
272:
273: try {
274: def.setXmlContent(XmlHelper.writeNode(e, true));
275: } catch (TransformerException te) {
276: throw generateSerializationException(EDLXmlUtils.EDL_E, te);
277: }
278: return def;
279: }
280:
281: private static WorkflowServiceErrorException generateMissingAttribException(
282: String element, String attrib) {
283: return generateException(
284: "EDocLite '" + element + "' element must contain a '"
285: + attrib + "' attribute", null);
286: }
287:
288: private static WorkflowServiceErrorException generateMissingChildException(
289: String element, String child) {
290: return generateException("EDocLite '" + element
291: + "' element must contain a '" + child
292: + "' child element", null);
293: }
294:
295: private static WorkflowServiceErrorException generateSerializationException(
296: String element, TransformerException cause) {
297: return generateException("Error serializing EDocLite '"
298: + element + "' element", cause);
299: }
300:
301: private static EDocLiteService getEDLService() {
302: return KEWServiceLocator.getEDocLiteService();
303: }
304: }
|