Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * CalabashTask.java
    *
    * Copyright 2012 Mentea.
    * All rights reserved.
    *
    * The contents of this file are subject to the terms of either the GNU
    * General Public License Version 2 only ("GPL") or the Common
    * Development and Distribution License("CDDL") (collectively, the
   * "License"). You may not use this file except in compliance with the
   * License. You can obtain a copy of the License at
   * https://xproc.dev.java.net/public/CDDL+GPL.html or
   * docs/CDDL+GPL.txt in the distribution. See the License for the
   * specific language governing permissions and limitations under the
   * License. When distributing the software, include this License Header
   * Notice in each file and include the License file at docs/CDDL+GPL.txt.
   */
  
  package com.xmlcalabash.drivers;
  
  
  import  org.apache.tools.ant.Project;
  import  org.apache.tools.ant.BuildException;
  import  org.apache.tools.ant.DirectoryScanner;
  import  org.apache.tools.ant.PropertyHelper;
  import  org.apache.tools.ant.taskdefs.MatchingTask;
  import  org.apache.tools.ant.types.CommandlineJava;
  import  org.apache.tools.ant.types.Environment;
  import  org.apache.tools.ant.types.Mapper;
  import  org.apache.tools.ant.types.PropertySet;
  import  org.apache.tools.ant.types.ResourceCollection;
  import  org.apache.tools.ant.types.Resource;
  import  org.apache.tools.ant.types.resources.FileResource;
  import  org.apache.tools.ant.types.resources.Resources;
  import  org.apache.tools.ant.types.resources.Union;
  import  org.apache.tools.ant.util.FileNameMapper;
  
  
  import java.io.File;
  import java.net.URI;
  import java.util.*;
Ant task to run Calabash.

Owes a lot to Ant's <xslt> task, but this task can't become part of Ant because this task relies on Calabash, which is licensed under LGPL.

