blob: 0f1751ad563cbfc75ca1f39afe705ea45c9c7a0a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.transforms.xslt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.equinox.transforms.Pipe;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.osgi.framework.FrameworkEvent;
import org.osgi.util.tracker.ServiceTracker;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class XSLTStreamTransformer {
class XSLTPipe extends Pipe {
private Transformer transformer;
private EntityResolver resolver;
public XSLTPipe(InputStream original, Transformer transformer,
EntityResolver resolver) throws IOException {
super(original);
this.transformer = transformer;
this.resolver = resolver;
}
protected void pipeInput(InputStream original, OutputStream result)
throws IOException {
try {
InputSource streamSource = new InputSource(original);
XMLReader reader = XMLReaderFactory.createXMLReader();
if (resolver != null)
reader.setEntityResolver(resolver);
else
reader.setFeature("http://xml.org/sax/features/validation",
false);
SAXSource saxSource = new SAXSource(reader, streamSource);
transformer.transform(saxSource, new StreamResult(result));
} catch (TransformerException e) {
log(FrameworkEvent.ERROR, "Could not perform transform.", e);
throw new IOException(e.getMessage());
} catch (SAXException e) {
log(FrameworkEvent.ERROR, "Problem parsing transform.", e);
throw new IOException(e.getMessage());
}
}
}
private EntityResolver resolver;
private ServiceTracker logTracker;
private static final Map templateMap = new HashMap();
public XSLTStreamTransformer(final File dataFile, ServiceTracker logTracker) {
this.logTracker = logTracker;
if (dataFile != null) {
if (!dataFile.exists())
dataFile.mkdir();
else if (!dataFile.isDirectory())
return;
resolver = new EntityResolver() {
Map entities = new HashMap();
public InputSource resolveEntity(String publicId,
String systemId) throws SAXException, IOException {
byte[] resolved = (byte[]) entities.get(systemId);
if (resolved == null) {
// check to see if we have it in our bundle
String escapedSystemId = escape(systemId);
File localCache = new File(dataFile, escapedSystemId);
if (localCache != null && localCache.exists()
&& localCache.isFile()) {
// we have it on disk so just return our cache
return new InputSource(new FileInputStream(
localCache));
}
try {
URL systemURL = new URL(systemId);
InputStream resolvedStream = systemURL.openStream();
ByteArrayOutputStream resolvedOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count = 0;
while ((count = resolvedStream.read(buffer)) != -1) {
resolvedOutputStream.write(buffer, 0, count);
}
resolved = resolvedOutputStream.toByteArray();
} catch (MalformedURLException e) {
// un-resolvable entity - return an empty entity to
// continue parsing
return new InputSource(new StringReader(""));
} catch (IOException e) {
// un-resolvable entity - return an empty entity to
// continue parsing
return new InputSource(new StringReader(""));
}
if (resolved != null)
entities.put(systemId, resolved);
}
return new InputSource(new ByteArrayInputStream(resolved));
}
private String escape(String systemId) {
return systemId;
}
};
}
}
public InputStream getInputStream(InputStream inputStream,
URL transformerUrl) throws IOException {
Templates template = getTemplate(transformerUrl);
if (template != null) {
Transformer transformer = null;
try {
transformer = template.newTransformer();
XSLTPipe pipe = new XSLTPipe(inputStream, transformer, resolver);
return pipe.getPipedInputStream();
} catch (TransformerConfigurationException e) {
log(FrameworkEvent.ERROR, "Could not perform transform.", e);
}
}
return null;
}
private synchronized Templates getTemplate(URL transformerURL) {
Templates templates = null;
SoftReference templatesRef = (SoftReference) templateMap
.get(transformerURL);
if (templatesRef != null) {
templates = (Templates) templatesRef.get();
}
if (templates == null) {
try {
InputStream xsltStream = transformerURL.openStream();
TransformerFactory tFactory = null;
try {
tFactory = TransformerFactory.newInstance();
InputSource inputSource = new InputSource(xsltStream);
XMLReader reader = XMLReaderFactory.createXMLReader();
if (resolver != null)
reader.setEntityResolver(resolver);
else
reader
.setFeature(
"http://xml.org/sax/features/validation",
false);
SAXSource xsltSource = new SAXSource(reader, inputSource);
try {
templatesRef = new SoftReference(templates = tFactory
.newTemplates(xsltSource));
templateMap.put(transformerURL, templatesRef);
} catch (Exception e) {
// cant create the template. May be an IO
// exception from the source or perhaps a badly
// formed XSLT. We shouldn't fail in this case.
log(FrameworkEvent.WARNING,
"Could not create transform template: "
+ transformerURL.toString(), e);
}
} catch (TransformerFactoryConfigurationError e) {
// we can proceed without a factory
log(
FrameworkEvent.WARNING,
"Could not create transformer factory. No transforms will be invoked.",
e);
} catch (SAXException e) {
// we can proceed without a reader
log(
FrameworkEvent.WARNING,
"Could not create XML reader. No transforms will be invoked.",
e);
}
} catch (IOException e) {
log(FrameworkEvent.WARNING, "General IO Exception creating templates.", e);
}
}
return templates;
}
void log(int severity, String msg, Throwable t) {
FrameworkLog log = (FrameworkLog) logTracker.getService();
if (log == null) {
if (msg != null)
System.err.println(msg);
if (t != null)
t.printStackTrace();
return;
}
FrameworkLogEntry entry = new FrameworkLogEntry(
"org.eclipse.equinox.transforms.xslt", severity, 0, msg, 0, t,
null);
log.log(entry);
}
}