View Javadoc

1   /*
2    * Copyright 2005-2008 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.edl.impl.xml;
18  
19  import org.apache.log4j.Logger;
20  import org.kuali.rice.core.api.CoreApiServiceLocator;
21  import org.kuali.rice.core.api.impex.xml.XmlIngestionException;
22  import org.kuali.rice.core.api.style.Style;
23  import org.kuali.rice.core.api.style.StyleService;
24  import org.kuali.rice.core.api.util.xml.XmlException;
25  import org.kuali.rice.core.api.util.xml.XmlJotter;
26  import org.kuali.rice.edl.impl.EDLXmlUtils;
27  import org.kuali.rice.edl.impl.bo.EDocLiteAssociation;
28  import org.kuali.rice.edl.impl.bo.EDocLiteDefinition;
29  import org.kuali.rice.edl.impl.service.EDocLiteService;
30  import org.kuali.rice.edl.impl.service.EdlServiceLocator;
31  import org.kuali.rice.kew.rule.bo.RuleAttribute;
32  import org.kuali.rice.kew.service.KEWServiceLocator;
33  import org.w3c.dom.Document;
34  import org.w3c.dom.Element;
35  import org.w3c.dom.Node;
36  import org.w3c.dom.NodeList;
37  
38  import javax.xml.parsers.DocumentBuilder;
39  import javax.xml.xpath.XPath;
40  import javax.xml.xpath.XPathConstants;
41  import javax.xml.xpath.XPathExpressionException;
42  import javax.xml.xpath.XPathFactory;
43  import java.io.InputStream;
44  import java.util.ArrayList;
45  import java.util.Collection;
46  import java.util.Iterator;
47  
48  
49  /**
50   * An XML parser which parses EDocLite definitions.
51   *
52   * @author Kuali Rice Team (rice.collab@kuali.org)
53   */
54  public class EDocLiteXmlParser {
55  
56  	private static final Logger LOG = Logger.getLogger(EDocLiteXmlParser.class);
57  
58      public static void loadXml(InputStream inputStream, String principalId) {
59          DocumentBuilder db = EDLXmlUtils.getDocumentBuilder();
60          XPath xpath = XPathFactory.newInstance().newXPath();
61          Document doc;
62          // parse and save EDocLiteDefinition, EDocLiteStyle, or EDocLiteAssociation xml from to-be-determined XML format
63          //try {
64          try {
65              doc = db.parse(inputStream);
66          } catch (Exception e) {
67              throw generateException("Error parsing EDocLite XML file", e);
68          }
69              /*try {
70                  LOG.info(XmlHelper.writeNode(doc.getFirstChild(), true));
71              } catch (TransformerException e) {
72                  LOG.warn("Error displaying document");
73              }*/
74  
75              NodeList edls;
76              try {
77                  edls = (NodeList) xpath.evaluate("//edoclite", doc.getFirstChild(), XPathConstants.NODESET);
78              } catch (XPathExpressionException e) {
79                  throw generateException("Error evaluating XPath expression", e);
80              }
81  
82              for (int i = 0; i < edls.getLength(); i++) {
83                  Node edl = edls.item(i);
84                  NodeList children = edl.getChildNodes();
85                  for (int j = 0; j < children.getLength(); j++) {
86                      Node node = children.item(j);
87                      /*try {
88                          LOG.info(XmlHelper.writeNode(node, true));
89                      } catch (TransformerException te) {
90                          LOG.warn("Error displaying node");
91                      }*/
92                      if (node.getNodeType() == Node.ELEMENT_NODE) {
93                          Element e = (Element) node;
94                          if ("style".equals(node.getNodeName())) {
95                              LOG.debug("Digesting EDocLiteStyle: " + e.getAttribute("name"));
96                              Style style = parseStyle(e);
97                              getStyleService().saveStyle(style);
98                          } else if ("edl".equals(node.getNodeName())) {
99                              LOG.debug("Digesting EDocLiteDefinition: " + e.getAttribute("name"));
100                             EDocLiteDefinition def = parseEDocLiteDefinition(e);
101                             getEDLService().saveEDocLiteDefinition(def);
102                         } else if ("association".equals(node.getNodeName())) {
103                             LOG.debug("Digesting EDocLiteAssociation: " + e.getAttribute("name"));
104                             EDocLiteAssociation assoc = parseEDocLiteAssociation(e);
105                             getEDLService().saveEDocLiteAssociation(assoc);
106                         } else {
107                             // LOG.debug("Unrecognized element '" + node.getNodeName() + "' in EDocLite XML doc");
108                         }
109                     }
110                 }
111             }
112         //} catch (Exception e) {
113         //    throw generateException("Error parsing EDocLite XML file", e);
114         //}
115     }
116 
117     private static XmlIngestionException generateException(String error, Throwable cause) {
118     	throw new XmlIngestionException(error, cause);
119     }
120 
121     /**
122      * Parses an EDocLiteAssocation
123      *
124      * @param e
125      *            element to parse
126      * @return an EDocLiteAssocation
127      */
128     private static EDocLiteAssociation parseEDocLiteAssociation(Element e) {
129         String docType = EDLXmlUtils.getChildElementTextValue(e, "docType");
130         if (docType == null) {
131             throw generateMissingChildException("association", "docType");
132         }
133         EDocLiteAssociation assoc = new EDocLiteAssociation();
134         assoc.setEdlName(docType);
135         assoc.setDefinition(EDLXmlUtils.getChildElementTextValue(e, "definition"));
136         assoc.setStyle(EDLXmlUtils.getChildElementTextValue(e, "style"));
137         assoc.setActiveInd(Boolean.valueOf(EDLXmlUtils.getChildElementTextValue(e, "active")));
138         return assoc;
139     }
140 
141     /**
142      * Parses an EDocLiteStyle
143      *
144      * @param e
145      *            element to parse
146      * @return an EDocLiteStyle
147      */
148     private static Style parseStyle(Element e) {
149         String name = e.getAttribute("name");
150         if (name == null || name.length() == 0) {
151             throw generateMissingAttribException("style", "name");
152         }
153         Style.Builder styleBuilder = Style.Builder.create(name);
154         Element stylesheet = null;
155         NodeList children = e.getChildNodes();
156         for (int i = 0; i < children.getLength(); i++) {
157             Node child = children.item(i);
158             /*
159              * LOG.debug("NodeName: " + child.getNodeName()); LOG.debug("LocalName: " + child.getLocalName()); LOG.debug("Prefix: " + child.getPrefix()); LOG.debug("NS URI: " + child.getNamespaceURI());
160              */
161             if (child.getNodeType() == Node.ELEMENT_NODE && "xsl:stylesheet".equals(child.getNodeName())) {
162                 stylesheet = (Element) child;
163                 break;
164             }
165         }
166         if (stylesheet == null) {
167             throw generateMissingChildException("style", "xsl:stylesheet");
168         }
169         try {
170             styleBuilder.setXmlContent(XmlJotter.jotNode(stylesheet, true));
171         } catch (XmlException te) {
172             throw generateSerializationException("style", te);
173         }
174         return styleBuilder.build();
175     }
176 
177     /**
178      * Parses an EDocLiteDefinition
179      *
180      * @param e
181      *            element to parse
182      * @return an EDocLiteDefinition
183      */
184     private static EDocLiteDefinition parseEDocLiteDefinition(Element e) {
185         EDocLiteDefinition def = new EDocLiteDefinition();
186         String name = e.getAttribute("name");
187         if (name == null || name.length() == 0) {
188             throw generateMissingAttribException(EDLXmlUtils.EDL_E, "name");
189         }
190         def.setName(name);
191 
192         // do some validation to ensure that any attributes referenced actually exist
193         // blow up if there is a problem
194 
195         XPath xpath = XPathFactory.newInstance().newXPath();
196         NodeList fields;
197         try {
198             fields = (NodeList) xpath.evaluate("fieldDef", e, XPathConstants.NODESET);
199         } catch (XPathExpressionException xpee) {
200             throw new XmlIngestionException("Invalid EDocLiteDefinition", xpee);
201         }
202 
203         if (fields != null) {
204             Collection invalidAttributes = new ArrayList(5);
205             for (int i = 0; i < fields.getLength(); i++) {
206                 Node node = (Node) fields.item(i);
207                 // they should all be Element...
208                 if (node instanceof Element) {
209                     Element field = (Element) node;
210                     // rely on XML validation to ensure this is present
211                     String fieldName = field.getAttribute("name");
212                     String attribute = field.getAttribute("attributeName");
213                     if (attribute != null && attribute.length() > 0) {
214                         RuleAttribute ruleAttrib = KEWServiceLocator.getRuleAttributeService().findByName(attribute);
215                         if (ruleAttrib == null) {
216                             LOG.error("Invalid attribute referenced in EDocLite definition: " + attribute);
217                             invalidAttributes.add("Attribute '" + attribute + "' referenced in field '" + fieldName + "' not found");
218                         }
219                     }
220                 }
221             }
222             if (invalidAttributes.size() > 0) {
223                 LOG.error("Invalid attributes referenced in EDocLite definition");
224                 StringBuffer message = new StringBuffer("EDocLite definition contains references to non-existent attributes;\n");
225                 Iterator it = invalidAttributes.iterator();
226                 while (it.hasNext()) {
227                     message.append(it.next());
228                     message.append("\n");
229                 }
230                 throw new XmlIngestionException(message.toString());
231             }
232         }
233 
234         try {
235             def.setXmlContent(XmlJotter.jotNode(e, true));
236         } catch (XmlException te) {
237             throw generateSerializationException(EDLXmlUtils.EDL_E, te);
238         }
239         return def;
240     }
241 
242     private static XmlIngestionException generateMissingAttribException(String element, String attrib) {
243         return generateException("EDocLite '" + element + "' element must contain a '" + attrib + "' attribute", null);
244     }
245 
246     private static XmlIngestionException generateMissingChildException(String element, String child) {
247         return generateException("EDocLite '" + element + "' element must contain a '" + child + "' child element", null);
248     }
249 
250     private static XmlIngestionException generateSerializationException(String element, XmlException cause) {
251         return generateException("Error serializing EDocLite '" + element + "' element", cause);
252     }
253 
254     private static EDocLiteService getEDLService() {
255     	return EdlServiceLocator.getEDocLiteService();
256     }
257     
258     private static StyleService getStyleService() {
259     	return CoreApiServiceLocator.getStyleService();
260     }
261 }