gt: 			catch ( IOException e ) { }
context:  /* Copyright (c) 2007 Pentaho Corporation.  All rights reserved. 
   * This software was developed by Pentaho Corporation and is provided under the terms 
   * of the GNU Lesser General Public License, Version 2.1. You may not use 
   * this file except in compliance with the license. If you need a copy of the license, 
   * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is Pentaho 
   * Data Integration.  The Initial Developer is Pentaho Corporation.
   *
   * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
   * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
   * the license for the specific language governing your rights and limitations.*/
  
  package com.panet.imeta.job.entries.xslt;
  
  import static com.panet.imeta.job.entry.validator.AbstractFileValidator.putVariableSpace;
  import static com.panet.imeta.job.entry.validator.AndValidator.putValidators;
  import static com.panet.imeta.job.entry.validator.JobEntryValidatorUtils.andValidator;
  import static com.panet.imeta.job.entry.validator.JobEntryValidatorUtils.fileExistsValidator;
  import static com.panet.imeta.job.entry.validator.JobEntryValidatorUtils.notBlankValidator;
  
  import java.io.IOException;
  import java.util.List;
  import java.util.Map;
  
  import javax.xml.transform.Source;
  import javax.xml.transform.Templates;
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerFactory;
  import javax.xml.transform.stream.StreamResult;
  import javax.xml.transform.stream.StreamSource;
  
  import org.apache.commons.vfs.FileObject;
  import org.w3c.dom.Node;
  
  import com.panet.imeta.cluster.SlaveServer;
  import com.panet.imeta.core.CheckResultInterface;
  import com.panet.imeta.core.Const;
  import com.panet.imeta.core.Result;
  import com.panet.imeta.core.ResultFile;
  import com.panet.imeta.core.database.DatabaseMeta;
  import com.panet.imeta.core.exception.KettleDatabaseException;
  import com.panet.imeta.core.exception.KettleException;
  import com.panet.imeta.core.exception.KettleXMLException;
  import com.panet.imeta.core.logging.LogWriter;
  import com.panet.imeta.core.util.StringUtil;
  import com.panet.imeta.core.vfs.KettleVFS;
  import com.panet.imeta.core.xml.XMLHandler;
  import com.panet.imeta.job.Job;
  import com.panet.imeta.job.JobEntryType;
  import com.panet.imeta.job.JobMeta;
  import com.panet.imeta.job.entry.JobEntryBase;
  import com.panet.imeta.job.entry.JobEntryInterface;
  import com.panet.imeta.job.entry.validator.ValidatorContext;
  import com.panet.imeta.repository.Repository;
  import com.panet.imeta.resource.ResourceEntry;
  import com.panet.imeta.resource.ResourceReference;
  import com.panet.imeta.resource.ResourceEntry.ResourceType;
  import com.panet.imeta.shared.SharedObjectInterface;
  
  
  /**
   * This defines a 'xslt' job entry.
   *
   * @author Samatar Hassan
   * @since 02-03-2007
   *
   */
  public class JobEntryXSLT extends JobEntryBase implements Cloneable, JobEntryInterface
  {
  	public static final String ENTRY_ATTRIBUTE_XMLFILENAME = "xmlfilename";
  	public static final String ENTRY_ATTRIBUTE_XSLFILENAME = "xslfilename";
  	public static final String ENTRY_ATTRIBUTE_OUTPUTFILENAME = "outputfilename";
  	public static final String ENTRY_ATTRIBUTE_IFFILEEXISTS = "iffileexists";
  	public static final String ENTRY_ATTRIBUTE_ADDFILETORESULT = "addfiletoresult";
  	public static final String ENTRY_ATTRIBUTE_XSLTFACTORY = "xsltfactory";
  	
  	public static String FACTORY_JAXP="JAXP";
  	public static String FACTORY_SAXON="SAXON";
  	
  	
  	private String xmlfilename;
  	private String xslfilename;
  	private String outputfilename;
  	public int iffileexists;
  	private boolean addfiletoresult;
  	private String xsltfactory;
  
  
  	public JobEntryXSLT(String n)
  	{
  		super(n, "");
       	xmlfilename=null;
       	xslfilename=null;
  		outputfilename=null;
  		iffileexists=1;
  		addfiletoresult = false;
  		xsltfactory=FACTORY_JAXP;
  		setID(-1L);
  		setJobEntryType(JobEntryType.XSLT);
  	}
  
  	public JobEntryXSLT()
  	{
  		this("");
  	}
  
  	public JobEntryXSLT(JobEntryBase jeb)
  	{
  		super(jeb);
  	}
  
      public Object clone()
      {
          JobEntryXSLT je = (JobEntryXSLT)super.clone();
          return je;
      }
  
  	public String getXML()
  	{
          StringBuffer retval = new StringBuffer(50);
  
  		retval.append(super.getXML());
  		retval.append("      ").append(XMLHandler.addTagValue(ENTRY_ATTRIBUTE_XMLFILENAME, xmlfilename));
  		retval.append("      ").append(XMLHandler.addTagValue(ENTRY_ATTRIBUTE_XSLFILENAME, xslfilename));
  		retval.append("      ").append(XMLHandler.addTagValue(ENTRY_ATTRIBUTE_OUTPUTFILENAME, outputfilename));
  		retval.append("      ").append(XMLHandler.addTagValue(ENTRY_ATTRIBUTE_IFFILEEXISTS,  iffileexists));
  		retval.append("      ").append(XMLHandler.addTagValue(ENTRY_ATTRIBUTE_ADDFILETORESULT,  addfiletoresult));
  		retval.append("      ").append(XMLHandler.addTagValue(ENTRY_ATTRIBUTE_XSLTFACTORY, xsltfactory));
  		
  		return retval.toString();
  	}
  
  	public void loadXML(Node entrynode, List<DatabaseMeta> databases, List<SlaveServer> slaveServers, Repository rep) throws KettleXMLException
  	{
  		try
  		{
  			super.loadXML(entrynode, databases, slaveServers);
  			xmlfilename = XMLHandler.getTagValue(entrynode, ENTRY_ATTRIBUTE_XMLFILENAME);
  			xslfilename = XMLHandler.getTagValue(entrynode, ENTRY_ATTRIBUTE_XSLFILENAME);
  			outputfilename = XMLHandler.getTagValue(entrynode, ENTRY_ATTRIBUTE_OUTPUTFILENAME);
  			iffileexists = Const.toInt(XMLHandler.getTagValue(entrynode, ENTRY_ATTRIBUTE_IFFILEEXISTS), -1);
  			addfiletoresult = "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, ENTRY_ATTRIBUTE_ADDFILETORESULT));
  			xsltfactory = XMLHandler.getTagValue(entrynode, ENTRY_ATTRIBUTE_XSLTFACTORY);
  			if(xsltfactory==null) xsltfactory=FACTORY_JAXP;
  
  		}
  		catch(KettleXMLException xe)
  		{
  			throw new KettleXMLException("Unable to load job entry of type 'xslt' from XML node", xe);
  		}
  	}
  	
  	public void setInfo(Map<String, String[]> p, String id,
  			List<? extends SharedObjectInterface> databases) {
  		xmlfilename = JobEntryBase.parameterToString(p.get(id + ".xmlfilename"));
  		xslfilename = JobEntryBase.parameterToString(p.get(id + ".xslfilename"));
  		outputfilename = JobEntryBase.parameterToString(p.get(id + ".outputfilename"));
  		iffileexists = JobEntryBase.parameterToInt(p.get(id + ".iffileexists"));
  		addfiletoresult = JobEntryBase.parameterToBoolean(p.get(id + ".addfiletoresult"));
  		xsltfactory = JobEntryBase.parameterToString(p.get(id + ".xsltfactory"));
  	}
  
  	public void loadRep(Repository rep, long id_jobentry, List<DatabaseMeta> databases, List<SlaveServer> slaveServers)
  		throws KettleException
  	{
  		try
  		{
  			super.loadRep(rep, id_jobentry, databases, slaveServers);
  			xmlfilename = rep.getJobEntryAttributeString(id_jobentry, ENTRY_ATTRIBUTE_XMLFILENAME);
  			xslfilename = rep.getJobEntryAttributeString(id_jobentry, ENTRY_ATTRIBUTE_XSLFILENAME);
  			outputfilename = rep.getJobEntryAttributeString(id_jobentry, ENTRY_ATTRIBUTE_OUTPUTFILENAME);
  			iffileexists=(int) rep.getJobEntryAttributeInteger(id_jobentry, ENTRY_ATTRIBUTE_IFFILEEXISTS);
  			addfiletoresult=rep.getJobEntryAttributeBoolean(id_jobentry, ENTRY_ATTRIBUTE_ADDFILETORESULT);
  			xsltfactory = rep.getJobEntryAttributeString(id_jobentry, ENTRY_ATTRIBUTE_XSLTFACTORY);
  			if(xsltfactory==null) xsltfactory=FACTORY_JAXP;
  		}
  		catch(KettleException dbe)
  		{
  			throw new KettleException("Unable to load job entry of type 'xslt' from the repository for id_jobentry="+id_jobentry, dbe);
  		}
  	}
  
  	public void saveRep(Repository rep, long id_job)
  		throws KettleException
  	{
  		try
  		{
  			super.saveRep(rep, id_job);
  
  			rep.saveJobEntryAttribute(id_job, getID(), ENTRY_ATTRIBUTE_XMLFILENAME, xmlfilename);
  			rep.saveJobEntryAttribute(id_job, getID(), ENTRY_ATTRIBUTE_XSLFILENAME, xslfilename);
  			rep.saveJobEntryAttribute(id_job, getID(), ENTRY_ATTRIBUTE_OUTPUTFILENAME, outputfilename);
  			rep.saveJobEntryAttribute(id_job, getID(), ENTRY_ATTRIBUTE_IFFILEEXISTS, iffileexists);
  			rep.saveJobEntryAttribute(id_job, getID(), ENTRY_ATTRIBUTE_ADDFILETORESULT, addfiletoresult);
  			rep.saveJobEntryAttribute(id_job, getID(), ENTRY_ATTRIBUTE_XSLTFACTORY, xsltfactory);
  			
  		}
  		catch(KettleDatabaseException dbe)
  		{
  			throw new KettleException("Unable to save job entry of type 'xslt' to the repository for id_job="+id_job, dbe);
  		}
  	}
  
  	public String getXSLTFactory()
  	{
  		return xsltfactory;
  	}
  	
  	public void setXSLTFactory(String xsltfactoryin)
  	{
  		xsltfactory=xsltfactoryin;
  	}
  	
      public String getRealxmlfilename()
      {
          return environmentSubstitute(getxmlFilename());
      }
  
  	public String getRealoutputfilename()
  	{
  		return environmentSubstitute(getoutputFilename());
  	}
  
  
      public String getRealxslfilename()
      {
          return environmentSubstitute(getxslFilename());
      }
  
  	public Result execute(Result previousResult, int nr, Repository rep, Job parentJob)
  	{
  		LogWriter log = LogWriter.getInstance();
  		Result result = previousResult;
  		result.setResult( false );
  
  		String realxmlfilename = getRealxmlfilename();
  		String realxslfilename = getRealxslfilename();
  		String realoutputfilename = getRealoutputfilename();
  		
  		FileObject xmlfile = null;
  		FileObject xslfile = null;
  		FileObject outputfile = null;
  
  		try
  
  		{
  
  			if (xmlfilename!=null && xslfilename!=null && outputfilename!=null)
  			{
  				xmlfile = KettleVFS.getFileObject(realxmlfilename);
  				xslfile = KettleVFS.getFileObject(realxslfilename);
  				outputfile = KettleVFS.getFileObject(realoutputfilename);
  
  				if ( xmlfile.exists() && xslfile.exists() )
  				{
  					if (outputfile.exists() && iffileexists==2)
  					{
  						//Output file exists
  						// User want to fail
  						log.logError(toString(), Messages.getString("JobEntryXSLT.OuputFileExists1.Label")
  										+ realoutputfilename + Messages.getString("JobEntryXSLT.OuputFileExists2.Label"));
  						result.setResult( false );
  						result.setNrErrors(1);
  					}
  
  					else if (outputfile.exists() && iffileexists==1)
  					{
  						// Do nothing
  						if(log.isDebug()) log.logDebug(toString(), Messages.getString("JobEntryXSLT.OuputFileExists1.Label")
  								+ realoutputfilename + Messages.getString("JobEntryXSLT.OuputFileExists2.Label"));
  						result.setResult( true );
  					}
  					else
  					{
  						 if (outputfile.exists() && iffileexists==0)
  							{
  								// the output file exists and user want to create new one with unique name
  								//Format Date
  
  								// Try to clean filename (without wildcard)
  								String wildcard = realoutputfilename.substring(realoutputfilename.length()-4,realoutputfilename.length());
  								if(wildcard.substring(0,1).equals("."))
  								{
  									// Find wildcard
  									realoutputfilename=realoutputfilename.substring(0,realoutputfilename.length()-4) +
  										"_" + StringUtil.getFormattedDateTimeNow(true) + wildcard;
  								}
  								else
  								{
  									// did not find wildcard
  									realoutputfilename=realoutputfilename + "_" + StringUtil.getFormattedDateTimeNow(true);
  								}
  							    if(log.isDebug()) log.logDebug(toString(),  Messages.getString("JobEntryXSLT.OuputFileExists1.Label") +
  										realoutputfilename +  Messages.getString("JobEntryXSLT.OuputFileExists2.Label"));
  								log.logDebug(toString(), Messages.getString("JobEntryXSLT.OuputFileNameChange1.Label") + realoutputfilename +
  								Messages.getString("JobEntryXSLT.OuputFileNameChange2.Label"));
  							}
  
  						
  						// Create transformer factory
  						TransformerFactory factory = TransformerFactory.newInstance();	
  						
  						if (xsltfactory.equals(FACTORY_SAXON))
  						{
  							// Set the TransformerFactory to the SAXON implementation.
  							factory = new net.sf.saxon.TransformerFactoryImpl(); 
  						}
  						
  						if (log.isDetailed()) log.logDetailed(Messages.getString("JobEntryXSL.Log.TransformerFactoryInfos"),Messages.getString("JobEntryXSL.Log.TransformerFactory",factory.getClass().getName()));
  				
  								
  						// Use the factory to create a template containing the xsl file
  						Templates template = factory.newTemplates(new StreamSource(	KettleVFS.getInputStream(xslfile))); 
  
  						// Use the template to create a transformer
  						Transformer xformer = template.newTransformer();
  						
  						if (log.isDetailed()) log.logDetailed(Messages.getString("JobEntryXSL.Log.TransformerClassInfos"),Messages.getString("JobEntryXSL.Log.TransformerClass",xformer.getClass().getName()));
  											
  						
  						// Prepare the input and output files
  						Source source = new StreamSource(KettleVFS.getInputStream(xmlfile));
  						StreamResult resultat = new StreamResult(KettleVFS.getOutputStream(outputfile, false));
  
  						// Apply the xsl file to the source file and write the result to the output file
  						xformer.transform(source, resultat);
  						
  						if (isAddFileToResult())
  						{
  							// Add output filename to output files
  		                	ResultFile resultFile = new ResultFile(ResultFile.FILE_TYPE_GENERAL, KettleVFS.getFileObject(realoutputfilename), parentJob.getJobname(), toString());
  		                    result.getResultFiles().put(resultFile.getFile().toString(), resultFile);
  						}
  						
  
  						// Everything is OK
  						result.setResult( true );
  					}
  				}
  				else
  				{
  
  					if(	!xmlfile.exists())
  					{
  						log.logError(toString(),  Messages.getString("JobEntryXSLT.FileDoesNotExist1.Label") +
  							realxmlfilename +  Messages.getString("JobEntryXSLT.FileDoesNotExist2.Label"));
  					}
  					if(!xslfile.exists())
  					{
  						log.logError(toString(),  Messages.getString("JobEntryXSLT.FileDoesNotExist1.Label") +
  							realxslfilename +  Messages.getString("JobEntryXSLT.FileDoesNotExist2.Label"));
  					}
  					result.setResult( false );
  					result.setNrErrors(1);
  				}
  
  			}
  			else
  			{
  				log.logError(toString(),  Messages.getString("JobEntryXSLT.AllFilesNotNull.Label"));
  				result.setResult( false );
  				result.setNrErrors(1);
  			}
  		}
  		catch ( Exception e )
  		{
  			log.logError(toString(), Messages.getString("JobEntryXSLT.ErrorXLST.Label") +
  				Messages.getString("JobEntryXSLT.ErrorXLSTXML1.Label") + realxmlfilename +
  				Messages.getString("JobEntryXSLT.ErrorXLSTXML2.Label") +
  				Messages.getString("JobEntryXSLT.ErrorXLSTXSL1.Label") + realxslfilename +
  				Messages.getString("JobEntryXSLT.ErrorXLSTXSL2.Label") + e.getMessage());
  			result.setResult( false );
  			result.setNrErrors(1);
  		}
  		finally
  		{
  			try
  			{
  			    if ( xmlfile != null )
  			    	xmlfile.close();
  
  			    if ( xslfile != null )
  			    	xslfile.close();
  				if ( outputfile != null )
  					outputfile.close();
  				
  				// file object is not properly garbaged collected and thus the file cannot
  				// be deleted anymore. This is a known problem in the JVM.
  
  				System.gc();
  		    }
  