/*******************************************************************************
* Copyright (c) 2007, 2009 David Green 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:
* David Green - initial API and implementation
*******************************************************************************/
package com.datastax.wikitext.anttask;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.FileSet;
import org.eclipse.mylyn.internal.wikitext.core.parser.builder.DitaTopicDocumentBuilder;
import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
import org.eclipse.mylyn.wikitext.core.parser.builder.DitaBookMapDocumentBuilder;
import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
import org.eclipse.mylyn.wikitext.core.parser.outline.OutlineItem;
import org.eclipse.mylyn.wikitext.core.parser.outline.OutlineParser;
import org.eclipse.mylyn.wikitext.core.util.DefaultXmlStreamWriter;
import org.eclipse.mylyn.wikitext.core.util.FormattingXMLStreamWriter;
/**
* An Ant task for converting markup to OASIS DITA format.
*
* @author David Green
* @since 1.0
*/
public class MarkupToDitaTask extends MarkupTask {
public enum BreakStrategy {
/**
* do not break: all output is one topic
*/
NONE,
/**
* break on level-1 headings
*/
LEVEL1,
/**
* break on the first level heading found in the document
*/
FIRST
}
private final List<FileSet> filesets = new ArrayList<FileSet>();
private String filenameFormat;
private String bookTitle;
private boolean overwrite = true;
protected File file;
private String doctype;
private String topicDoctype;
private String topicFolder = "topics"; //$NON-NLS-1$
private BreakStrategy topicStrategy = BreakStrategy.FIRST;
private boolean formatting = true;
/**
* Adds a set of files to process.
*/
public void addFileset(FileSet set) {
filesets.add(set);
}
@Override
public void execute() throws BuildException {
if (file == null && filesets.isEmpty()) {
throw new BuildException(Messages.getString("MarkupToDitaTask.1")); //$NON-NLS-1$
}
if (file != null && !filesets.isEmpty()) {
throw new BuildException(Messages.getString("MarkupToDitaTask.2")); //$NON-NLS-1$
}
if (file != null) {
if (!file.exists()) {
throw new BuildException(MessageFormat.format(Messages.getString("MarkupToDitaTask.3"), file)); //$NON-NLS-1$
} else if (!file.isFile()) {
throw new BuildException(MessageFormat.format(Messages.getString("MarkupToDitaTask.4"), file)); //$NON-NLS-1$
} else if (!file.canRead()) {
throw new BuildException(MessageFormat.format(Messages.getString("MarkupToDitaTask.5"), file)); //$NON-NLS-1$
}
}
if (filenameFormat == null) {
switch (topicStrategy) {
case NONE:
filenameFormat = "$1.dita"; //$NON-NLS-1$
break;
default:
filenameFormat = "$1.ditamap"; //$NON-NLS-1$
}
}
MarkupLanguage markupLanguage = createMarkupLanguage();
for (FileSet fileset : filesets) {
File filesetBaseDir = fileset.getDir(getProject());
DirectoryScanner ds = fileset.getDirectoryScanner(getProject());
String[] files = ds.getIncludedFiles();
if (files != null) {
File baseDir = ds.getBasedir();
for (String file : files) {
File inputFile = new File(baseDir, file);
try {
processFile(markupLanguage, filesetBaseDir, inputFile);
} catch (BuildException e) {
throw e;
} catch (Exception e) {
throw new BuildException(MessageFormat.format(
Messages.getString("MarkupToDitaTask.6"), inputFile, //$NON-NLS-1$
e.getMessage()), e);
}
}
}
}
if (file != null) {
try {
processFile(markupLanguage, file.getParentFile(), file);
} catch (BuildException e) {
throw e;
} catch (Exception e) {
throw new BuildException(MessageFormat.format(
Messages.getString("MarkupToDitaTask.7"), file, e.getMessage()), e); //$NON-NLS-1$
}
}
}
private void processFile(MarkupLanguage markupLanguage, final File baseDir, final File source)
throws BuildException {
log(MessageFormat.format(Messages.getString("MarkupToDitaTask.8"), source), Project.MSG_VERBOSE); //$NON-NLS-1$
String markupContent = null;
String name = source.getName();
if (name.lastIndexOf('.') != -1) {
name = name.substring(0, name.lastIndexOf('.'));
}
File outputFile = new File(source.getParentFile(), filenameFormat.replace("$1", name)); //$NON-NLS-1$
if (!outputFile.exists() || overwrite || outputFile.lastModified() < source.lastModified()) {
if (markupContent == null) {
markupContent = readFully(source);
}
performValidation(source, markupContent);
OutlineItem outline = new OutlineParser(markupLanguage).parse(markupContent);
Writer writer;
try {
writer = new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream(outputFile)), "utf-8"); //$NON-NLS-1$
} catch (Exception e) {
throw new BuildException(MessageFormat.format(Messages.getString("MarkupToDitaTask.11"), outputFile, //$NON-NLS-1$
e.getMessage()), e);
}
try {
if (topicStrategy == BreakStrategy.NONE) {
DitaTopicDocumentBuilder builder = new DitaTopicDocumentBuilder(new DefaultXmlStreamWriter(writer),
formatting);
builder.setRootTopicTitle(bookTitle);
MarkupParser parser = new MarkupParser();
parser.setMarkupLanguage(markupLanguage);
parser.setBuilder(builder);
if (topicDoctype != null) {
builder.setDoctype(topicDoctype);
}
builder.setFilename(outputFile.getName());
builder.setOutline(outline);
parser.parse(markupContent);
} else {
DitaBookMapDocumentBuilder builder = new DitaBookMapDocumentBuilder(
formatting ? new FormattingXMLStreamWriter(new DefaultXmlStreamWriter(writer))
: new DefaultXmlStreamWriter(writer));
try {
builder.setFormattingDependencies(formatting);
MarkupParser parser = new MarkupParser();
parser.setMarkupLanguage(markupLanguage);
parser.setBuilder(builder);
builder.setBookTitle(bookTitle == null ? name : bookTitle);
if (doctype != null) {
builder.setDoctype(doctype);
}
if (topicDoctype != null) {
builder.setTopicDoctype(topicDoctype);
}
builder.setTargetFile(outputFile);
builder.setTopicFolder(topicFolder);
builder.setOutline(outline);
switch (topicStrategy) {
case FIRST:
if (!outline.getChildren().isEmpty()) {
builder.setTopicBreakLevel(outline.getChildren().get(0).getLevel());
} else {
builder.setTopicBreakLevel(1);
}
break;
case LEVEL1:
builder.setTopicBreakLevel(1);
break;
}
parser.parse(markupContent);
} finally {
try {
builder.close();
} catch (IOException e) {
throw new BuildException(MessageFormat.format(
Messages.getString("MarkupToDitaTask.12"), outputFile, //$NON-NLS-1$
e.getMessage()), e);
}
}
}
} finally {
try {
writer.close();
} catch (Exception e) {
throw new BuildException(MessageFormat.format(
Messages.getString("MarkupToDitaTask.12"), outputFile, //$NON-NLS-1$
e.getMessage()), e);
}
}
}
}
/**
* The format of the DocBook output file. Consists of a pattern where the '$1' is replaced with the filename of the
* input file. Default value is <code>$1.ditamap</code>
*
* @see #setFilenameFormat(String)
*/
public String getFilenameFormat() {
return filenameFormat;
}
/**
* The format of the DocBook output file. Consists of a pattern where the '$1' is replaced with the filename of the
* input file. Default value is <code>$1.ditamap</code>
*/
public void setFilenameFormat(String filenameFormat) {
this.filenameFormat = filenameFormat;
}
/**
* Get the book title.
*
* @return the title, or null if the source filename is to be used as the title.
*/
public String getBookTitle() {
return bookTitle;
}
/**
* The book title.
*
* @param bookTitle
* the title, or null if the source filename is to be used as the title.
*/
public void setBookTitle(String bookTitle) {
this.bookTitle = bookTitle;
}
/**
* Set the XML doctype of the ditamap. The doctype should look something like this:
*
* <pre>
* <!DOCTYPE bookmap PUBLIC \"-//OASIS//DTD DITA 1.1 BookMap//EN\" \"http://docs.oasis-open.org/dita/v1.1/OS/dtd/bookmap.dtd\">
* </pre>
*/
public void setDoctype(String doctype) {
this.doctype = doctype;
}
/**
* The XML doctype of the ditamap.
*/
public String getDoctype() {
return doctype;
}
/**
* the XML doctype of topics
*/
public String getTopicDoctype() {
return topicDoctype;
}
/**
* the XML doctype of topics The doctype should look something like this:
*
* <pre>
* <!DOCTYPE topic PUBLIC \"-//OASIS//DTD DITA 1.1 Topic//EN\">
* </pre>
*/
public void setTopicDoctype(String topicDoctype) {
this.topicDoctype = topicDoctype;
}
public boolean isOverwrite() {
return overwrite;
}
public void setOverwrite(boolean overwrite) {
this.overwrite = overwrite;
}
public String getTopicFolder() {
return topicFolder;
}
public void setTopicFolder(String topicFolder) {
this.topicFolder = topicFolder;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public BreakStrategy getTopicStrategy() {
return topicStrategy;
}
public void setTopicStrategy(BreakStrategy topicStrategy) {
this.topicStrategy = topicStrategy;
}
/**
* Indicate if the dita output should be formatted
*
* @since 1.2
*/
public boolean isFormatting() {
return formatting;
}
/**
* Indicate if the dita output should be formatted
*
* @since 1.2
*/
public void setFormatting(boolean formatting) {
this.formatting = formatting;
}
}