View Javadoc
1   /**
2    * Copyright 2005-2015 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.xml;
17  
18  import org.apache.log4j.Logger;
19  import org.kuali.rice.core.api.impex.xml.XmlIngestionException;
20  import org.kuali.rice.coreservice.api.style.Style;
21  import org.kuali.rice.coreservice.api.style.StyleService;
22  import org.kuali.rice.core.api.util.xml.XmlException;
23  import org.kuali.rice.core.api.util.xml.XmlJotter;
24  import org.kuali.rice.coreservice.api.CoreServiceApiServiceLocator;
25  import org.kuali.rice.edl.impl.EDLXmlUtils;
26  import org.kuali.rice.edl.impl.bo.EDocLiteAssociation;
27  import org.kuali.rice.edl.impl.bo.EDocLiteDefinition;
28  import org.kuali.rice.edl.impl.service.EDocLiteService;
29  import org.kuali.rice.edl.impl.service.EdlServiceLocator;
30  import org.kuali.rice.kew.rule.bo.RuleAttribute;
31  import org.kuali.rice.kew.service.KEWServiceLocator;
32  import org.w3c.dom.Document;
33  import org.w3c.dom.Element;
34  import org.w3c.dom.Node;
35  import org.w3c.dom.NodeList;
36  
37  import javax.xml.parsers.DocumentBuilder;
38  import javax.xml.xpath.XPath;
39  import javax.xml.xpath.XPathConstants;
40  import javax.xml.xpath.XPathExpressionException;
41  import javax.xml.xpath.XPathFactory;
42  import java.io.InputStream;
43  import java.util.ArrayList;
44  import java.util.Collection;
45  import java.util.Iterator;
46  
47  
48  /**
49   * An XML parser which parses EDocLite definitions.
50   *
51   * @author Kuali Rice Team (rice.collab@kuali.org)
52   */
53  public class EDocLiteXmlParser {
54  
55  	private static final Logger LOG = Logger.getLogger(EDocLiteXmlParser.class);
56  
57      public static void loadXml(InputStream inputStream, String principalId) {
58          DocumentBuilder db = EDLXmlUtils.getDocumentBuilder();
59          XPath xpath = XPathFactory.newInstance().newXPath();
60          Document doc;
61          // parse and save EDocLiteDefinition, EDocLiteStyle, or EDocLiteAssociation xml from to-be-determined XML format
62          //try {
63          try {
64              doc = db.parse(inputStream);
65          } catch (Exception e) {
66              throw generateException("Error parsing EDocLite XML file", e);
67          }
68              /*try {
69                  LOG.info(XmlHelper.writeNode(doc.getFirstChild(), true));
70              } catch (TransformerException e) {
71                  LOG.warn("Error displaying document");
72              }*/
73  
74              NodeList edls;
75              try {
76                  edls = (NodeList) xpath.evaluate("//edoclite", doc.getFirstChild(), XPathConstants.NODESET);
77              } catch (XPathExpressionException e) {
78                  throw generateException("Error evaluating XPath expression", e);
79              }
80  
81              for (int i = 0; i < edls.getLength(); i++) {
82                  Node edl = edls.item(i);
83                  NodeList children = edl.getChildNodes();
84                  for (int j = 0; j < children.getLength(); j++) {
85                      Node node = children.item(j);
86                      /*try {
87                          LOG.info(XmlHelper.writeNode(node, true));
88                      } catch (TransformerException te) {
89                          LOG.warn("Error displaying node");
90                      }*/
91                      if (node.getNodeType() == Node.ELEMENT_NODE) {
92                          Element e = (Element) node;
93                          if ("style".equals(node.getNodeName())) {
94                              LOG.debug("Digesting EDocLiteStyle: " + e.getAttribute("name"));
95                              Style style = parseStyle(e);
96                              getStyleService().saveStyle(style);
97                          } else if ("edl".equals(node.getNodeName())) {
98                              LOG.debug("Digesting EDocLiteDefinition: " + e.getAttribute("name"));
99                              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 }