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