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