View Javadoc

1   /**
2    * Copyright 2005-2012 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.coreservice.impl.style;
17  
18  import org.apache.log4j.Logger;
19  import org.kuali.rice.core.api.impex.xml.XmlConstants;
20  import org.kuali.rice.core.api.impex.xml.XmlIngestionException;
21  import org.kuali.rice.coreservice.api.style.Style;
22  import org.kuali.rice.coreservice.api.style.StyleService;
23  import org.kuali.rice.core.api.util.xml.XmlException;
24  import org.kuali.rice.core.api.util.xml.XmlJotter;
25  import org.w3c.dom.Document;
26  import org.w3c.dom.Element;
27  import org.w3c.dom.Node;
28  import org.w3c.dom.NodeList;
29  
30  import javax.xml.parsers.DocumentBuilder;
31  import javax.xml.parsers.DocumentBuilderFactory;
32  import javax.xml.parsers.ParserConfigurationException;
33  import javax.xml.xpath.XPath;
34  import javax.xml.xpath.XPathConstants;
35  import javax.xml.xpath.XPathExpressionException;
36  import javax.xml.xpath.XPathFactory;
37  import java.io.InputStream;
38  import java.util.ArrayList;
39  import java.util.List;
40  
41  
42  /**
43   * Parser for Style content type, managed by StyleService
44   * @author Kuali Rice Team (rice.collab@kuali.org)
45   */
46  public class StyleXmlParserImpl implements StyleXmlParser {
47  	private static final Logger LOG = Logger.getLogger(StyleXmlParserImpl.class);
48  
49  	private StyleService styleService;
50  	
51      private static ThreadLocal<DocumentBuilder> DOCUMENT_BUILDER = new ThreadLocal<DocumentBuilder>() {
52          protected DocumentBuilder initialValue() {
53              try {
54                  return DocumentBuilderFactory.newInstance().newDocumentBuilder();
55              } catch (ParserConfigurationException pce) {
56                  // well folks, there is not much we can do if we get a ParserConfigurationException
57                  // so might as well isolate the evilness here, and just balk if this occurs
58                  String message = "Error obtaining document builder";
59                  LOG.error(message, pce);
60                  throw new RuntimeException(message, pce);
61              }
62          }
63      };
64  
65      /**
66       * Returns a valid DocumentBuilder
67       * @return a valid DocumentBuilder
68       */
69      private static DocumentBuilder getDocumentBuilder() {
70          return (DocumentBuilder) DOCUMENT_BUILDER.get();
71      }
72  
73      public void loadXml(InputStream inputStream, String principalId) {
74      	List<Style> styles = parseStyles(inputStream);
75      	for (Style style : styles) {
76      		styleService.saveStyle(style);
77      	}
78      }
79      
80      public List<Style> parseStyles(InputStream inputStream) {
81      	DocumentBuilder db = getDocumentBuilder();
82          XPath xpath = XPathFactory.newInstance().newXPath();
83          Document doc;
84          try {
85              doc = db.parse(inputStream);
86          } catch (Exception e) {
87              throw generateException("Error parsing Style XML file", e);
88          }
89          NodeList styles;
90          try {
91          	styles = (NodeList) xpath.evaluate("//" + XmlConstants.STYLE_STYLES, doc.getFirstChild(), XPathConstants.NODESET);
92          } catch (XPathExpressionException e) {
93          	throw generateException("Error evaluating XPath expression", e);
94          }
95  
96          List<Style> parsedStyles = new ArrayList<Style>();
97          for (int i = 0; i < styles.getLength(); i++) {
98          	Node edl = styles.item(i);
99          	NodeList children = edl.getChildNodes();
100         	for (int j = 0; j < children.getLength(); j++) {
101         		Node node = children.item(j);
102         		if (node.getNodeType() == Node.ELEMENT_NODE) {
103         			Element e = (Element) node;
104         			if (XmlConstants.STYLE_STYLE.equals(node.getNodeName())) {
105         				LOG.debug("Digesting style: " + e.getAttribute("name"));
106         				Style.Builder styleBuilder = parseStyle(e);
107         				parsedStyles.add(styleBuilder.build());
108         			}
109                 }
110             }
111         }
112         return parsedStyles;
113     }
114     
115     /**
116      * Parses an EDocLiteStyle
117      *
118      * @param e
119      *            element to parse
120      * @return an EDocLiteStyle
121      */
122     private static Style.Builder parseStyle(Element e) {
123         String name = e.getAttribute("name");
124         if (name == null || name.length() == 0) {
125             throw generateMissingAttribException(XmlConstants.STYLE_STYLE, "name");
126         }
127         Style.Builder style = Style.Builder.create(name);
128         Element stylesheet = null;
129         NodeList children = e.getChildNodes();
130         for (int i = 0; i < children.getLength(); i++) {
131             Node child = children.item(i);
132             if (child.getNodeType() == Node.ELEMENT_NODE && "xsl:stylesheet".equals(child.getNodeName())) {
133                 stylesheet = (Element) child;
134                 break;
135             }
136         }
137         if (stylesheet == null) {
138             throw generateMissingChildException(XmlConstants.STYLE_STYLE, "xsl:stylesheet");
139         }
140         try {
141             style.setXmlContent(XmlJotter.jotNode(stylesheet, true));
142         } catch (XmlException te) {
143             throw generateSerializationException(XmlConstants.STYLE_STYLE, te);
144         }
145         return style;
146     }
147 
148     private static XmlIngestionException generateMissingAttribException(String element, String attrib) {
149         return generateException("Style '" + element + "' element must contain a '" + attrib + "' attribute", null);
150     }
151 
152     private static XmlIngestionException generateMissingChildException(String element, String child) {
153         return generateException("Style '" + element + "' element must contain a '" + child + "' child element", null);
154     }
155 
156     private static XmlIngestionException generateSerializationException(String element, XmlException cause) {
157         return generateException("Error serializing Style '" + element + "' element", cause);
158     }
159     
160     private static XmlIngestionException generateException(String error, Throwable cause) {
161     	return new XmlIngestionException(error, cause);
162     }
163     
164     public void setStyleService(StyleService styleService) {
165     	this.styleService = styleService;
166     }
167 
168 }