package er.pdf.builder;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import org.xhtmlrenderer.resource.FSEntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import com.webobjects.appserver.WOApplication;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSMutableArray;
import er.extensions.foundation.ERXProperties;
/**
*
* @property er.pdf.validation
*/
public class FlyingSaucerImpl implements PDFBuilder {
private static final DocumentBuilderFactory _builderFactory;
private ITextRenderer renderer = new ITextRenderer();
private Document doc;
private ErrorHandler errorHandler;
private SAXParseException exception;
static {
_builderFactory = DocumentBuilderFactory.newInstance();
_builderFactory.setValidating(ERXProperties.booleanForKeyWithDefault("er.pdf.validation", false));
_builderFactory.setNamespaceAware(true);
_builderFactory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", true);
}
public FlyingSaucerImpl() {
errorHandler = new ErrorHandler() {
public void error(SAXParseException e) throws SAXException {
exception = e;
}
public void fatalError(SAXParseException e) throws SAXException {
exception = e;
}
public void warning(SAXParseException e) throws SAXException {
exception = e;
}
};
ReplacedElementFactory ref = new ERPDFReplacedElementFactory(renderer.getOutputDevice());
renderer.getSharedContext().setReplacedElementFactory(ref);
}
public void createDocument(OutputStream os) {
try {
renderer.createPDF(os);
} catch (DocumentException e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
}
}
public void setSource(String document, String encoding, String urlPrefix, NSDictionary<String, Object> configuration) throws UnsupportedEncodingException {
DocumentBuilder builder;
try {
exception = null;
builder = _builderFactory.newDocumentBuilder();
builder.setEntityResolver(FSEntityResolver.instance());
builder.setErrorHandler(errorHandler);
} catch (ParserConfigurationException e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
}
InputStream is = new ByteArrayInputStream(document.getBytes(encoding));
ITextFontResolver resolver = renderer.getFontResolver();
for (String font : fontsFromConfiguration(configuration)) {
try {
resolver.addFont(font, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
} catch (Exception e) {
e.printStackTrace();
}
}
try {
doc = builder.parse(is);
if (exception != null)
throw exception;
// Hook up a metadata listener to push keys and values to PDF
FlyingSaucerMetadataCreationListener mcl = new FlyingSaucerMetadataCreationListener();
mcl.parseMetaTags(doc);
renderer.setListener(mcl);
renderer.setDocument(doc, urlPrefix);
renderer.layout();
} catch (Exception e) {
throw NSForwardException._runtimeExceptionForThrowable(e);
}
}
@SuppressWarnings("unchecked")
private NSArray<String> fontsFromConfiguration(NSDictionary<String, Object> configuration) {
if (configuration == null)
return NSArray.emptyArray();
NSArray<String> fonts = (NSArray<String>) configuration.objectForKey("fonts");
NSMutableArray<String> result = new NSMutableArray<>();
String framework = (String) configuration.objectForKey("framework");
if (fonts != null) {
for (String font : fonts) {
URL path = WOApplication.application().resourceManager().pathURLForResourceNamed(font, framework, null);
if (path != null)
result.addObject(path.getFile());
}
}
return result;
}
}