buildframework/helium/sf/java/sysdef/src/com/nokia/helium/sysdef/ant/taskdefs/AbstractSydefTask.java
/*
* Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.helium.sysdef.ant.taskdefs;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
/**
* This is the base class for manipulating Sysdef v3 files using XML Stylesheet.
* The implementation/interface is not frozen yet. It is morelikely going to
* change in the future, depending of the underlaying implementation.
*
*/
public abstract class AbstractSydefTask extends Task implements ErrorListener {
private File srcFile;
private File destFile;
private File epocroot;
private boolean failOnError = true; // Error should not fail by default.
private boolean failOnWarning; // Warning should not fail by default.
/**
* Get the source file.
* @return
*/
public File getSrcFile() {
return srcFile;
}
/**
* Defines the location of the source system definition file.
* @param srcfile
* @ant.required
*/
public void setSrcFile(File srcfile) {
this.srcFile = srcfile;
}
/**
* Get the location of the output file.
* @return
*/
public File getDestFile() {
return destFile;
}
/**
* The the name of the destination file.
* @param destfile
* @ant.required
*/
public void setDestFile(File destfile) {
this.destFile = destfile;
}
/**
* Get the epocroot.
* If epocroot is not set by the user it return the value from the EPOCROOT environment variable.
* If the EPOCROOT environment variable is not defined then a BuildException is thrown.
* @return the epocroot location as a File object.
*/
public File getEpocroot() {
if (epocroot == null) {
if (System.getenv("EPOCROOT") != null) {
return new File(System.getenv("EPOCROOT"));
}
else {
throw new BuildException("'epocroot' attribute has not been defined.");
}
}
return epocroot;
}
/**
* Location of the EPOCROOT.
* @ant.not-required By default the EPOCROOT environment variable is used.
* @param epocroot path to the epocroot.
*/
public void setEpocroot(File epocroot) {
this.epocroot = epocroot;
}
/**
* Shall we fail the build on error.
* @return is the task should failonerror.
*/
public boolean isFailOnError() {
return failOnError;
}
/**
* Shall we fail the build on warning.
* @return is the task should fail on warning.
*/
public boolean isFailOnWarning() {
return failOnWarning;
}
/**
* Defines if the task should fail on error.
* @param failonerror
* @ant.not-required Default is true.
*/
public void setFailOnError(boolean failonerror) {
this.failOnError = failonerror;
}
/**
* Defines if the task should fail on warning.
* @param failonerror
* @ant.not-required Default is true.
*/
public void setFailOnWarning(boolean failOnWarning) {
this.failOnWarning = failOnWarning;
}
/**
* This method should be defined by the implementing class
* to define the location of the XSLT file.
* @return the XSLT file location.
*/
protected abstract File getXsl();
/**
* Check if required attribute have been configured correctly.
* If not the method will raise a BuildException.
*/
protected void check() {
if (getSrcFile() == null) {
throw new BuildException("'srcfile' attribute is not defined");
}
if (getDestFile() == null) {
throw new BuildException("'destfile' attribute is not defined");
}
File xslt = getXsl();
if (!xslt.exists()) {
throw new BuildException("Could not find " + xslt);
}
if (!getSrcFile().exists()) {
throw new BuildException("Could not find source file " + srcFile);
}
}
/**
* Transform the srcfile using the stylesheet provided by getXsl. The data parameters are
* passed to the template engine. The result is save to the destfile.
*
* @param data a set of key/value to pass to the XSLT engine.
*/
public void transform(Map<String, String> data) {
check();
if (getDestFile().exists()) {
log("Deleting previous output file: " + destFile, Project.MSG_DEBUG);
getDestFile().delete();
}
FileOutputStream output = null;
try {
output = new FileOutputStream(getDestFile());
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(getXsl()));
transformer.setParameter("path", getSrcFile());
for (Map.Entry<String, String> entry : data.entrySet()) {
transformer.setParameter(entry.getKey(), entry.getValue());
}
transformer.setErrorListener(this);
transformer.transform(new StreamSource(getSrcFile()), new StreamResult(
output));
output.close();
} catch (FileNotFoundException exc) {
// deleting the intermediate file in case of error.
if (getDestFile().exists()) {
// closing current output stream, so we can delete the file
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// we should just ignore that error.
log(ioe, Project.MSG_DEBUG);
}
log("Deleting " + destFile + " because an error occured.", Project.MSG_INFO);
getDestFile().delete();
}
// Raising the error to Ant.
throw new BuildException(exc.toString());
} catch (TransformerConfigurationException exc) {
// deleting the intermediate file in case of error.
if (destFile.exists()) {
// closing current output stream, so we can delete the file
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// we should just ignore that error.
log(ioe, Project.MSG_DEBUG);
}
log("Deleting " + destFile + " because an error occured.", Project.MSG_INFO);
getDestFile().delete();
}
// Raising the error to Ant.
throw new BuildException(exc.toString());
} catch (TransformerException exc) {
// deleting the intermediate file in case of error.
if (getDestFile().exists()) {
// closing current output stream, so we can delete the file
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// we should just ignore that error.
log(ioe, Project.MSG_DEBUG);
}
log("Deleting " + getDestFile() + " because an error occured.", Project.MSG_INFO);
getDestFile().delete();
}
// Raising the error to Ant.
throw new BuildException(exc.toString());
} catch (IOException e) {
// we should just ignore that error, error while closing the file.
log(e.getMessage(), Project.MSG_DEBUG);
}
}
/**
* {@inheritDoc}
* Reports errors to the Ant logging system of throw the exception if the task
* is set to failonerror.
*/
@Override
public void error(TransformerException message) throws TransformerException {
if (this.isFailOnError()) {
throw message;
} else {
log("ERROR: " + message.getMessageAndLocation(), Project.MSG_ERR);
}
}
/**
* {@inheritDoc}
* Fails the task in case of fatal error. The is nothing we can do about that.
*/
@Override
public void fatalError(TransformerException message) throws TransformerException {
log("ERROR: " + message.getMessageAndLocation(), Project.MSG_ERR);
throw message;
}
/**
* {@inheritDoc}
* Reports errors to the Ant logging system of throw the exception if the task
* is set to failonerror.
*/
@Override
public void warning(TransformerException message) throws TransformerException {
if (this.isFailOnWarning()) {
throw message;
} else {
log("WARNING: " + message.getMessageAndLocation(), Project.MSG_WARN);
}
}
}