/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.fo;
import java.io.File;
import java.io.InputStream;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.events.EventListener;
/**
* Parse an FO document and run the corresponding FO events through a given
* {@link FOEventHandler} instance. That instance is created using the helper
* {@link FOEventHandlerFactory}.
*
* <p>An instance of this class may not be used in multiple threads concurrently.<p>
*
* <p>An instance of this class may be used multiple times if the given
* {@link FOEventHandler} implementation can be used multiple times.
*/
public final class FODocumentParser {
private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
private static final FopFactory FOP_FACTORY = FopFactory.newInstance(new File(".").toURI());
private final FOEventHandlerFactory foEventHandlerFactory;
private Fop fop;
private Transformer transformer;
private EventListener eventListener;
/**
* A factory to create custom instances of {@link FOEventHandler}.
*/
public interface FOEventHandlerFactory {
/**
* Creates a new {@code FOEventHandler} instance parameterized with the given FO user agent.
*
* @param foUserAgent an FO user agent
* @return a new {@code FOEventHandler} instance
*/
FOEventHandler newFOEventHandler(FOUserAgent foUserAgent);
}
private FODocumentParser(FOEventHandlerFactory foeEventHandlerFactory) {
this.foEventHandlerFactory = foeEventHandlerFactory;
}
/**
* Creates and returns a new FO document parser. The given factory will be used to
* customize the handler that will receive FO events, using the
* {@link FOUserAgent#setFOEventHandlerOverride(FOEventHandler)} method.
*
* @param foEventHandlerFactory the factory to be used to create {@code
* FOEventHandler} instances
* @return a new parser
*/
public static FODocumentParser newInstance(FOEventHandlerFactory foEventHandlerFactory) {
return new FODocumentParser(foEventHandlerFactory);
}
/**
* Sets the event listener to be used if events occurs when parsing the document.
*
* @param eventListener an event listener
*/
public void setEventListener(EventListener eventListener) {
this.eventListener = eventListener;
}
/**
* Runs FOP on the given document.
*
* @param document XSL-FO document to parse
* @throws FOPException if an error occurs when initializing FOP
* @throws LoadingException if an error occurs when parsing the document
*/
public void parse(InputStream document) throws FOPException, LoadingException {
parse(document, createFOUserAgent());
}
/**
* Runs FOP on the given document with the supplied {@link FOUserAgent}.
*
* @param document XSL-FO document to parse
* @param foUserAgent The user agent
* @throws FOPException if an error occurs when initializing FOP
* @throws LoadingException if an error occurs when parsing the document
*/
public void parse(InputStream document, FOUserAgent foUserAgent)
throws FOPException, LoadingException {
fop = FOP_FACTORY.newFop(foUserAgent);
createTransformer();
runTransformer(document);
}
/**
* Creates a new {@link FOUserAgent}.
* @return It
*/
public FOUserAgent createFOUserAgent() {
FOUserAgent userAgent = FOP_FACTORY.newFOUserAgent();
FOEventHandler foEventHandler = foEventHandlerFactory.newFOEventHandler(userAgent);
userAgent.setFOEventHandlerOverride(foEventHandler);
if (eventListener != null) {
userAgent.getEventBroadcaster().addEventListener(eventListener);
}
return userAgent;
}
private void createTransformer() {
try {
transformer = TRANSFORMER_FACTORY.newTransformer();
} catch (TransformerConfigurationException e) {
throw new RuntimeException(e);
}
}
private void runTransformer(InputStream input) throws LoadingException, FOPException {
Source source = new StreamSource(input);
Result result = new SAXResult(fop.getDefaultHandler());
try {
transformer.transform(source, result);
} catch (TransformerException e) {
Throwable cause = e.getCause();
throw new LoadingException(cause == null ? e : cause);
}
}
}