/*
* Copyright (C) 2011 Laurent Caillette
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.novelang.produce;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutorService;
import com.google.common.base.Preconditions;
import org.novelang.common.FileTools;
import org.novelang.common.Problem;
import org.novelang.common.Renderable;
import org.novelang.common.StructureKind;
import org.novelang.common.metadata.Page;
import org.novelang.common.metadata.PageIdentifier;
import org.novelang.configuration.ProducerConfiguration;
import org.novelang.configuration.RenderingConfiguration;
import org.novelang.logger.Logger;
import org.novelang.logger.LoggerFactory;
import org.novelang.novella.Novella;
import org.novelang.opus.Opus;
import org.novelang.outfit.ArrayTools;
import org.novelang.outfit.loader.ResourceName;
import org.novelang.rendering.FragmentWriter;
import org.novelang.rendering.GenericRenderer;
import org.novelang.rendering.HtmlWriter;
import org.novelang.rendering.NovellaWriter;
import org.novelang.rendering.PdfWriter;
import org.novelang.rendering.PlainTextWriter;
import org.novelang.rendering.RenditionMimeType;
import org.novelang.rendering.XmlWriter;
import org.novelang.rendering.XslWriter;
/**
* Produces a document into passed-in {@link DocumentRequest}s.
*
* @author Laurent Caillette
*/
public class DocumentProducer {
private static final Logger LOGGER = LoggerFactory.getLogger( DocumentProducer.class ) ;
private final File basedir ;
private final RenderingConfiguration renderingConfiguration ;
private final Charset defaultSourceCharset ;
private final ExecutorService executorService ;
public DocumentProducer( final ProducerConfiguration configuration ) {
this.basedir = Preconditions.checkNotNull(
configuration.getContentConfiguration().getContentRoot() ) ;
this.renderingConfiguration = Preconditions.checkNotNull(
configuration.getRenderingConfiguration() ) ;
this.defaultSourceCharset = Preconditions.checkNotNull(
configuration.getContentConfiguration().getSourceCharset() ) ;
this.executorService = configuration.getExecutorService() ;
}
public Iterable< Problem > produce(
final DocumentRequest request,
final Renderable rendered,
final StreamDirector streamDirector
) throws Exception {
final RenditionMimeType mimeType = request.getRenditionMimeType() ;
// Java-flavored curryfication, wow!
class Serve {
public void with( final GenericRenderer renderer ) throws Exception {
serve( streamDirector, renderer, request.getPageIdentifier(), rendered ) ;
}
}
final Serve serve = new Serve() ;
LOGGER.debug( "Attempting to produce ", request );
final ResourceName stylesheet = ArrayTools.firstNotNull(
request.getAlternateStylesheet(),
rendered.getCustomStylesheetMap().get( mimeType )
) ;
final Charset charset = rendered.getRenderingCharset() ;
final FragmentWriter fragmentWriter ;
boolean renderLocation = false ;
switch( mimeType ) {
case PDF :
fragmentWriter = new PdfWriter( renderingConfiguration, stylesheet ) ;
break ;
case TXT :
fragmentWriter = new PlainTextWriter( charset ) ;
break ;
case XML :
fragmentWriter = new XmlWriter() ;
renderLocation = true ;
break ;
case HTML :
fragmentWriter = new HtmlWriter( renderingConfiguration, stylesheet, charset ) ;
renderLocation = true ;
break ;
case NOVELLA:
fragmentWriter = new NovellaWriter( renderingConfiguration, stylesheet, charset ) ;
break ;
case FO :
final ResourceName foStylesheet =
stylesheet == null ? PdfWriter.DEFAULT_FO_STYLESHEET : stylesheet ;
fragmentWriter = new XslWriter( renderingConfiguration, foStylesheet ) ;
break ;
default :
throw new IllegalArgumentException( "Unsupported: " + mimeType ) ;
}
serve.with( new GenericRenderer( fragmentWriter, renderLocation ) ) ;
LOGGER.debug( "Done with '", request.getOriginalTarget(), "'." ) ;
return rendered.getProblems() ;
}
private void serve(
final StreamDirector streamDirector,
final GenericRenderer renderer,
final PageIdentifier pageIdentifier,
final Renderable renderable
) throws Exception {
streamDirector.feedStreams(
renderable,
renderer,
pageIdentifier,
new StreamDirector.StreamFeeder() {
@Override
public void feed(
final Renderable someRenderable,
final OutputStream outputStream,
final Page page
) throws Exception {
renderer.render( someRenderable, outputStream, page, basedir ) ;
}
}
) ;
}
public Renderable createRenderable( final DocumentRequest documentRequest ) throws IOException {
final Charset suggestedRenderingCharset = renderingConfiguration.getDefaultCharset() ;
LOGGER.debug( "About to create renderable with document source name '",
documentRequest.getDocumentSourceName(),
"'..."
) ;
try {
final File bookFile = FileTools.load(
basedir,
documentRequest.getDocumentSourceName(),
StructureKind.OPUS.getFileExtensions()
) ;
LOGGER.info( "Attempting to load file '", bookFile, "' with charset ",
suggestedRenderingCharset.name() ) ;
return new Opus(
basedir,
bookFile,
executorService,
defaultSourceCharset,
suggestedRenderingCharset,
documentRequest.getTags()
) ;
} catch( FileNotFoundException e ) {
final File partFile = FileTools.load(
basedir,
documentRequest.getDocumentSourceName(),
StructureKind.NOVELLA.getFileExtensions()
) ;
return new Novella(
partFile,
defaultSourceCharset,
suggestedRenderingCharset
).relocateResourcePaths( basedir ).makeStandalone( documentRequest.getTags() ) ;
}
}
}