001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: // Created on Jan 4, 2007
018: package edu.iu.uis.eden.edl;
019:
020: import java.io.InputStream;
021: import java.io.StringReader;
022: import java.util.List;
023: import java.util.Properties;
024:
025: import javax.xml.parsers.DocumentBuilderFactory;
026: import javax.xml.transform.Templates;
027: import javax.xml.transform.TransformerConfigurationException;
028: import javax.xml.transform.TransformerException;
029: import javax.xml.transform.TransformerFactory;
030: import javax.xml.transform.URIResolver;
031: import javax.xml.transform.stream.StreamSource;
032:
033: import org.apache.log4j.Logger;
034: import org.w3c.dom.Document;
035: import org.w3c.dom.Element;
036: import org.w3c.dom.Node;
037: import org.w3c.dom.NodeList;
038:
039: import edu.iu.uis.eden.EdenConstants;
040: import edu.iu.uis.eden.KEWServiceLocator;
041: import edu.iu.uis.eden.WorkflowServiceErrorException;
042: import edu.iu.uis.eden.WorkflowServiceErrorImpl;
043: import edu.iu.uis.eden.edl.dao.EDocLiteDAO;
044: import edu.iu.uis.eden.export.ExportDataSet;
045: import edu.iu.uis.eden.user.WorkflowUser;
046: import edu.iu.uis.eden.util.Utilities;
047: import edu.iu.uis.eden.util.XmlHelper;
048: import edu.iu.uis.eden.xml.StyleXmlParser;
049: import edu.iu.uis.eden.xml.export.StyleXmlExporter;
050:
051: /**
052: * Implements generic StyleService via existing EDL style table
053: * @author Aaron Hamid (arh14 at cornell dot edu)
054: */
055: public class StyleServiceImpl implements StyleService {
056: private static final Logger LOG = Logger
057: .getLogger(StyleServiceImpl.class);
058:
059: private static final String TEMPLATES_CACHE_GROUP_NAME = "Templates";
060:
061: /**
062: * The Spring-wired DAO bean
063: */
064: private EDocLiteDAO dao;
065:
066: // ---- Spring DAO setter
067:
068: public void setStyleDAO(EDocLiteDAO dao) {
069: this .dao = dao;
070: }
071:
072: // ---- StyleService interface
073:
074: public EDocLiteStyle getStyle(String styleName) {
075: return dao.getEDocLiteStyle(styleName);
076: }
077:
078: public Templates getStyleAsTranslet(String name)
079: throws TransformerConfigurationException {
080: if (name == null)
081: return null;
082: Templates translet = fetchTemplatesFromCache(name);
083: if (translet == null) {
084: EDocLiteStyle edlStyleData = getStyle(name);
085: if (edlStyleData == null) {
086: //throw new WorkflowRuntimeException("Style " + name + " not found.");
087: return null;
088: }
089:
090: if (new Boolean(
091: Utilities
092: .getApplicationConstant(EdenConstants.APP_CONST_EDL_USE_XSLTC))
093: .booleanValue()) {
094: LOG.info("using xsltc to compile stylesheet");
095: String key = "javax.xml.transform.TransformerFactory";
096: String value = "org.apache.xalan.xsltc.trax.TransformerFactoryImpl";
097: Properties props = System.getProperties();
098: props.put(key, value);
099: System.setProperties(props);
100: }
101:
102: TransformerFactory factory = TransformerFactory
103: .newInstance();
104: URIResolver resolver = new WidgetURIResolver();
105: factory.setURIResolver(resolver);
106:
107: if (new Boolean(
108: Utilities
109: .getApplicationConstant(EdenConstants.APP_CONST_EDL_USE_XSLTC))
110: .booleanValue()) {
111: factory.setAttribute("translet-name", name);
112: factory.setAttribute("generate-translet", Boolean.TRUE);
113: if (new Boolean(
114: Utilities
115: .getApplicationConstant(EdenConstants.APP_CONST_EDL_DEBUG_TRANSFORM))
116: .booleanValue()) {
117: factory.setAttribute("debug", Boolean.TRUE);
118: }
119:
120: }
121:
122: translet = factory.newTemplates(new StreamSource(
123: new StringReader(edlStyleData.getXmlContent())));
124: putTemplatesInCache(name, translet);
125: }
126: return translet;
127: }
128:
129: /**
130: * Returns all styles
131: */
132: public List<EDocLiteStyle> getStyles() {
133: return dao.getEDocLiteStyles();
134: }
135:
136: /**
137: * Returns all style names
138: */
139: public List<String> getStyleNames() {
140: return dao.getEDocLiteStyleNames();
141: }
142:
143: /**
144: * Does not currently take into account style sheet dependences robustly
145: */
146: public void removeStyleFromCache(String styleName) {
147: LOG.info("Removing Style " + styleName
148: + " from the style cache");
149: // we don't know what styles may import other styles so we need to flush them all
150: KEWServiceLocator.getCacheAdministrator().flushGroup(
151: TEMPLATES_CACHE_GROUP_NAME);
152: //KEWServiceLocator.getCacheAdministrator().flushEntry(getTemplatesCacheKey(styleName));
153: }
154:
155: public void saveStyle(InputStream xml) {
156: // convert xml to EDocLiteStyle
157: EDocLiteStyle data = parseEDocLiteStyle(parse(xml)
158: .getDocumentElement());
159: saveStyle(data);
160: }
161:
162: public void saveStyle(EDocLiteStyle data) {
163: EDocLiteStyle existingData = getStyle(data.getName());
164: if (existingData != null) {
165: existingData.setActiveInd(Boolean.FALSE);
166: dao.saveEDocLiteStyle(existingData);
167: }
168: // if not specified (from xml), mark it as active
169: if (data.getActiveInd() == null) {
170: data.setActiveInd(Boolean.TRUE);
171: }
172: dao.saveEDocLiteStyle(data);
173: removeStyleFromCache(data.getName());
174: }
175:
176: // ---- XmlLoader interface implementation
177:
178: public void loadXml(InputStream inputStream, WorkflowUser user) {
179: StyleXmlParser.loadXml(this , inputStream, user);
180: }
181:
182: // ---- XmlExporter interface implementation
183: public org.jdom.Element export(ExportDataSet dataSet) {
184: return new StyleXmlExporter().export(dataSet);
185: }
186:
187: // cache helper methods
188:
189: /**
190: * Returns the key to be used for caching the Templates for the given style name.
191: */
192: protected String getTemplatesCacheKey(String styleName) {
193: return TEMPLATES_CACHE_GROUP_NAME + ":" + styleName;
194: }
195:
196: protected Templates fetchTemplatesFromCache(String styleName) {
197: return (Templates) KEWServiceLocator.getCacheAdministrator()
198: .getFromCache(getTemplatesCacheKey(styleName));
199: }
200:
201: protected void putTemplatesInCache(String styleName,
202: Templates templates) {
203: KEWServiceLocator.getCacheAdministrator().putInCache(
204: getTemplatesCacheKey(styleName), templates,
205: TEMPLATES_CACHE_GROUP_NAME);
206: }
207:
208: // parsing helper methods
209:
210: /**
211: * Parses an EDocLiteStyle
212: *
213: * @param e
214: * element to parse
215: * @return an EDocLiteStyle
216: */
217: private static EDocLiteStyle parseEDocLiteStyle(Element e) {
218: String name = e.getAttribute("name");
219: if (name == null || name.length() == 0) {
220: throw generateMissingAttribException("style", "name");
221: }
222: EDocLiteStyle style = new EDocLiteStyle();
223: style.setName(name);
224: Element stylesheet = null;
225: NodeList children = e.getChildNodes();
226: for (int i = 0; i < children.getLength(); i++) {
227: Node child = children.item(i);
228: /*
229: * LOG.debug("NodeName: " + child.getNodeName()); LOG.debug("LocalName: " + child.getLocalName()); LOG.debug("Prefix: " + child.getPrefix()); LOG.debug("NS URI: " + child.getNamespaceURI());
230: */
231: if (child.getNodeType() == Node.ELEMENT_NODE
232: && "xsl:stylesheet".equals(child.getNodeName())) {
233: stylesheet = (Element) child;
234: break;
235: }
236: }
237: if (stylesheet == null) {
238: throw generateMissingChildException("style",
239: "xsl:stylesheet");
240: }
241: try {
242: style.setXmlContent(XmlHelper.writeNode(stylesheet, true));
243: } catch (TransformerException te) {
244: throw generateSerializationException("style", te);
245: }
246: return style;
247: }
248:
249: /**
250: * Parses an arbitrary XML stream
251: *
252: * @param stream
253: * stream containing XML doc content
254: * @return parsed Document object
255: */
256: private static Document parse(InputStream stream) {
257: try {
258: return DocumentBuilderFactory.newInstance()
259: .newDocumentBuilder().parse(stream);
260: } catch (Exception e) {
261: WorkflowServiceErrorException wsee = new WorkflowServiceErrorException(
262: "Error parsing Style XML file",
263: new WorkflowServiceErrorImpl(
264: "Error parsing XML file.",
265: EdenConstants.XML_FILE_PARSE_ERROR));
266: wsee.initCause(e);
267: throw wsee;
268: }
269: }
270:
271: private static WorkflowServiceErrorException generateMissingAttribException(
272: String element, String attrib) {
273: return generateException(
274: "Style '" + element + "' element must contain a '"
275: + attrib + "' attribute", null);
276: }
277:
278: private static WorkflowServiceErrorException generateMissingChildException(
279: String element, String child) {
280: return generateException("Style '" + element
281: + "' element must contain a '" + child
282: + "' child element", null);
283: }
284:
285: private static WorkflowServiceErrorException generateSerializationException(
286: String element, TransformerException cause) {
287: return generateException("Error serializing EDocLite '"
288: + element + "' element", cause);
289: }
290:
291: private static WorkflowServiceErrorException generateException(
292: String error, Throwable cause) {
293: WorkflowServiceErrorException wsee = new WorkflowServiceErrorException(
294: error, new WorkflowServiceErrorImpl(error,
295: EdenConstants.XML_FILE_PARSE_ERROR));
296: if (cause != null) {
297: wsee.initCause(cause);
298: }
299: return wsee;
300: }
301: }
|