| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 |
| * |
| * https://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.ant.dotnet.compile; |
| |
| import java.io.File; |
| import java.util.Vector; |
| import java.util.Iterator; |
| import java.net.MalformedURLException; |
| |
| import org.apache.ant.dotnet.NetCommand; |
| |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.types.EnumeratedAttribute; |
| import org.apache.tools.ant.taskdefs.condition.Os; |
| import org.apache.tools.ant.util.FileUtils; |
| |
| /** |
| * Converts a WSDL file or URL resource into a .NET language. |
| * |
| * Why add a wrapper to the MS WSDL tool? |
| * So that you can verify that your web services, be they written with Axis or |
| *anyone else's SOAP toolkit, work with .NET clients. |
| * |
| *This task is dependency aware when using a file as a source and destination; |
| *so if you <get> the file (with <code>usetimestamp="true"</code>) then |
| *you only rebuild stuff when the WSDL file is changed. Of course, |
| *if the server generates a new timestamp every time you ask for the WSDL, |
| *this is not enough...use the <filesmatch> <condition> to |
| *to byte for byte comparison against a cached WSDL file then make |
| *the target conditional on that test failing. |
| |
| * See "Creating an XML Web Service Proxy", "wsdl.exe" docs in |
| * the framework SDK documentation |
| * @version 0.5 |
| * @ant.task category="dotnet" |
| * @since Ant 1.5 |
| */ |
| |
| public class WsdlToDotnet extends Task { |
| |
| /** |
| * used for timestamp checking |
| */ |
| private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); |
| |
| /** |
| * name of output file (required) |
| */ |
| private File destFile = null; |
| |
| /** |
| * language; defaults to C# |
| */ |
| private String language = "CS"; |
| |
| /** |
| * flag set to true to generate server side skeleton |
| */ |
| private boolean server = false; |
| |
| /** |
| * namespace |
| */ |
| private String namespace = null; |
| |
| /** |
| * flag to control action on execution trouble |
| */ |
| private boolean failOnError = true; |
| |
| /** |
| * any extra command options? |
| */ |
| protected String extraOptions = null; |
| |
| |
| /** |
| * protocol string. Exact value set depends on SOAP stack version. |
| * @since Ant 1.7 |
| */ |
| private String protocol = null; |
| |
| /** |
| * should errors come in an IDE format. This |
| * is WSE only. |
| * @since Ant 1.7 |
| */ |
| private boolean ideErrors = false; |
| |
| /** |
| * filesets of file to compile |
| * @since Ant 1.7 |
| */ |
| private Vector schemas = new Vector(); |
| |
| /** |
| * our WSDL file. |
| * @since ant1.7 |
| */ |
| private Schema wsdl = new Schema(); |
| |
| /** |
| * compiler |
| * @since ant1.7 |
| */ |
| private Compiler compiler = null; |
| |
| /** |
| * error message: dest file is a directory |
| */ |
| public static final String ERROR_DEST_FILE_IS_DIR = "destination file is a directory"; |
| |
| /** |
| * error message: no dest file |
| */ |
| public static final String ERROR_NO_DEST_FILE = "destination file must be specified"; |
| |
| /** |
| * Name of the file to generate. Required |
| * @param destFile filename |
| */ |
| public void setDestFile(File destFile) { |
| this.destFile = destFile; |
| } |
| |
| /** |
| * Sets the URL to fetch. Fetching is by wsdl.exe; Ant proxy settings |
| * are ignored; either url or srcFile is required. |
| * @param url url to save |
| */ |
| |
| public void setUrl(String url) { |
| wsdl.setUrl(url); |
| } |
| |
| /** |
| * The local WSDL file to parse; either url or srcFile is required. |
| * @param srcFile WSDL file |
| */ |
| public void setSrcFile(File srcFile) { |
| wsdl.setFile(srcFile); |
| } |
| |
| /** |
| * set the language; one of "CS", "JS", or "VB" |
| * optional, default is CS for C# source |
| * @param language language to generate |
| */ |
| public void setLanguage(String language) { |
| this.language = language; |
| } |
| |
| /** |
| * flag to enable server side code generation; |
| * optional, default=false |
| * @param server server-side flag |
| */ |
| |
| public void setServer(boolean server) { |
| this.server = server; |
| } |
| |
| /** |
| * namespace to place the source in. |
| * optional; default "" |
| * @param namespace new namespace |
| */ |
| public void setNamespace(String namespace) { |
| this.namespace = namespace; |
| } |
| |
| /** |
| * Whether or not a failure should halt the build. |
| * Optional - default is <code>true</code>. |
| * @param failOnError new failure option |
| */ |
| public void setFailOnError(boolean failOnError) { |
| this.failOnError = failOnError; |
| } |
| |
| /** |
| * Any extra WSDL.EXE options which aren't explicitly |
| * supported by the ant wrapper task; optional |
| * |
| *@param extraOptions The new ExtraOptions value |
| */ |
| public void setExtraOptions(String extraOptions) { |
| this.extraOptions = extraOptions; |
| } |
| |
| /** |
| * Defines wether errors are machine parseable. |
| * Optional, default=true |
| * |
| * @since Ant 1.7 |
| * @param ideErrors |
| */ |
| public void setIdeErrors(boolean ideErrors) { |
| this.ideErrors = ideErrors; |
| } |
| |
| /** |
| * what protocol to use. SOAP, SOAP1.2, HttpPost and HttpGet |
| * are the base options. Different version and implementations may. |
| * offer different options. |
| * @since Ant 1.7 |
| * |
| * @param protocol |
| */ |
| public void setProtocol(String protocol) { |
| this.protocol = protocol; |
| } |
| |
| /** |
| * add a new source schema to the compilation |
| * @since Ant 1.7 |
| * |
| * @param source |
| */ |
| public void addSchema(Schema source) { |
| schemas.add(source); |
| } |
| |
| /** |
| * flag to trigger turning a filename into a file:url |
| * ignored for the mono compiler. |
| * @param b |
| */ |
| public void setMakeURL(boolean b) { |
| wsdl.setMakeURL(b); |
| } |
| |
| /** |
| * identify the compiler |
| * @since Ant 1.7 |
| * @param compiler |
| */ |
| public void setCompiler(Compiler compiler) { |
| this.compiler = compiler; |
| } |
| |
| /** |
| * validation code |
| * @throws BuildException if validation failed |
| */ |
| protected void validate() |
| throws BuildException { |
| if (destFile == null) { |
| throw new BuildException(ERROR_NO_DEST_FILE); |
| } |
| if (destFile.isDirectory()) { |
| throw new BuildException( |
| ERROR_DEST_FILE_IS_DIR); |
| } |
| wsdl.validate(); |
| } |
| |
| /** |
| * do the work by building the command line and then calling it |
| * |
| *@throws BuildException if validation or execution failed |
| */ |
| public void execute() |
| throws BuildException { |
| if ("WsdlToDotnet".equals(getTaskType())) { |
| log("Warning: the task name <WsdlToDotnet> is deprecated. Use <wsdltodotnet> (all lowercase) instead.", Project.MSG_WARN); |
| } |
| |
| if (compiler == null) { |
| compiler = Compiler.createDefaultCompiler(); |
| } |
| validate(); |
| NetCommand command = new NetCommand(this, |
| "WSDL", |
| compiler.getCommand()); |
| command.setFailOnError(failOnError); |
| //fill in args |
| compiler.applyExtraArgs(command); |
| command.addArgument("/nologo"); |
| command.addArgument("/out:" + destFile); |
| command.addArgument("/language:", language); |
| if (server) { |
| command.addArgument("/server"); |
| } |
| command.addArgument("/namespace:", namespace); |
| if (protocol != null) { |
| command.addArgument("/protocol:" + protocol); |
| } |
| if (ideErrors) { |
| command.addArgument("/parsableErrors"); |
| } |
| command.addArgument(extraOptions); |
| |
| //set source and rebuild options |
| boolean rebuild = true; |
| long destLastModified = -1; |
| |
| //rebuild unless the dest file is newer than the source file |
| if (destFile.exists()) { |
| destLastModified = destFile.lastModified(); |
| rebuild = isRebuildNeeded(wsdl, destLastModified); |
| } |
| String path; |
| //mark for a rebuild if the dest file is newer |
| path = wsdl.evaluate(); |
| if (!compiler.supportsAbsoluteFiles() && wsdl.getFile() != null) { |
| // Mono 1.0's wsdl doesn't deal with absolute paths |
| File f = wsdl.getFile(); |
| command.setDirectory(f.getParentFile()); |
| path = f.getName(); |
| } |
| command.addArgument(path); |
| //add in any extra files. |
| //this is an error in mono, but we do not warn on it as they may fix that outside |
| //the ant build cycle. |
| Iterator it = schemas.iterator(); |
| while (it.hasNext()) { |
| Schema schema = (Schema) it.next(); |
| //mark for a rebuild if we are newer |
| rebuild |= isRebuildNeeded(schema, destLastModified); |
| command.addArgument(schema.evaluate()); |
| } |
| //conditionally compile |
| if (rebuild) { |
| command.runCommand(); |
| } |
| } |
| |
| /** |
| * checks for a schema being out of data |
| * @param schema url/file |
| * @param destLastModified timestamp, -1 for no dest |
| * @return true if a rebuild is needed. |
| */ |
| private boolean isRebuildNeeded(Schema schema, long destLastModified) { |
| if (destLastModified == -1) { |
| return true; |
| } |
| return !FILE_UTILS.isUpToDate(schema.getTimestamp(), destLastModified); |
| } |
| |
| |
| /** |
| * nested schema class |
| * Only supported on NET until mono add multi-URL handling on the command line |
| */ |
| public static class Schema { |
| private File file; |
| private String url; |
| private boolean makeURL = false; |
| |
| public static final String ERROR_NONE_DECLARED = "One of file and url must be set"; |
| public static final String ERROR_BOTH_DECLARED = "Only one of file or url can be set"; |
| public static final String ERROR_FILE_NOT_FOUND = "Not found: "; |
| public static final String ERROR_FILE_IS_DIR = "File is a directory: "; |
| public static final String ERROR_NO_URL_CONVERT = "Could not URL convert "; |
| |
| /** |
| * validate the schema |
| */ |
| public void validate() { |
| |
| if (file != null) { |
| if (!file.exists()) { |
| throw new BuildException(ERROR_FILE_NOT_FOUND + file.toString()); |
| } |
| if (file.isDirectory()) { |
| throw new BuildException(ERROR_FILE_IS_DIR + file.toString()); |
| } |
| } |
| if (file != null && url != null) { |
| throw new BuildException(ERROR_BOTH_DECLARED); |
| } |
| if (file == null && url == null) { |
| throw new BuildException(ERROR_NONE_DECLARED); |
| } |
| } |
| |
| /** |
| * Validate our settings. |
| * @return either the URL or the full file path |
| */ |
| public String evaluate() { |
| validate(); |
| if (url != null) { |
| return getUrl(); |
| } |
| if (makeURL) { |
| try { |
| return FILE_UTILS.getFileURL(file).toExternalForm(); |
| } catch (MalformedURLException e) { |
| throw new BuildException(ERROR_NO_URL_CONVERT + file); |
| } |
| } |
| return file.toString(); |
| } |
| |
| public File getFile() { |
| return file; |
| } |
| |
| /** |
| * name of a file to use as a source of WSDL or XSD data |
| * @param file |
| */ |
| public void setFile(File file) { |
| this.file = file; |
| } |
| |
| public String getUrl() { |
| return url; |
| } |
| |
| /** |
| * url of a resource. |
| * URLs have no timestamp checking, and are not validated |
| * @param url |
| */ |
| public void setUrl(String url) { |
| this.url = url; |
| } |
| |
| public boolean isMakeURL() { |
| return makeURL; |
| } |
| |
| /** |
| * flag to request that a file is turned into an absolute file: URL |
| * before being passed to the WSDL compiler |
| * @param makeURL |
| */ |
| public void setMakeURL(boolean makeURL) { |
| this.makeURL = makeURL; |
| } |
| |
| /** |
| * Gets the file timestamp. |
| * @return the timestamp of a file, or -1 for a URL (meaning we do not know its age) |
| */ |
| public long getTimestamp() { |
| if (file != null) { |
| return file.lastModified(); |
| } else { |
| return -1; |
| } |
| } |
| } |
| |
| /** |
| * The enumerated values for our compiler |
| */ |
| public static class Compiler extends EnumeratedAttribute { |
| |
| public static final String COMPILER_MS = "microsoft"; |
| public static final String COMPILER_MONO = "mono"; |
| public static final String COMPILER_MS_ON_MONO = "microsoft-on-mono"; |
| String[] compilers = { |
| COMPILER_MS, |
| COMPILER_MONO, |
| COMPILER_MS_ON_MONO |
| }; |
| |
| public static final String EXE_WSDL = "wsdl"; |
| public static final String EXE_MONO = "mono"; |
| /** |
| * programs to run |
| */ |
| String[] compilerExecutables = { |
| EXE_WSDL, |
| EXE_WSDL, |
| EXE_MONO |
| }; |
| |
| |
| /** |
| * extra things |
| */ |
| String[][] extraCompilerArgs = { |
| {}, |
| {}, |
| {EXE_WSDL + ".exe"} |
| }; |
| |
| boolean[] absoluteFiles = { |
| true, |
| false, |
| true |
| }; |
| |
| /** |
| * This is the only method a subclass needs to implement. |
| * |
| * @return an array holding all possible values of the enumeration. |
| * The order of elements must be fixed so that <tt>indexOfValue(String)</tt> |
| * always return the same index for the same value. |
| */ |
| public String[] getValues() { |
| return compilers; |
| } |
| |
| /** |
| * Create the default compiler for this platform. |
| * @return the default compiler |
| */ |
| public static Compiler createDefaultCompiler() { |
| Compiler c = new Compiler(); |
| String compilerName; |
| compilerName = Os.isFamily("windows") ? COMPILER_MS : COMPILER_MONO; |
| c.setValue(compilerName); |
| return c; |
| } |
| |
| /** |
| * return the command to run |
| * @return the command |
| */ |
| public String getCommand() { |
| return compilerExecutables[getIndex()]; |
| } |
| |
| /** |
| * return any extra arguments for the compiler |
| * @return extra compiler arguments |
| */ |
| public String[] getExtraArgs() { |
| return extraCompilerArgs[getIndex()]; |
| } |
| |
| public boolean supportsAbsoluteFiles() { |
| return absoluteFiles[getIndex()]; |
| } |
| |
| /** |
| * apply any extra arguments of this class |
| * @param command |
| */ |
| public void applyExtraArgs(NetCommand command) { |
| String[] args = getExtraArgs(); |
| for (int i = 0; i < args.length; i++) { |
| command.addArgument(args[i]); |
| } |
| } |
| |
| } |
| |
| } |