blob: 40a69c90d6fec13244f005894ad729310b9c8843 [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xmlbeans.impl.tool;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.taskdefs.Javac;
import org.apache.tools.ant.taskdefs.Jar;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.FileScanner;
import org.apache.tools.ant.Project;
import java.io.File;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.*;
import java.net.URI;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.impl.common.IOUtil;
/**
* Modeled after Ant's javac and zip tasks.
*
* Schema files to process, or directories of schema files, are set with the 'schema'
* attribute, and can be filtered with 'includes' and 'excludes'.
* Alternatively, one or more nested <fileset> elements can specify the
* files and directories to be used to generate this XMLBean.
* The include set can also define .java files that should be built as well.
* See the FileSet documentation at http://jakarta.apache.org/ant/manual/index.html
* for instructions on FileSets if you are unfamiliar with their usage.
*/
public class XMLBean extends MatchingTask
{
private ArrayList schemas = new ArrayList();
private Set mdefnamespaces;
private Path classpath;
private File destfile,
schema,
srcgendir,
classgendir;
private boolean quiet,
verbose,
debug,
optimize,
download,
srconly,
noupa,
nopvr,
noann,
novdoc,
noext = false,
failonerror = true,
fork = true,
includeAntRuntime = true,
noSrcRegen,
includeJavaRuntime = false,
nowarn = false;
private String typesystemname,
forkedExecutable,
compiler,
debugLevel,
memoryInitialSize,
memoryMaximumSize,
catalog,
javasource;
private List extensions = new ArrayList();
private HashMap _extRouter = new HashMap(5);
private static final String XSD = ".xsd",
WSDL = ".wsdl",
JAVA = ".java",
XSDCONFIG = ".xsdconfig";
public void execute() throws BuildException
{
/* VALIDATION */
//required
if (schemas.size() == 0
&& schema == null
&& fileset.getDir(project) == null)
{
String msg = "The 'schema' or 'dir' attribute or a nested fileset is required.";
if (failonerror)
throw new BuildException(msg);
else
{
log(msg, Project.MSG_ERR);
return;
}
}
_extRouter.put(XSD, new HashSet());
_extRouter.put(WSDL, new HashSet());
_extRouter.put(JAVA, new HashSet());
_extRouter.put(XSDCONFIG, new HashSet());
File theBasedir = schema;
if (schema != null)
{
if (schema.isDirectory())
{
FileScanner scanner = getDirectoryScanner(schema);
String[] paths = scanner.getIncludedFiles();
processPaths(paths, scanner.getBasedir());
}
else
{
theBasedir = schema.getParentFile();
processPaths(new String[] { schema.getName() }, theBasedir);
}
}
if (fileset.getDir(project) != null)
schemas.add(fileset);
Iterator si = schemas.iterator();
while (si.hasNext())
{
FileSet fs = (FileSet) si.next();
FileScanner scanner = fs.getDirectoryScanner(project);
File basedir = scanner.getBasedir();
String[] paths = scanner.getIncludedFiles();
processPaths(paths, basedir);
}
Set xsdList = (Set) _extRouter.get(XSD);
Set wsdlList = (Set) _extRouter.get(WSDL);
if (xsdList.size() + wsdlList.size() == 0)
{
log("Could not find any xsd or wsdl files to process.", Project.MSG_WARN);
return;
}
//optional
Set javaList = (Set) _extRouter.get(JAVA);
Set xsdconfigList = (Set) _extRouter.get(XSDCONFIG);
if (srcgendir == null && srconly)
srcgendir = classgendir;
if (destfile == null && classgendir == null && ! srconly)
destfile = new File("xmltypes.jar");
if (verbose)
quiet = false;
/* EXECUTION */
File[] xsdArray = (File[]) xsdList.toArray(new File[xsdList.size()]);
File[] wsdlArray = (File[]) wsdlList.toArray(new File[wsdlList.size()]);
File[] javaArray = (File[]) javaList.toArray(new File[javaList.size()]);
File[] xsdconfigArray = (File[]) xsdconfigList.toArray(new File[xsdconfigList.size()]);
ErrorLogger err = new ErrorLogger(verbose);
boolean success = false;
try
{
// create a temp directory
File tmpdir = null;
if (srcgendir == null || classgendir == null)
{
tmpdir = SchemaCodeGenerator.createTempDir();
}
if (srcgendir == null)
srcgendir = IOUtil.createDir(tmpdir, "src");
if (classgendir == null)
classgendir = IOUtil.createDir(tmpdir, "classes");
// use the system classpath if user didn't provide any
if (classpath == null)
{
classpath = new Path(project);
classpath.concatSystemClasspath();
}
// prepend the output directory on the classpath
Path.PathElement pathElement = classpath.createPathElement();
pathElement.setLocation(classgendir);
String[] paths = classpath.list();
File[] cp = new File[paths.length];
for (int i = 0; i < paths.length; i++)
cp[i] = new File(paths[i]);
// generate the source
SchemaCompiler.Parameters params = new SchemaCompiler.Parameters();
params.setBaseDir(theBasedir);
params.setXsdFiles(xsdArray);
params.setWsdlFiles(wsdlArray);
params.setJavaFiles(javaArray);
params.setConfigFiles(xsdconfigArray);
params.setClasspath(cp);
params.setName(typesystemname);
params.setSrcDir(srcgendir);
params.setClassesDir(classgendir);
params.setNojavac(true); // always compile using javac task below
params.setDebug(debug);
params.setVerbose(verbose);
params.setQuiet(quiet);
params.setDownload(download);
params.setExtensions(extensions);
params.setErrorListener(err);
params.setCatalogFile(catalog);
params.setIncrementalSrcGen(noSrcRegen);
params.setMdefNamespaces(mdefnamespaces);
params.setNoUpa(noupa);
params.setNoPvr(nopvr);
params.setNoAnn(noann);
params.setNoVDoc(novdoc);
params.setNoExt(noext);
params.setJavaSource(javasource);
success = SchemaCompiler.compile(params);
if (success && !srconly) {
long start = System.currentTimeMillis();
// compile the source
Javac javac = new Javac();
javac.setProject(project);
javac.setTaskName(getTaskName());
javac.setClasspath(classpath);
if (compiler != null) javac.setCompiler(compiler);
javac.setDebug(debug);
if (debugLevel != null) javac.setDebugLevel(debugLevel);
javac.setDestdir(classgendir);
javac.setExecutable(forkedExecutable);
javac.setFailonerror(failonerror);
javac.setFork(fork);
if (javasource != null)
{
javac.setSource(javasource);
javac.setTarget(javasource);
}
else
{
javac.setSource("1.4");
javac.setTarget("1.4");
}
javac.setIncludeantruntime(includeAntRuntime);
javac.setIncludejavaruntime(includeJavaRuntime);
javac.setNowarn(nowarn);
javac.setSrcdir(new Path(project, srcgendir.getAbsolutePath()));
if (memoryInitialSize != null) javac.setMemoryInitialSize(memoryInitialSize);
if (memoryMaximumSize != null) javac.setMemoryMaximumSize(memoryMaximumSize);
javac.setOptimize(optimize);
javac.setVerbose(verbose);
javac.execute();
long finish = System.currentTimeMillis();
if (!quiet)
log("Time to compile code: " + ((double)(finish - start) / 1000.0) + " seconds");
if (destfile != null)
{
// jar the compiled classes
Jar jar = new Jar();
jar.setProject(project);
jar.setTaskName(getTaskName());
jar.setBasedir(classgendir);
jar.setDestFile(destfile);
jar.execute();
}
}
if (tmpdir != null) {
SchemaCodeGenerator.tryHardToDelete(tmpdir);
}
}
catch (BuildException e)
{
// re-throw anything thrown from javac or jar task
throw e;
}
catch (Throwable e)
{
//interrupted means cancel
if (e instanceof InterruptedException || failonerror)
throw new BuildException(e);
log("Exception while building schemas: " + e.getMessage(), Project.MSG_ERR);
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
log(sw.toString(), Project.MSG_VERBOSE);
}
if (!success && failonerror)
throw new BuildException(); //stop the build
}
private void processPaths(String[] paths, File baseDir)
{
for (int i = 0; i < paths.length; i++)
{
int dot = paths[i].lastIndexOf('.');
if (dot > -1)
{
String path = paths[i];
String possExt = path.substring(dot).toLowerCase();
Set set = (Set) _extRouter.get(possExt);
if (set != null)
set.add(new File(baseDir, path));
}
}
}
public void addFileset(FileSet fileset)
{
schemas.add(fileset);
}
/////////////////////////////
//Getter/Setters
public File getSchema()
{
return schema;
}
/**
* A file that points to either an individual schema file or a directory of files.
* It is optional only if one or more &lt;fileset&gt; elements are nested in this
* task.
* @param schema Required, unless a fileset element is nested.
*/
public void setSchema(File schema)
{
this.schema = schema;
}
/**
* The classpath to use if schemas in the fileset import definitions that are
* supplied by other compiled xml beans JAR files, or if .java files are in the
* schema fileset.
* @param classpath Optional.
*/
public void setClasspath(Path classpath)
{
if (this.classpath != null)
this.classpath.append(classpath);
else
this.classpath = classpath;
}
/**
* Adds a path to the classpath.
*/
public Path createClasspath() {
if (classpath == null) {
classpath = new Path(project);
}
return classpath.createPath();
}
/**
* Adds a reference to a classpath defined elsewhere.
* @param classpathref Optional.
*/
public void setClasspathRef(Reference classpathref)
{
if (classpath == null)
classpath = new Path(project);
classpath.createPath().setRefid(classpathref);
}
public Path getClasspath()
{
return classpath;
}
public File getDestfile()
{
return destfile;
}
/**
* Define the name of the jar file created. For instance, "myXMLBean.jar"
* will output the results of this task into a jar with the same name.
* Optional, defaults to "xmltypes.jar".
* @param destfile Optional.
*/
public void setDestfile(File destfile)
{
this.destfile = destfile;
}
public File getSrcgendir()
{
return srcgendir;
}
/**
* Set a location to generate .java files into. Optional, defaults to
* a temp dir.
* @param srcgendir Optional.
*/
public void setSrcgendir(File srcgendir)
{
this.srcgendir = srcgendir;
}
public File getClassgendir()
{
return classgendir;
}
/**
* Set a location to generate .class files into. Optional, defaults to
* a temp dir.
* @param classgendir Optional.
*/
public void setClassgendir(File classgendir)
{
this.classgendir = classgendir;
}
/**
* Choose the implementation for this particular task.
*
* @since Ant 1.5
*/
public void setCompiler(String compiler)
{
this.compiler = compiler;
}
public boolean isDownload()
{
return download;
}
/**
* Set to true to permit the compiler to download URLs for imports
* and includes. Defaults to false, meaning all imports and includes
* must be copied locally.
* @param download Optional.
*/
public void setDownload(boolean download)
{
this.download = download;
}
/**
* If true, compiles with optimization enabled.
*/
public void setOptimize(boolean optimize) {
this.optimize = optimize;
}
/** Gets the optimize flag. */
public boolean getOptimize() {
return optimize;
}
public boolean isVerbose()
{
return verbose;
}
/**
* Controls the amount of output. Defaults to true.
* @param verbose Optional.
*/
public void setVerbose(boolean verbose)
{
this.verbose = verbose;
}
public boolean isQuiet()
{
return quiet;
}
/**
* Controls the amount of output. Defaults to false.
* @param quiet Optional.
*/
public void setQuiet(boolean quiet)
{
this.quiet = quiet;
}
public boolean isDebug()
{
return debug;
}
/**
* Get the value of debugLevel.
* @return value of debugLevel.
*/
public String getDebugLevel() {
return debugLevel;
}
/**
* Keyword list to be appended to the -g command-line switch.
*
* This will be ignored by all implementations except modern
* and classic(ver >= 1.2). Legal values are none or a
* comma-separated list of the following keywords: lines, vars,
* and source. If debuglevel is not specified, by default, :none
* will be appended to -g. If debug is not turned on, this attribute
* will be ignored.
*
* @param v Value to assign to debugLevel.
*/
public void setDebugLevel(String v) {
this.debugLevel = v;
}
/**
* Generate debugging symbols.
* @param debug Optional.
*/
public void setDebug(boolean debug)
{
this.debug = debug;
}
/**
* If true, forks the javac compiler.
*
* @param f "true|false|on|off|yes|no"
*/
public void setFork(boolean f) {
fork = f;
}
/**
* Sets the the name of the javac executable.
*
* <p>Ignored unless fork is true or extJavac has been specified
* as the compiler.</p>
*/
public void setExecutable(String forkExec) {
forkedExecutable = forkExec;
}
public String getExecutable() {
return forkedExecutable;
}
public boolean isSrconly()
{
return srconly;
}
/**
* A value of true means that only source will be generated. Optional,
* default is false.
* @param srconly Optional.
*/
public void setSrconly(boolean srconly)
{
this.srconly = srconly;
}
public String getTypesystemname()
{
return typesystemname;
}
/**
* One or more SchemaCompiler extensions can be passed in via the &lt;extension> subelement.
* Schema Compiler extensions must implement the interface com.xbean.too.SchemaCompilerExtension
*/
public Extension createExtension() {
Extension e = new Extension();
extensions.add(e);
return e;
}
/**
* One or more namespaces in which duplicate definitions are to be ignored
* can be passed in via the &lt;ignoreDuplicatesInNamespaces> subelement.
*/
public void setIgnoreDuplicatesInNamespaces(String namespaces) {
mdefnamespaces = new HashSet();
StringTokenizer st = new StringTokenizer(namespaces, ",");
while (st.hasMoreTokens())
{
String namespace = st.nextToken().trim();
mdefnamespaces.add(namespace);
}
}
public String getIgnoreDuplicatesInNamespaces() {
if (mdefnamespaces == null) {
return null;
}
StringBuilder buf = new StringBuilder();
Iterator i = mdefnamespaces.iterator();
while (i.hasNext()) {
buf.append((String)i.next());
if (i.hasNext()) {
buf.append(",");
}
}
return buf.toString();
}
/**
* The name of the package that the TypeSystemHolder class should be
* generated in. Normally this should be left unspecified. None of
* the xml beans are generated in this package.
* <BR><BR>Use .xsdconfig files to modify xml bean package or class names.
* @param typesystemname Optional.
*/
public void setTypesystemname(String typesystemname)
{
this.typesystemname = typesystemname;
}
public boolean isFailonerror()
{
return failonerror;
}
/**
* Determines whether or not the ant target will continue if the XMLBean
* creation encounters a build error. Defaults to true. Optional.
* @param failonerror Optional.
*/
public void setFailonerror(boolean failonerror)
{
this.failonerror = failonerror;
}
public boolean isIncludeAntRuntime()
{
return includeAntRuntime;
}
public void setIncludeAntRuntime(boolean includeAntRuntime)
{
this.includeAntRuntime = includeAntRuntime;
}
public boolean isIncludeJavaRuntime()
{
return includeJavaRuntime;
}
public void setIncludeJavaRuntime(boolean includeJavaRuntime)
{
this.includeJavaRuntime = includeJavaRuntime;
}
public boolean isNowarn()
{
return nowarn;
}
public void setNowarn(boolean nowarn)
{
this.nowarn = nowarn;
}
public boolean isNoSrcRegen()
{
return noSrcRegen;
}
public void setNoSrcRegen(boolean noSrcRegen)
{
this.noSrcRegen = noSrcRegen;
}
/**
* Set the initial memory size of the underlying javac process.
*/
public String getMemoryInitialSize()
{
return memoryInitialSize;
}
public void setMemoryInitialSize(String memoryInitialSize)
{
this.memoryInitialSize = memoryInitialSize;
}
/**
* Set the maximum memory size of the underlying javac process.
*/
public String getMemoryMaximumSize()
{
return memoryMaximumSize;
}
public void setMemoryMaximumSize(String memoryMaximumSize)
{
this.memoryMaximumSize = memoryMaximumSize;
}
/**
* Do not enforce the unique particle attribution rule.
*/
public void setNoUpa(boolean noupa)
{
this.noupa = noupa;
}
public boolean isNoUpa()
{
return noupa;
}
/**
* Do not enforce the particle valid (restriction) rule.
*/
public void setNoPvr(boolean nopvr)
{
this.nopvr = nopvr;
}
public boolean isNoPvr()
{
return nopvr;
}
/**
* Skip over schema &lt;annotation%gt; elements.
*/
public void setNoAnnotations(boolean noann)
{
this.noann = noann;
}
public boolean isNoAnnotations()
{
return noann;
}
/**
* Do not validate the contents of schema &lt;documentation&gt; elements.
*/
public void setNoValidateDoc(boolean novdoc)
{
this.novdoc = novdoc;
}
public boolean isNoValidateDoc()
{
return novdoc;
}
/**
* Ignore extensions found in .xsdconfig files
* @param novdoc
*/
public void setNoExt(boolean noext)
{
this.noext = noext;
}
public boolean isNoExt()
{
return noext;
}
/**
* Generate java source compatible with the given version. Currently,
* only "1.4" or "1.5" are supported and "1.4" is the default.
*/
public void setJavaSource(String javasource)
{
this.javasource = javasource;
}
public String getJavaSource()
{
return javasource;
}
//REVIEW this allows people to deal with the case where they drag in
//more files for compilation than they should. not sure if this is
//a good thing or not
private String source = null;
public void setSource(String s) { source = s; }
/**
* Gets the XML Catalog file for org.apache.xml.resolver.tools.CatalogResolver. (Note: needs resolver.jar from http://xml.apache.org/commons/components/resolver/index.html)
*/
public String getCatalog()
{
return catalog;
}
/**
* Sets the XML Catalog file for org.apache.xml.resolver.tools.CatalogResolver. (Note: needs resolver.jar from http://xml.apache.org/commons/components/resolver/index.html)
*/
public void setCatalog(String catalog)
{
this.catalog = catalog;
}
private static URI uriFromFile(File f)
{
if (f == null)
return null;
try
{
return f.getCanonicalFile().toURI();
}
catch(java.io.IOException e)
{
// Don't spit out an exception here because on Windows you'll get one
// if the filename is "aux", "lpt1", etc. It's the caller's responsibility
// to deal with those cases correctly, usually by calling FileSvc.invalidPathCheck()
// MessageSvc.get().logException(e);
return f.getAbsoluteFile().toURI();
}
}
public class ErrorLogger extends AbstractCollection
{
private boolean _noisy;
private URI _baseURI;
public ErrorLogger(boolean noisy)
{
_noisy = noisy;
_baseURI = uriFromFile(project.getBaseDir());
}
public boolean add(Object o)
{
if (o instanceof XmlError)
{
XmlError err = (XmlError)o;
if (err.getSeverity() == XmlError.SEVERITY_ERROR)
log(err.toString(_baseURI), Project.MSG_ERR);
else if (err.getSeverity() == XmlError.SEVERITY_WARNING)
log(err.toString(_baseURI), Project.MSG_WARN);
else if (_noisy)
log(err.toString(_baseURI), Project.MSG_INFO);
}
return false;
}
public Iterator iterator()
{
return Collections.EMPTY_LIST.iterator();
}
public int size()
{
return 0;
}
}
}