/**
* Copyright 2011 meltmedia
*
* Licensed 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.
*/
package org.xchain.framework.sax;
import javax.xml.transform.Result;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import org.xml.sax.ContentHandler;
import java.util.List;
import java.util.ArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xchain.framework.lifecycle.XmlFactoryLifecycle;
/**
* A composite stage is a stage that is made up of many interior stages. The methods on this class need to be called in the following order.
* <ol>
* <li>addStage(Stage stage) once for each stage in the composite stage.</li>
* <li>setResult(Result result) once.</li>
* <li>getContentHandler() as many times as needed.</li>
* </ol>
* Calling these methods in the wrong order will result in an illegal state exception.
*
* Calling setResult() causes the stages to be "wired up" into one stage. If there are no stages defined and the Result is a SAXResult, then
* the following call to getContentHandler() will return the results content handler. If the Result is not a SAXResult, then an identity transform
* will be inserted to adapt the Result into a content handler.
*
* @author Mike Moulton
* @author Christian Trimble
* @author Josh Kennedy
*/
public class CompositeStage
implements Stage
{
public static Logger log = LoggerFactory.getLogger( CompositeStage.class );
protected List<Stage> stageList = new ArrayList<Stage>();
protected ContentHandler contentHandler = null;
protected boolean isResultSet = false;
protected Stage lastStage = null;
public void addStage( Stage stage )
{
if( log.isDebugEnabled() ) {
log.debug("Adding stage to pipeline.");
}
if( isResultSet ) {
throw new IllegalStateException("Stages cannot be added to a composite stage after the result has been set.");
}
stageList.add(stage);
}
/**
* Returns the content handler for this stage list. Once this method is called, no more stages can be added to the
* stage list.
*/
public ContentHandler getContentHandler()
{
if( !isResultSet ) {
throw new IllegalStateException("The content handler for a composite stage cannot be returned before the result has been set.");
}
// return the content handler for this stage.
return contentHandler;
}
/**
* Sets the result for this stage list. Once this method is called, no more stages can be added to the
* stage list.
*/
public void setResult( Result result )
{
if( isResultSet ) {
throw new IllegalStateException("The result of a composite stage cannot be set more than once.");
}
if( stageList.isEmpty() && !( result instanceof SAXResult ) ) {
addIdentityTransformer();
}
if( !stageList.isEmpty() ) {
// set the result on the last stage in the list.
lastStage = (Stage)stageList.get(stageList.size()-1);
lastStage.setResult(result);
// iterate over the stages in reverse order, wiring them up as we go.
for( int i = stageList.size() - 1; i > 0; i-- ) {
Stage previousStage = (Stage)stageList.get(i-1);
Stage nextStage = (Stage)stageList.get(i);
// create a result that will feed the next stage.
SAXResult nextResult = new SAXResult();
nextResult.setHandler(nextStage.getContentHandler());
// set next stage result as the result of the previous stage.
previousStage.setResult(nextResult);
}
// set the content handler as the content handler for the first stage.
Stage firstStage = (Stage)stageList.get(0);
contentHandler = firstStage.getContentHandler();
}
else if( result instanceof SAXResult ) {
contentHandler = ((SAXResult)result).getHandler();
}
else {
throw new IllegalStateException("Currently, all composite stages must have at least one stage, or they must have a SAXResult.");
}
// set the isResultSet flag to true.
isResultSet = true;
}
/**
* Returns the internet media type for the final stage of the composite
*/
public String getMediaType()
{
if( !isResultSet ) {
throw new IllegalStateException("The media type for a composite stage cannot be returned before the result has been set.");
}
return lastStage.getMediaType();
}
/**
* Returns the character encoding for the final stage of the composite
*/
public String getEncoding()
{
if( !isResultSet ) {
throw new IllegalStateException("The encoding for a composite stage cannot be returned before the result has been set.");
}
return lastStage.getEncoding();
}
public void addIdentityTransformer()
{
try {
// Create identity (copy) transformer
TransformerHandler transformerHandler = XmlFactoryLifecycle.newTransformerFactory(XmlFactoryLifecycle.DEFAULT_TRANSFORMER_FACTORY_NAME).newTransformerHandler();
// create a transformer handler stage for the identity.
TransformerHandlerStage stage = new TransformerHandlerStage(transformerHandler);
// set the transformer handler for the identity.
addStage(stage);
}
catch( Exception e ) {
throw new RuntimeException("Could not create identity transformer.", e);
}
}
}