Author(s):
MenteaXML
  
  public class CalabashTask extends MatchingTask {
      /*
       * Ant can reuse a Task multiple times in the one build file, so
       * all of these fields need to be reset to their initial values
       * at the end of evaluate().
       *
       * Fields with null or false initial value are explicitly set so
       * it's obvious what to reset them to at the end of evaluate().
       *
       * Fields vaguely follow the sequence input, pipeline, output,
       * then the rest.
       */

    
Input ports and the resources associated with each.
  
      private HashMap<String,Union> inputResources = new HashMap<String,Union> ();

    
Input ports and the mapper associated with each.
  
      private Map<String,FileNameMapper> inputMappers = new HashMap<String,FileNameMapper> ();

    
Where to find the source XML file, default is the project's basedir
  
      private File baseDir = null;

    
Port of the pipeline input. As attribute.
  
      private String inPort = null;

    
URI of the input XML. As attribute.
  
      private Resource inResource = null;

    
Whether the build should fail if the nested resource collection is empty.
  
      private boolean failOnNoResources = true;

    
URI of the pipeline to run. As attribute.
  
     private String pipelineURI = null;

    
Pipeline as a org.apache.tools.ant.types.Resource
 
     private Resource pipelineResource = null;

    
destination directory
 
     private File destDir = null;

    
Port of the pipeline output. As attribute.
 
     private String outPort = null;

    
Resource of the output XML. As attribute.
 
     private  Resource outResource = null;

    
Output ports and the resources associated with each.
 
     private HashMap<String,Union> outputResources = new HashMap<String,Union> ();

    
Output ports and the mapper associated with each.
 
     private Map<String,FileNameMapper> outputMappers = new HashMap<String,FileNameMapper> ();

    
extension of the files produced by pipeline processing
 
     private String targetExtension = "-out.xml";

    
whether target extension has been set from build file
 
     private boolean isTargetExtensionSet = false;

    
Whether to fail the build if an error occurs.
 
     private boolean failOnError = true;

    
Additional resource collections to process.
 
     private Union resources = new Union();

    
whether resources has been set from nested resource collection
 
     private boolean isResourcesSet = false;

    
Whether to use the implicit fileset.
 
     private boolean useImplicitFileset = true;

    
Whether to process all files in the included directories as well.
 
     private boolean performDirectoryScan = true;

    
Mapper to use when a set of files gets processed.
 
     private FileNameMapper mapper = null;

    
force output of target files even if they already exist
 
     private boolean force = false;

    
System properties to set during transformation.
 
     private CommandlineJava.SysProperties sysProperties =
         new CommandlineJava.SysProperties();

    
Namespace prefix--URI bindings
 
     private Hashtable<StringStringbindings =
 	new Hashtable<String,String> ();

    
The <option>s, ready for further processing
 
     private Vector<Optionoptions = new Vector<Option> ();

    
The processed options, ready for passing to Calabash
 
     private Map<QName,RuntimeValueoptionsMap =
 	new HashMap<QName,RuntimeValue> ();

    
The <param>s, ready for further processing
 
     private Vector<Parameterparameters = new Vector<Parameter> ();

    
The processed parameters, ready for passing to Calabash
 
whether to enable debug output
 
     private boolean debug = false;

    
whether to enable general values. Description is about 'general values', but XProcConfiguration field is 'extensionValues'.
 
     private boolean extensionValues = false;

    
whether the xpointer attribute on an XInclude element can be used when parse="text"
 
     private boolean allowXPointerOnText = false;

    
whether to use XSLT 1.0 when ???
 
     private boolean useXslt10 = false;

    
whether to automatically translate between JSON and XML
 
     private boolean transparentJSON = false;

    
flavor of JSON to use. As attribute.
 
     String jsonFlavor = null;
 
     /* End of fields to reset at end of execute(). */

    
Set the base directory; optional, default is the project's basedir.

Parameters:
dir the base directory
 
     public void setBasedir(File dir) {
          = dir;
     }

    
Set the input port name. optional, default is the first unmatched pipeline input port.

Parameters:
port the port name
 
     public void setinPort(String port) {
          = port;
     }

    
Set the input resource. optional, implicit and/or explicit filest will be used if this and outResource are not set.

Parameters:
inResource the org.apache.tools.ant.types.Resource
 
     public void setIn(Resource inResource) {
         this. = inResource;
     }

    
Work with an instance of an <input> element already configured by Ant.

Parameters:
i the configured input Port
 
     public void addConfiguredInput(Port i) {
 	if (!i.shouldUse()) {
 	    log("Skipping input '" + i.getPort() + "' as it is configured to be unused.", Project.MSG_DEBUG);
 	    return;
 	}
 
 	String port = i.getPort();
 	FileNameMapper inputMapper = i.getMapper();
 	Union resources = i.getResources();
 
 	if (port == null) {
             port = ;
         }
 
 	if (inputMapper != null && resources.size() != 0) {
 	    handleError("Both mapper and fileset on input port: " + port);
 	    return;
 	}
 
 	if (inputMapper != null) {
 	    if (port.equals()) {
 		handleError("Cannot use mapper on main input port: " + port);
 		return;
 	    }
 	    if (.containsKey(port)) {
 		handleError("Mapper used on input port that already has resources: " + port);
 		return;
 	    }
 
 	    if (.containsKey(port)) {
 		handleError("Mapper used on input port that already has a mapper: " + port);
 		return;
 	    }
 
 	    .put(portinputMapper);
 	} else {
 	    if (.containsKey(port)) {
 		handleError("Resources used on input port that already has a mapper: " + port);
 		return;
 	    }
 
 	    if (!.containsKey(port)) {
 		.put(portnew Union ());
 	    }
 
 	    .get(port).add(resources);
 	}
     }

    
Whether the build should fail if the nested resource collection is empty.
 
     public void setFailOnNoResources(boolean b) {
          = b;
     }

    
Set the pipeline. optional, nested <pipeline> will be used if not set.

Parameters:
uri pipeline location
 
     public void setPipeline(String uri) {
          = uri;
     }

    
API method to set the pipeline Resource.

Parameters:
pipelineResource Resource to set as the pipeline.
 
     public void setPipelineResource(Resource pipelineResource) {
  	this. = pipelineResource;
     }

    
Add a nested <pipeline> element.

Parameters:
rc the configured Resources object represented as <pipeline>.
 
     public void addConfiguredPipeline(Resources rc) {
  	if (rc.size() != 1) {
 	    throw new BuildException("The pipeline element must be specified with exactly one"
 			+ " nested resource.");
  	} else {
 	    setPipelineResource((Resource) rc.iterator().next());
  	}
     }

    
Set the destination directory into which the XSL result files should be copied to; required, unless in and out are specified.

Parameters:
dir the name of the destination directory
 
     public void setDestdir(File dir) {
          = dir;
     }

    
Set the output port name. optional, default is the first unmatched pipeline output port.

Parameters:
port the port name
 
     public void setOutPort(String port) {
          = port;
     }

    
Set the output resource. optional, implicit and/or explicit filest will be used if this and inResource are not set.

Parameters:
outResource the org.apache.tools.ant.types.Resource
 
     public void setOut(Resource outResource) {
         this. = outResource;
     }

    
Work with an instance of an <output> element already configured by Ant.

Parameters:
o the configured Port
 
     public void addConfiguredOutput(Port o) {
 	if (!o.shouldUse()) {
 	    log("Skipping output '" + o.getPort() + "' as it is configured to be unused.", Project.MSG_DEBUG);
 	    return;
 	}
 
 	String port = o.getPort();
  	FileNameMapper outputMapper = o.getMapper();
 	Union resources = o.getResources();
 
 	if (port == null) {
             port = ;
         }
 
 	if (outputMapper != null && resources.size() != 0) {
 	    handleError("Both mapper and fileset on input port: " + port);
 	    return;
 	}
 
 	if (outputMapper != null) {
 	    if (.containsKey(port)) {
 		handleError("Mapper used on output port that already has resources: " + port);
 		return;
 	    }
 
 	    if (.containsKey(port)) {
 		handleError("Mapper used on output port that already has a mapper: " + port);
 		return;
 	    }
 
 	    .put(portoutputMapper);
 	} else {
 	    if (.containsKey(port)) {
 		handleError("Resources used on output port that already has a mapper: " + port);
 		return;
 	    }
 
 	    if (!.containsKey(port)) {
 		.put(portnew Union ());
 	    }
 	    .get(port).add(o.getResources());
 	}
     }

    
Set the desired file extension to be used for the target; optional, default is '-out.xml'.

Parameters:
name the extension to use
 
     public void setExtension(String name) {
          = name;
     }

    
Whether any errors should make the build fail.
 
     public void setFailOnError(boolean b) {
          = b;
     }

    
Adds a collection of resources to process in addition to the given file or the implicit fileset.

Parameters:
rc the collection of resources to style
 
     public void add(ResourceCollection rc) {
         .add(rc);
 	 = true;
     }

    
Whether to use the implicit fileset.

Set this to false if you want explicit control with nested resource collections.

Parameters:
useimplicitfileset set to true if you want to use implicit fileset
 
     public void setUseImplicitFileset(boolean useimplicitfileset) {
          = useimplicitfileset;
     }

    
Whether to process all files in the included directories as well; optional, default is true.

Parameters:
b true if files in included directories are processed.
 
     public void setScanIncludedDirectories(boolean b) {
          = b;
     }

    
Defines the mapper to map source to destination files.

Parameters:
mapper the mapper to use
Throws:
BuildException if more than one mapper is defined
 
     public void addMapper(Mapper mapperthrows BuildException {
 	add(mapper.getImplementation());
     }

    
Adds a nested filenamemapper.

Parameters:
fileNameMapper the mapper to add
Throws:
BuildException if more than one mapper is defined
 
     public void add(FileNameMapper fileNameMapperthrows BuildException {
         if ( != null) {
             handleError("Cannot define more than one mapper");
 	    return;
         }
 
 	 = fileNameMapper;
     }

    
Set whether to check dependencies, or always generate; optional, default is false.

Parameters:
force true if always generate.
 
     public void setForce(boolean force) {
         this. = force;
     }

    
A system property to set during transformation.
 
     public void addSysproperty(Environment.Variable sysp) {
         .addVariable(sysp);
     }

    
A set of system properties to set during transformation.
 
     public void addSyspropertyset(PropertySet sysp) {
         .addSyspropertyset(sysp);
     }

    
Work with an instance of a <binding> element already configured by Ant.

Parameters:
n the configured Namespace
 
     public void addConfiguredNamespace(Namespace n) {
 	// prefix and/or uri may have been omitted in build file
 	// without Ant complaining
 	if (n.getPrefix() == null) {
 	   handleError("<namespace> prefix cannot be null");
 	   return;
 	}
 
 	if (n.getURI() == null) {
 	   handleError("<namespace> URI cannot be null");
 	   return;
 	}
 
 	    handleError("Duplicated <namespace> prefix: " + n.getPrefix());
 	   return;
 	}
 
         .put(n.getPrefix(), n.getURI());
     }

    
Work with an instance of a <option> element already configured by Ant.

Parameters:
o the configured Option
 
     public void addConfiguredOption(Option o) {
 	if (!o.shouldUse()) {
 	    log("Skipping option '" + o.getName() + "' as it is configured to be unused.", Project.MSG_DEBUG);
 	    return;
 	}
 
     }

    
Work with an instance of a <parameter> element already configured by Ant.

Parameters:
p the configured Parameter
 
     public void addConfiguredParameter(Parameter p) {
 	if (!p.shouldUse()) {
 	    log("Skipping parameter '" + p.getName() + "' as it is configured to be unused.", Project.MSG_DEBUG);
 	    return;
 	}
 
     }

    
Set whether to enable debugging output; optional, default is false.

Parameters:
debug true if enable debug output
 
     public void setDebug(boolean debug) {
         this. = debug;
     }

    
Set whether to enable general values; optional, default is false.

Parameters:
generalValues true if enable general values
See also:
General values extension
 
     public void setGeneralValues(boolean generalValues) {
         this. = generalValues;
     }

    
Set whether xpointer attribute on an XInclude element can be used when parse="text"; optional, default is false.

Parameters:
xpointerOnText true if enable XPointer on text
 
     public void setXPointerOnText(boolean xpointerOnText) {
         this. = xpointerOnText;
     }

    
Set whether to enable use of XSLT 1.0; optional, default is false.

Parameters:
useXslt10 true if enable XSLT 1.0 support
 
     public void setUseXslt10(boolean useXslt10) {
         this. = useXslt10;
     }

    
Set whether to automatically translate between JSON and XML; optional, default is false.

Parameters:
transparentJSON true if enable translation
 
     public void setTransparentJSON(boolean transparentJSON) {
         this. = transparentJSON;
     }

    
Set whether to automatically translate between JSON and XML; optional, default is false.

Parameters:
jsonFlavor the flavor of JSON/XML transformation to use
 
     public void setJSONFlavor(String jsonFlavor) {
         this. = jsonFlavor;
     }


    
Do the work.
 
     public void execute() {
 	Resource usePipelineResource = null;
 	if ( != null) {
 	    // If we enter here, it means that the pipeline is supplied
 	    // via 'pipeline' attribute
 	    File pipelineFile = getProject().resolveFile();
 	    FileResource fr = new FileResource();
 	    fr.setProject(getProject());
 	    fr.setFile(pipelineFile);
 	    usePipelineResource = fr;
 	} else {
 	    usePipelineResource = ;
 	}
 
 	if (!usePipelineResource.isExists()) {
 	    handleError("pipeline '" + usePipelineResource.getName() + "' does not exist");
 	    return;
 	}
 
 	if ( != null && !.isExists()) {
 	    handleError("input file '" + .getName() + "' does not exist");
 	    return;
 	}
 
 	if ( != null && .size() != 0) {
 	    handleError("'in' and explicit filesets cannot be used together.");
 	    return;
 	}
 
 	if (( != null ||  != null) && ) {
 	    log("'in' and/or 'out' cannot be used with implicit fileset: ignoring implicit fileset.", Project.MSG_VERBOSE);
 	     = false;
 	}
 
 	if ( != null &&  != null) {
 	    handleError("Nested <mapper> for default output and 'out' cannot be used together.");
 	    return;
 	}
 
 	if ((.containsKey() ||
 	     .containsKey()) &&
 	     != null) {
 	    handleError("Nested <mapper> and port for default output cannot be used together.");
 	    return;
 	}
 
 	if ( != null && ) {
 	    handleError("'extension' and 'out' cannot be used together.");
 	    return;
 	}
 
 	if ( &&  != null) {
 	    handleError("'extension' and nested <mapper> cannot be used together.");
 	    return;
 	}
 
 	File savedBaseDir = ;
 
         try {
 	    if ( == null) {
 		 = getProject().getBaseDir();
 	    }
 
 	    if (.size() > 0) {
 		.setSystem();
 	    }
 
 	    // When prefix "p" not set, default to the XProc namespace
 	    if (!.containsKey("p")) {
 	    }
 
 	    // Can only really work with options now bindings all present
 	    for (Option o : ) {
 		QName qname = makeQName(o.getName());
 		String value = o.getValue();
 
 		if (.containsKey(qname)) {
 		    handleError("Duplicated option QName: " + qname.getClarkName());
 		    continue;
 		}
 
 		.put(qnamenew RuntimeValue(value));
 	    }
 
 	    // Can only really work with parameters now bindings all present
 	    for (Parameter p : ) {
 		String port = p.getPort();
 		QName qname = makeQName(p.getName());
 		String value = p.getValue();
 
 		if (!.containsKey(port)) {
 		    portParams = new Hashtable<QName,RuntimeValue> ();
 		} else {
 		    portParams = .get(port);
 		    if (portParams.containsKey(qname)) {
 			handleError("Duplicated parameter QName: " + qname.getClarkName());
 			continue;
 		    }
 		}
 
 		portParams.put(qnamenew RuntimeValue(value));
 		.put(portportParams);
 	    }
 
 	    //-- make sure destination directory exists...
 	    checkDest();
 
 	    // if we have an in file or out file then process them
 	    if ( != null) {
 		Port i = new Port();
 	    }
 	    // Since processing specified inputs, use outResource too
 	    if ( != null) {
 		Port o = new Port();
 	    }
 
 	    if (.containsKey()
 		&& ( ||  != null)) {
 		handleError("Either 'out' or <output> corresponding to default output port and either 'extension' and nested <mapper> for naming output cannot be used together.");
 		return;
 	    }
 
 	    // Set up Calabash config.
 	    XProcConfiguration config =
 		new XProcConfiguration("he"false);
             config.extensionValues |= ;
             config.xpointerOnText |= ;
             config.transparentJSON |= ;
             if ( != null) {
 		if (!JSONtoXML.knownFlavor()) {
 		    handleError("Can't parse JSON flavor '" +  + "' or unrecognized format: " + );
 		    return;
                     }
                 config.jsonFlavor = ;
             }
             config.useXslt10 |= ;
 
             config.debug = ;
 
 	    // If neither implicit or explicit fileset, assume user
 	    // knows what they're doing even though there may be no
 	    // input or output ports.
 	    if (! && .size() == 0) {
 		HashMap<String, Union> useInputResources =
 		    new HashMap<String, Union> ();
 		// Any fixed resources on any input ports.
 		useInputResources.putAll();
 		// Any mapped resources on non-inPort input ports.
 		for (String port : .keySet()) {
 		    FileNameMapper inputMapper = .get(port);
 		    for (Resource resource : .get().listResources()) {
 			String[] inputFileNames =
 			    inputMapper.mapFileName(resource.getName());
 			// Mapper may produce zero or more filenames,
 			// which may or may not be what was wanted but
 			// only the user will know that.
 			Union mappedResources = new Union();
 			for (String fileName : inputFileNames) {
 			    FileResource mappedResource =
 				new FileResource(fileName);
 			    if (mappedResource.isExists()) {
 				mappedResources.add(mappedResource);
 			    } else {
 				log("Skipping non-exstent mapped resource: " + mappedResource.toString(), Project.MSG_DEBUG);
 			    }
 			}
 			useInputResources.put(portmappedResources);
 		    }
 		}
 		HashMap<String, Union> useOutputResources =
 		    new HashMap<String, Union> ();
 		useOutputResources.putAll();
 
 		if (.size() != 0) {
 		    for (Resource resource : .get().listResources()) {
 			// Aadd any mapped resources on output ports.
 			for (String port : .keySet()) {
 			    FileNameMapper outputMapper = .get(port);
 
 			    String[] outputFileNames =
 				outputMapper.mapFileName(resource.getName());
 			    // Mapper may produce zero or more filenames,
 			    // which may or may not be what was wanted but
 			    // only the user will know that.
 			    if (outputFileNames != null) {
 				Union outputResources = new Union();
 				for (String fileName : outputFileNames) {
 				    outputResources.add(new FileResource(fileName));
 				}
 				useOutputResources.put(portoutputResources);
 			    }
 			}
 		    }
 		}
 		process(config,
 			useInputResources,
 			useOutputResources,
 			usePipelineResource,
 		//return;
 	    } else { // Using implicit and/or explicit filesets
 		    DirectoryScanner scanner = getDirectoryScanner();
 		    log("Pipelining into " + , Project.MSG_INFO);
 
 		    // Process all the files marked for styling
 		    String[] includedFiles = scanner.getIncludedFiles();
 		    for (int i = 0; i < includedFiles.length; ++i) {
 			.add(new FileResource(includedFiles[i]));
 		    }
 		    if () {
 			// Process all the directories marked for styling
 			String[] includedDirs = scanner.getIncludedDirectories();
 			for (int j = 0; j < includedDirs.length; ++j) {
 			    includedFiles = new File(includedDirs[j]).list();
 			    for (int i = 0; i < includedFiles.length; ++i) {
 				.add(new FileResource(includedDirs[j] + . + includedFiles[i]));
 			    }
 			}
 		    }
 		} else { // only resource collections, there better be some
 		    if (.size() == 0) {
 			    handleError("no resources specified");
 			}
 			return;
 		    }
 		}
 
     		FileNameMapper useMapper = null;
 		if (!.containsKey()) {
 		    if ( != null) {
 			useMapper = ;
 		    } else {
 			useMapper = new ExtensionMapper();
 		    }
                 }
 
 		// Process implicit and/or explicit resources one at a
 		// time.
                 for (Resource resource : .listResources()) {
                     log("Resource: " + resource.getName(), Project.MSG_DEBUG);
                     HashMap<String, Union> useInputResources =
 			new HashMap<String, Union> ();
 
 		    // Any fixed resources on other input ports.
 		    useInputResources.putAll();
 		    // The resource.
                     useInputResources.put(new Union(resource));
 		    // Any mapped resources on other input ports.
 		    for (String port : .keySet()) {
 			FileNameMapper inputMapper = .get(port);
 
                         String[] inputFileNames =
 			    inputMapper.mapFileName(resource.getName());
 			// Mapper may produce zero or more filenames,
 			// which may or may not be what was wanted but
 			// only the user will know that.
 			if (inputFileNames != null) {
 			    Union mappedResources = new Union();
 			    for (String fileName : inputFileNames) {
 				mappedResources.add(new FileResource(fileName));
 			    }
 			    useInputResources.put(portmappedResources);
 			}
 		    }
 
                     HashMap<String, Union> useOutputResources =
 			new HashMap<String, Union> ();
 		    useOutputResources.putAll();
 		    // FIXME: Why is it necessary to check for null?
                     if (useMapper != null) {
                         String[] outFileName = useMapper.mapFileName(resource.getName());
 			// Require exactly one output for each mapped
 			// input.
                         if (outFileName == null || outFileName.length == 0) {
                             log("Skipping '" + resource.getName() + "' as it cannot be mapped to output.", Project.MSG_VERBOSE);
                             continue;
                         } else if (outFileName == null || outFileName.length > 1) {
                             log("Skipping " + resource.getName() + " as its mapping is ambiguous.", Project.MSG_VERBOSE);
                             continue;
                         }
                         useOutputResources.put(new Union(new FileResource(outFileName[0])));
                     }
 
 		    // Any mapped resources on other output ports.
 		    for (String port : .keySet()) {
 			FileNameMapper outputMapper = .get(port);
 
                         String[] outputFileNames =
 			    outputMapper.mapFileName(resource.getName());
 			// Mapper may produce zero or more filenames,
 			// which may or may not be what was wanted but
 			// only the user will know that.
 			if (outputFileNames != null) {
 			    Union outputResources = new Union();
 			    for (String fileName : outputFileNames) {
 				outputResources.add(new FileResource(fileName));
 			    }
 			    useOutputResources.put(portoutputResources);
 			}
 		    }
                     process(configuseInputResourcesuseOutputResourcesusePipelineResource);
                 }
 	    }
 	} finally {
 	    // Same instance is reused when Ant runs this task
 	    // again, so reset everything.
 	    .clear();
 	    .clear();
 	    .clear();
              = null;
 	     = null;
 	     = null;
 	     = true;
 	     = null;
 	     = null;
 	     = null;
 	     = null;
 	     = null;
 	     = "-out.xml";
 	     = false;
 	     = true;
 	     = new Union();
 	     = false;
 	     = true;
 	     = true;
 	     = null;
 	     = false;
             if (.size() > 0) {
                 .restoreSystem();
 		// No way to clear CommandlineJava.SysProperties
 		 = new CommandlineJava.SysProperties();
             }
 	    .clear();
 	    .clear();
 	    .clear();
 	    .clear();
 	     = false;
 	     = false;
 	     = false;
 	     = false;
 	     = false;
 	     = null;
 	}
     }

    
Process the input file to the output file with the given pipeline.

Parameters:
inputResources the map of input ports to resources
outputResources the map of output ports to resources
pipelineResource the pipeline to use.
Throws:
BuildException if the processing fails.
 
     private void process(XProcConfiguration config,
 			 Map<String,Union> inputResources,
 			 Map<String,Union> outputResources,
 			 Resource pipelineResource,
 			 Map<QName,RuntimeValueoptionsMap,
 			 Map<String,Hashtable<QName,RuntimeValue>> parametersMap,
 			 boolean forcethrows BuildException {
 
 	long pipelineLastModified = pipelineResource.getLastModified();
 	Collection<LonginputsLastModified = new Vector<Long> ();
 	for (String port : inputResources.keySet()) {
 	    for (Resource resource : inputResources.get(port).listResources()) {
 		inputsLastModified.add(resource.getLastModified());
 	    }
 	}
 	long newestInputLastModified =
 	    inputsLastModified.isEmpty() ? 0 : Collections.max(inputsLastModified);
 
 	Collection<LongoutputsLastModified = new Vector<Long> ();
 	for (String port : outputResources.keySet()) {
	    for (Resource resource : outputResources.get(port).listResources()) {
		outputsLastModified.add(resource.getLastModified());
	    }
	long oldestOutputLastModified =
	    outputsLastModified.isEmpty() ? 0 : Collections.min(outputsLastModified);
	log("Newest input time: " + newestInputLastModified, Project.MSG_DEBUG);
	log("Oldest output time: " + oldestOutputLastModified, Project.MSG_DEBUG);
	log("Pipeline file " + pipelineResource + " time: " + pipelineLastModified, Project.MSG_DEBUG);
	if (!force) {
	    if (newestInputLastModified < oldestOutputLastModified &&
		pipelineLastModified < oldestOutputLastModified) {
		log("Skipping because all outputs are newer than inputs and newer than pipeline", Project.MSG_DEBUG);
		return;
	    }
	//log("Processing " + in + " to " + out, Project.MSG_INFO);
        XProcRuntime runtime = new XProcRuntime(config);
	XPipeline pipeline = null;
	try {
	    pipeline =
		runtime.load(pipelineResource.toString());
	    // The unnamed input is matched to one unmatched input
	    for (String port : pipeline.getInputs()) {
                if (pipeline.getInput(port).getParameters()) {
                    continue;
                }
		if (!inputResources.containsKey(port)) {
                    if (inputResources.containsKey(null)) {
                        inputResources.put(portinputResources.remove(null));
                        log("Binding unnamed input port to '" + port + "'.", Project.MSG_INFO);
                    } else {
                        log("You didn't specify any binding for the input port '" + port + "'.", Project.MSG_WARN);
                        continue;
                    }
                }
            }
	    for (String port : pipeline.getInputs()) {
                if (inputResources.containsKey(port)) {
		    for (Resource resource : inputResources.get(port).listResources()) {
			log(resource.getName() + "::" + resource.isExists(), Project.MSG_INFO);
			if (!resource.isExists()) {
			    log("Skipping non-existent input: " + resource, Project.MSG_DEBUG);
			InputStream is = resource.getInputStream();
			XdmNode doc = runtime.parse(new InputSource(resource.getInputStream()));
			pipeline.writeTo(portdoc);
		    }
                }
            }
	    // Pass any options to the pipeline
	    for (QName name : optionsMap.keySet()) {
		pipeline.passOption(nameoptionsMap.get(name));
	    }
	    // Pass any parameters to the pipeline
	    for (String port : parametersMap.keySet()) {
		Hashtable<QName,RuntimeValueuseTable = parametersMap.get(port);
		if ("*".equals(port)) { // For primary parameter input port
		    for (QName name : useTable.keySet()) {
			pipeline.setParameter(nameuseTable.get(name));
		    }
else { // For specified parameter input port
		    for (QName name : useTable.keySet()) {
			pipeline.setParameter(portnameuseTable.get(name));
		    }
	    }
	    pipeline.run();
            // The unamed output is matched to one unmatched output
            for (String port : pipeline.getOutputs()) {
		if (!outputResources.containsKey(port)) {
		    if (outputResources.containsKey(null)) {
			outputResources.put(portoutputResources.remove(null));
			log("Binding unnamed output port to '" + port + "'.", Project.MSG_INFO);
		    } else {
			log("You didn't specify any binding for the output port '" + port + "': its output will be discarded.", Project.MSG_WARN);
		    }
            }
            for (String port : pipeline.getOutputs()) {
                String uri = null;
                if (outputResources.containsKey(port)) {
                    Union resources = outputResources.get(port);
		    if (resources.size() != 1) {
			handleError("The '" + port + "' output port must be specified with exactly one"
                        + " nested resource.");
		    }
		    uri = ((Resource) resources.iterator().next()).toString();
                    log("Writing port '" + port + "' to '" + uri + "'.", Project.MSG_INFO);
               }
                if (uri == null) {
                    // You didn't bind it, and it isn't going to stdout, so it's going into the bit bucket.
                    continue;
                }
                Serialization serial = pipeline.getSerialization(port);
                if (serial == null) {
                    // Use the configuration options
                    // FIXME: should each of these be considered separately?
                    // FIXME: should there be command-line options to override these settings?
                    serial = new Serialization(runtimepipeline.getNode()); // The node's a hack
                    for (String name : config.serializationOptions.keySet()) {
                        String value = config.serializationOptions.get(name);
                        if ("byte-order-mark".equals(name)) serial.setByteOrderMark("true".equals(value));
                        if ("escape-uri-attributes".equals(name)) serial.setEscapeURIAttributes("true".equals(value));
                        if ("include-content-type".equals(name)) serial.setIncludeContentType("true".equals(value));
                        if ("indent".equals(name)) serial.setIndent("true".equals(value));
                        if ("omit-xml-declaration".equals(name)) serial.setOmitXMLDeclaration("true".equals(value));
                        if ("undeclare-prefixes".equals(name)) serial.setUndeclarePrefixes("true".equals(value));
                        if ("method".equals(name)) serial.setMethod(new QName(""value));
                        // FIXME: if ("cdata-section-elements".equals(name)) serial.setCdataSectionElements();
                        if ("doctype-public".equals(name)) serial.setDoctypePublic(value);
                        if ("doctype-system".equals(name)) serial.setDoctypeSystem(value);
                        if ("encoding".equals(name)) serial.setEncoding(value);
                        if ("media-type".equals(name)) serial.setMediaType(value);
                        if ("normalization-form".equals(name)) serial.setNormalizationForm(value);
                        if ("standalone".equals(name)) serial.setStandalone(value);
                        if ("version".equals(name)) serial.setVersion(value);
                    }
                }
                // ndw wonders if there's a better way...
                WritableDocument wd = null;
                if (uri != null) {
                    URI furi = new URI(uri);
                    String filename = furi.getPath();
                    FileOutputStream outfile = new FileOutputStream(filename);
                    wd = new WritableDocument(runtime,filename,serial,outfile);
                } else {
                    wd = new WritableDocument(runtime,uri,serial);
                }
                ReadablePipe rpipe = pipeline.readFrom(port);
                while (rpipe.moreDocuments()) {
                    wd.write(rpipe.read());
                }
                if (uri!=null) {
		    wd.close();
                }
            }
catch (Exception err) {
	   handleError("Pipeline failed: " + err.toString());
finally {
	    pipeline = null;
	    runtime = null;
	    config = null;
    }

    
Mapper implementation that replaces file's extension.

If the file has an extension, chop it off. Append whatever the user has specified as extension or "-out.xml".

    private class ExtensionMapper implements FileNameMapper {
        public void setFrom(String from) {
        }
        public void setTo(String to) {
        }
        public String[] mapFileName(String xmlFile) {
            int dotPos = xmlFile.lastIndexOf('.');
            if (dotPos > 0) {
                xmlFile = xmlFile.substring(0, dotPos);
            }
            return new String[] {xmlFile + };
        }
    }

    
Makes a QName using the bindings defined on the task.

Parameters:
name possibly-prefixed name
Returns:
QName
    private QName makeQName(String name) {
	String uri = null;
	QName qname;
	if (name.indexOf("{") == 0) {
	    qname = QName.fromClarkName(name);
else {
	    int cpos = name.indexOf(":");
	    if (cpos > 0) {
		String prefix = name.substring(0, cpos);
		if (!.containsKey(prefix)) {
		    handleError("Unbound prefix \"" + prefix + "\" in: " + name);
		uri = .get(prefix);
		qname = new QName(prefixuriname.substring(cpos+1));
	    } else {
		qname = new QName(""name);
	    }
	return qname;
    }

    
Throws a BuildException if the destination directory hasn't been specified.
    private void checkDest() {
        if ( == null) {
	     = ;
            log("destdir defaulting to basedir", Project.MSG_DEBUG);
        }
    }

    
Throws an exception with the given message if failOnError is true, otherwise logs the message using the WARN level.
    protected void handleError(String msg) {
        if () {
            throw new BuildException(msggetLocation());
        }
        log(msg, Project.MSG_WARN);
    }


    
Throws an exception with the given nested exception if failOnError is true, otherwise logs the message using the WARN level.
    protected void handleError(Throwable ex) {
        if () {
            throw new BuildException(ex);
        } else {
            log("Caught an exception: " + ex, Project.MSG_WARN);
        }
    }

    
The Port inner class used to represent input and output ports.
    public static class Port {
        
The input port
        private String port = null;

        
The input's resources
        private Union resources = new Union();

Mapper to inPort files.
	private FileNameMapper mapper = null;
        private Object ifCond;
        private Object unlessCond;
        private Project project;

        
Set the current project

Parameters:
project the current project
        public void setProject(Project project) {
            this. = project;
        }

        
Set the input port.

Parameters:
port the name of the port.
        public void setPort(String port) {
            this. = port;
        }

Adds a collection of resources to process in addition to the given file or the implicit fileset.

Parameters:
rc the collection of resources to use
	public void add(ResourceCollection rc) {
	    .add(rc);
	}

Defines the mapper to map source to destination files.

Parameters:
mapper the mapper to use
Throws:
BuildException if more than one mapper is defined
	public void addMapper(Mapper mapperthrows BuildException {
	    add(mapper.getImplementation());
	}

Adds a nested filenamemapper.

Parameters:
fileNameMapper the mapper to add
Throws:
BuildException if more than one mapper is defined
	public void add(FileNameMapper fileNameMapperthrows BuildException {
	    if ( != null) {
		throw new BuildException("Cannot define more than one mapper");
	    }
	     = fileNameMapper;
	}

        
Get the port name

Returns:
the port name
        public String getPort() {
            return ;
        }

        
Get the port's resources

Returns:
the port's resources
        public Union getResources() {
            return ;
        }

        
Get the port's Mapper element, if any

Returns:
the ports's mapper
        public FileNameMapper getMapper() {
            return ;
        }

        
Set whether this input should be used. It will be used if the expression evalutes to true or the name of a property which has been set, otherwise it won't.

Parameters:
ifCond evaluated expression
        public void setIf(Object ifCond) {
            this. = ifCond;
        }

        
Set whether this input should be used. It will be used if the expression evalutes to true or the name of a property which has been set, otherwise it won't.

Parameters:
ifProperty evaluated expression
        public void setIf(String ifProperty) {
            setIf((ObjectifProperty);
        }

        
Set whether this input should NOT be used. It will not be used if the expression evaluates to true or the name of a property which has been set, otherwise it will be used.

Parameters:
unlessCond evaluated expression
        public void setUnless(Object unlessCond) {
            this. = unlessCond;
        }

        
Set whether this input should NOT be used. It will not be used if the expression evaluates to true or the name of a property which has been set, otherwise it will be used.

Parameters:
unlessProperty evaluated expression
        public void setUnless(String unlessProperty) {
            setUnless((ObjectunlessProperty);
        }

        
Ensures that the input passes the conditions placed on it with if and unless properties.

Returns:
true if the task passes the "if" and "unless" parameters
        public boolean shouldUse() {
            PropertyHelper ph = PropertyHelper.getPropertyHelper();
            return ph.testIfCondition()
                && ph.testUnlessCondition();
        }
    } // Port

    
The Namespace inner class represents a namespace binding.
    public static class Namespace {
        
The prefix
        private String prefix = null;
        
The URI
        private String uri = null;

        
Set the prefix.

Parameters:
prefix prefix to which to bind the namespace
        public void setPrefix(String prefix) {
            this. = prefix;
        }

Get the prefix

Returns:
the namespace prefix
        public String getPrefix() {
            return ;
        }

       
Set the namespace URI.

Parameters:
uri the namespace URI
        public void setURI(String uri) {
            this. = uri;
        }

Get the namespace URI

Returns:
the namespace URI
        public String getURI() {
            return ;
        }
    } // Namespace

    
The Option inner class represents a pipeline option.
    public static class Option {
        
The name
        private String name = null;
        
The parameter value
        private String value = null;
        private Object ifCond;
        private Object unlessCond;
        private Project project;

        
Set the current project

Parameters:
project the current project
        public void setProject(Project project) {
            this. = project;
        }

       
Set the name.

Parameters:
name the parameter name