source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 14.8 KB
Line 
1/*
2 * Copyright 2001-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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 */
17
18package org.apache.tools.ant.taskdefs.optional;
19
20import java.io.BufferedInputStream;
21import java.io.BufferedOutputStream;
22import java.io.File;
23import java.io.FileInputStream;
24import java.io.FileOutputStream;
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.OutputStream;
28import java.util.Vector;
29import java.util.Enumeration;
30import javax.xml.parsers.ParserConfigurationException;
31import javax.xml.parsers.SAXParserFactory;
32import javax.xml.transform.ErrorListener;
33import javax.xml.transform.Source;
34import javax.xml.transform.SourceLocator;
35import javax.xml.transform.Templates;
36import javax.xml.transform.Transformer;
37import javax.xml.transform.TransformerException;
38import javax.xml.transform.TransformerFactory;
39import javax.xml.transform.URIResolver;
40import javax.xml.transform.sax.SAXSource;
41import javax.xml.transform.stream.StreamResult;
42import javax.xml.transform.stream.StreamSource;
43import javax.xml.transform.TransformerConfigurationException;
44import org.apache.tools.ant.BuildException;
45import org.apache.tools.ant.taskdefs.XSLTLiaison2;
46import org.apache.tools.ant.taskdefs.XSLTProcess;
47import org.apache.tools.ant.taskdefs.XSLTLogger;
48import org.apache.tools.ant.taskdefs.XSLTLoggerAware;
49import org.apache.tools.ant.types.XMLCatalog;
50import org.apache.tools.ant.util.JAXPUtils;
51import org.xml.sax.EntityResolver;
52import org.xml.sax.InputSource;
53import org.xml.sax.SAXException;
54import org.xml.sax.XMLReader;
55
56/**
57 * Concrete liaison for XSLT processor implementing TraX. (ie JAXP 1.1)
58 *
59 * @since Ant 1.3
60 */
61public class TraXLiaison implements XSLTLiaison2, ErrorListener, XSLTLoggerAware {
62
63 /**
64 * the name of the factory implementation class to use
65 * or null for default JAXP lookup.
66 */
67 private String factoryName = null;
68
69 /** The trax TransformerFactory */
70 private TransformerFactory tfactory = null;
71
72 /** stylesheet to use for transformation */
73 private File stylesheet;
74
75 private XSLTLogger logger;
76
77 /** possible resolver for publicIds */
78 private EntityResolver entityResolver;
79
80 /** transformer to use for processing files */
81 private Transformer transformer;
82
83 /** The In memory version of the stylesheet */
84 private Templates templates;
85
86 /**
87 * The modification time of the stylesheet from which the templates
88 * are read
89 */
90 private long templatesModTime;
91
92 /** possible resolver for URIs */
93 private URIResolver uriResolver;
94
95 /** transformer output properties */
96 private Vector outputProperties = new Vector();
97
98 /** stylesheet parameters */
99 private Vector params = new Vector();
100
101 /** factory attributes */
102 private Vector attributes = new Vector();
103
104 public TraXLiaison() throws Exception {
105 }
106
107 public void setStylesheet(File stylesheet) throws Exception {
108 if (this.stylesheet != null) {
109 // resetting the stylesheet - reset transformer
110 transformer = null;
111
112 // do we need to reset templates as well
113 if (!this.stylesheet.equals(stylesheet)
114 || (stylesheet.lastModified() != templatesModTime)) {
115 templates = null;
116 }
117 }
118 this.stylesheet = stylesheet;
119 }
120
121 public void transform(File infile, File outfile) throws Exception {
122 if (transformer == null) {
123 createTransformer();
124 }
125
126 InputStream fis = null;
127 OutputStream fos = null;
128 try {
129 fis = new BufferedInputStream(new FileInputStream(infile));
130 fos = new BufferedOutputStream(new FileOutputStream(outfile));
131 StreamResult res = new StreamResult(fos);
132 // not sure what could be the need of this...
133 res.setSystemId(JAXPUtils.getSystemId(outfile));
134 Source src = getSource(fis, infile);
135 transformer.transform(src, res);
136 } finally {
137 // make sure to close all handles, otherwise the garbage
138 // collector will close them...whenever possible and
139 // Windows may complain about not being able to delete files.
140 try {
141 if (fis != null) {
142 fis.close();
143 }
144 } catch (IOException ignored) {
145 // ignore
146 }
147 try {
148 if (fos != null) {
149 fos.close();
150 }
151 } catch (IOException ignored) {
152 // ignore
153 }
154 }
155 }
156
157 /**
158 * Get the source instance from the stream and id of the file.
159 * @param is the stream containing the stylesheet data.
160 * @param infile the file that will be used for the systemid.
161 * @return the configured source instance matching the stylesheet.
162 * @throws Exception if there is a problem creating the source.
163 */
164 private Source getSource(InputStream is, File infile)
165 throws ParserConfigurationException, SAXException {
166 // todo: is this comment still relevant ??
167 // FIXME: need to use a SAXSource as the source for the transform
168 // so we can plug in our own entity resolver
169 Source src = null;
170 if (entityResolver != null) {
171 if (getFactory().getFeature(SAXSource.FEATURE)) {
172 SAXParserFactory spFactory = SAXParserFactory.newInstance();
173 spFactory.setNamespaceAware(true);
174 XMLReader reader = spFactory.newSAXParser().getXMLReader();
175 reader.setEntityResolver(entityResolver);
176 src = new SAXSource(reader, new InputSource(is));
177 } else {
178 throw new IllegalStateException("xcatalog specified, but "
179 + "parser doesn't support SAX");
180 }
181 } else {
182 // WARN: Don't use the StreamSource(File) ctor. It won't work with
183 // xalan prior to 2.2 because of systemid bugs.
184 src = new StreamSource(is);
185 }
186 src.setSystemId(JAXPUtils.getSystemId(infile));
187 return src;
188 }
189
190 /**
191 * Read in templates from the stylesheet
192 */
193 private void readTemplates()
194 throws IOException, TransformerConfigurationException,
195 ParserConfigurationException, SAXException {
196
197 // Use a stream so that you can close it yourself quickly
198 // and avoid keeping the handle until the object is garbaged.
199 // (always keep control), otherwise you won't be able to delete
200 // the file quickly on windows.
201 InputStream xslStream = null;
202 try {
203 xslStream
204 = new BufferedInputStream(new FileInputStream(stylesheet));
205 templatesModTime = stylesheet.lastModified();
206 Source src = getSource(xslStream, stylesheet);
207 templates = getFactory().newTemplates(src);
208 } finally {
209 if (xslStream != null) {
210 xslStream.close();
211 }
212 }
213 }
214
215 /**
216 * Create a new transformer based on the liaison settings
217 * @return the newly created and configured transformer.
218 * @throws Exception thrown if there is an error during creation.
219 * @see #setStylesheet(java.io.File)
220 * @see #addParam(java.lang.String, java.lang.String)
221 * @see #setOutputProperty(java.lang.String, java.lang.String)
222 */
223 private void createTransformer() throws Exception {
224 if (templates == null) {
225 readTemplates();
226 }
227
228 transformer = templates.newTransformer();
229
230 // configure the transformer...
231 transformer.setErrorListener(this);
232 if (uriResolver != null) {
233 transformer.setURIResolver(uriResolver);
234 }
235 for (int i = 0; i < params.size(); i++) {
236 final String[] pair = (String[]) params.elementAt(i);
237 transformer.setParameter(pair[0], pair[1]);
238 }
239 for (int i = 0; i < outputProperties.size(); i++) {
240 final String[] pair = (String[]) outputProperties.elementAt(i);
241 transformer.setOutputProperty(pair[0], pair[1]);
242 }
243 }
244
245 /**
246 * return the Transformer factory associated to this liaison.
247 * @return the Transformer factory associated to this liaison.
248 * @throws BuildException thrown if there is a problem creating
249 * the factory.
250 * @see #setFactory(String)
251 * @since Ant 1.5.2
252 */
253 private TransformerFactory getFactory() throws BuildException {
254 if (tfactory != null) {
255 return tfactory;
256 }
257 // not initialized yet, so create the factory
258 if (factoryName == null) {
259 tfactory = TransformerFactory.newInstance();
260 } else {
261 try {
262 Class clazz = Class.forName(factoryName);
263 tfactory = (TransformerFactory) clazz.newInstance();
264 } catch (Exception e) {
265 throw new BuildException(e);
266 }
267 }
268 tfactory.setErrorListener(this);
269
270 // specific attributes for the transformer
271 for (int i = 0; i < attributes.size(); i++) {
272 final Object[] pair = (Object[]) attributes.elementAt(i);
273 tfactory.setAttribute((String) pair[0], pair[1]);
274 }
275
276 if (uriResolver != null) {
277 tfactory.setURIResolver(uriResolver);
278 }
279 return tfactory;
280 }
281
282
283 /**
284 * Set the factory name to use instead of JAXP default lookup.
285 * @param name the fully qualified class name of the factory to use
286 * or null for the default JAXP look up mechanism.
287 * @since Ant 1.6
288 */
289 public void setFactory(String name) {
290 factoryName = name;
291 }
292
293 /**
294 * Set a custom attribute for the JAXP factory implementation.
295 * @param name the attribute name.
296 * @param value the value of the attribute, usually a boolean
297 * string or object.
298 * @since Ant 1.6
299 */
300 public void setAttribute(String name, Object value) {
301 final Object[] pair = new Object[]{name, value};
302 attributes.addElement(pair);
303 }
304
305 /**
306 * Set the output property for the current transformer.
307 * Note that the stylesheet must be set prior to calling
308 * this method.
309 * @param name the output property name.
310 * @param value the output property value.
311 * @since Ant 1.5
312 * @since Ant 1.5
313 */
314 public void setOutputProperty(String name, String value) {
315 final String[] pair = new String[]{name, value};
316 outputProperties.addElement(pair);
317 }
318
319 /** Set the class to resolve entities during the transformation
320 */
321 public void setEntityResolver(EntityResolver aResolver) {
322 entityResolver = aResolver;
323 }
324
325 /** Set the class to resolve URIs during the transformation
326 */
327 public void setURIResolver(URIResolver aResolver) {
328 uriResolver = aResolver;
329 }
330
331 public void addParam(String name, String value) {
332 final String[] pair = new String[]{name, value};
333 params.addElement(pair);
334 }
335
336 public void setLogger(XSLTLogger l) {
337 logger = l;
338 }
339
340 public void error(TransformerException e) {
341 logError(e, "Error");
342 }
343
344 public void fatalError(TransformerException e) {
345 logError(e, "Fatal Error");
346 throw new BuildException("Fatal error during transformation", e);
347 }
348
349 public void warning(TransformerException e) {
350 logError(e, "Warning");
351 }
352
353 private void logError(TransformerException e, String type) {
354 if (logger == null) {
355 return;
356 }
357
358 StringBuffer msg = new StringBuffer();
359 SourceLocator locator = e.getLocator();
360 if (locator != null) {
361 String systemid = locator.getSystemId();
362 if (systemid != null) {
363 String url = systemid;
364 if (url.startsWith("file:///")) {
365 url = url.substring(8);
366 }
367 msg.append(url);
368 } else {
369 msg.append("Unknown file");
370 }
371 int line = locator.getLineNumber();
372 if (line != -1) {
373 msg.append(":" + line);
374 int column = locator.getColumnNumber();
375 if (column != -1) {
376 msg.append(":" + column);
377 }
378 }
379 }
380 msg.append(": " + type + "! ");
381 msg.append(e.getMessage());
382 if (e.getCause() != null) {
383 msg.append(" Cause: " + e.getCause());
384 }
385
386 logger.log(msg.toString());
387 }
388
389 // kept for backwards compatibility
390 /**
391 * @deprecated use org.apache.tools.ant.util.JAXPUtils#getSystemId instead
392 */
393 protected String getSystemId(File file) {
394 return JAXPUtils.getSystemId(file);
395 }
396
397
398 /**
399 * Specific configuration for the TRaX liaison.
400 * @param xsltTask the XSLTProcess task instance from which this liasion
401 * is to be configured.
402 */
403 public void configure(XSLTProcess xsltTask) {
404 XSLTProcess.Factory factory = xsltTask.getFactory();
405 if (factory != null) {
406 setFactory(factory.getName());
407
408 // configure factory attributes
409 for (Enumeration attrs = factory.getAttributes();
410 attrs.hasMoreElements();) {
411 XSLTProcess.Factory.Attribute attr =
412 (XSLTProcess.Factory.Attribute) attrs.nextElement();
413 setAttribute(attr.getName(), attr.getValue());
414 }
415 }
416
417 XMLCatalog xmlCatalog = xsltTask.getXMLCatalog();
418 // use XMLCatalog as the entity resolver and URI resolver
419 if (xmlCatalog != null) {
420 setEntityResolver(xmlCatalog);
421 setURIResolver(xmlCatalog);
422 }
423
424
425 // configure output properties
426 for (Enumeration props = xsltTask.getOutputProperties();
427 props.hasMoreElements();) {
428 XSLTProcess.OutputProperty prop
429 = (XSLTProcess.OutputProperty) props.nextElement();
430 setOutputProperty(prop.getName(), prop.getValue());
431 }
432 }
433}
Note: See TracBrowser for help on using the repository browser.