| /* |
| * |
| * 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 |
| * |
| * 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 flex.ant; |
| |
| import flex.ant.config.ConfigVariable; |
| import flex.ant.config.NestedAttributeElement; |
| import flex.ant.config.OptionSpec; |
| |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.types.Commandline; |
| import org.apache.tools.ant.types.Path; |
| import org.apache.tools.ant.taskdefs.Java; |
| |
| import java.io.File; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.lang.reflect.Method; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.util.List; |
| |
| /** |
| * This class contains common data and logic used by all the Flex Ant tasks. |
| */ |
| public abstract class FlexTask extends Java |
| { |
| /** |
| * The build tool's name. |
| */ |
| protected final String toolName; |
| |
| /** |
| * The build tool's class name. |
| */ |
| private final String toolClassName; |
| |
| /** |
| * The build tool's jar file name. |
| */ |
| private final String jarFileName; |
| |
| /** |
| * The commandline used in execute() |
| */ |
| protected final Commandline cmdl; |
| |
| /** |
| * An array of ConfigVariabes that are set by setDynamicAttribute(). |
| */ |
| protected final ConfigVariable[] variables; |
| |
| protected List nestedAttribs; |
| |
| /** |
| * fork attribute |
| */ |
| protected boolean fork; |
| |
| /** |
| * max memory attribute |
| */ |
| private String maxmemory; |
| |
| private ClassLoader originalContextClassLoader; |
| |
| protected static OptionSpec rslpSpec = new OptionSpec(null, "runtime-shared-library-path", "rslp"); |
| |
| /** |
| * @param toolName The build tool's name. |
| * @param toolClassName The build tool's class name. |
| * @param jarFileName The build tool's jar file. |
| * @param vars An array of ConfigVariables that will be set by attributes of the task |
| */ |
| protected FlexTask(String toolName, String toolClassName, String jarFileName, ConfigVariable[] vars) |
| { |
| this.toolName = toolName; |
| this.toolClassName = toolClassName; |
| this.jarFileName = jarFileName; |
| this.variables = vars; |
| |
| cmdl = new Commandline(); |
| } |
| |
| public Object createDynamicElement(String elementName) |
| { |
| ConfigVariable var = null; |
| |
| for (int i = 0; i < variables.length && var == null; i++) |
| { |
| if (variables[i].matches(elementName)) |
| { |
| var = variables[i]; |
| } |
| } |
| |
| if (var != null) |
| { |
| return createElem(elementName, var.getSpec()); |
| } |
| else |
| { |
| throw new BuildException("The <" + toolName + "> type doesn't support the \"" + |
| elementName + "\" nested element.", getLocation()); |
| } |
| } |
| |
| protected NestedAttributeElement createElem(String attrib, OptionSpec spec) |
| { |
| NestedAttributeElement e = new NestedAttributeElement(attrib, spec, this); |
| nestedAttribs.add(e); |
| return e; |
| } |
| |
| protected NestedAttributeElement createElem(String[] attribs, OptionSpec spec) |
| { |
| NestedAttributeElement e = new NestedAttributeElement(attribs, spec, this); |
| nestedAttribs.add(e); |
| return e; |
| } |
| |
| protected NestedAttributeElement createElemAllowAppend(String[] attribs, OptionSpec spec) |
| { |
| NestedAttributeElement e = new NestedAttributeElement(attribs, spec, this, true); |
| nestedAttribs.add(e); |
| return e; |
| } |
| |
| /*=======================================================================* |
| * Static Attributes * |
| *=======================================================================*/ |
| /** |
| * Sets whether to run the task in a separate VM. |
| * |
| * @param f if true then run in a separate VM. |
| */ |
| public void setFork(boolean f) |
| { |
| super.setFork(f); |
| this.fork = f; |
| } |
| |
| /** |
| * Sets the max memory of each VM |
| * |
| * @param max max memory parameter |
| */ |
| public void setMaxmemory(String max) |
| { |
| super.setMaxmemory(max); |
| this.maxmemory = max; |
| } |
| |
| /*=======================================================================* |
| * Dynamic Attributes * |
| *=======================================================================*/ |
| |
| /** |
| * Set the named attribute to the given value. |
| * |
| * @param attributeName The name of the attribute to set |
| * @param value The value to set the named attribute to |
| */ |
| public void setDynamicAttribute(String attributeName, String value) |
| { |
| ConfigVariable var = null; |
| |
| for (int i = 0; i < variables.length && var == null; i++) |
| { |
| if (variables[i].matches(attributeName)) |
| { |
| var = variables[i]; |
| } |
| } |
| |
| if (var != null) |
| { |
| var.set(value); |
| } |
| else |
| { |
| throw new BuildException("The <" + toolName + "> type doesn't support the \"" + |
| attributeName + "\" attribute.", getLocation()); |
| } |
| } |
| |
| /*=======================================================================* |
| * Execute and Related Functions * |
| *=======================================================================*/ |
| |
| /** |
| * Called by execute after the set ConfigVariables in <code>vars</code> has |
| * been added to the commandline. This function is responsible for adding |
| * all tool-specific options to the commandline as well as setting the |
| * default options of a build tool. |
| */ |
| protected abstract void prepareCommandline() throws BuildException; |
| |
| /** |
| * Execute the task |
| * |
| * @throws BuildException If running build tool failed |
| */ |
| public final void execute() throws BuildException |
| { |
| String flexHomeProperty = getProject().getProperty("FLEX_HOME"); |
| |
| if (flexHomeProperty == null) |
| { |
| throw new BuildException("FLEX_HOME must be set to use the Flex Ant Tasks"); |
| } |
| |
| System.setProperty("FLEX_HOME", flexHomeProperty); |
| |
| cmdl.createArgument().setValue("+flexlib=" + flexHomeProperty + "/frameworks"); |
| |
| prepareCommandline(); |
| |
| if (fork) |
| executeOutOfProcess(); |
| else |
| executeInProcess(); |
| |
| } |
| |
| /** |
| * Executes the task in a separate VM |
| */ |
| private void executeOutOfProcess() throws BuildException |
| { |
| try |
| { |
| Class toolClass = resolveClass(toolClassName); |
| |
| super.setClassname(toolClassName); |
| |
| // convert arguments into a string for use by executeJava() |
| // also auto-quotes arguments with spaces |
| super.createArg().setLine( |
| Commandline.toString(cmdl.getArguments())); |
| |
| int err = super.executeJava(); |
| //check error code |
| if (err > 0) |
| { |
| throw new BuildException(toolName + " task failed."); |
| } |
| } |
| finally |
| { |
| if (originalContextClassLoader != null) |
| { |
| Thread.currentThread().setContextClassLoader(originalContextClassLoader); |
| } |
| } |
| } |
| |
| /** |
| * Executes the task in the same VM |
| */ |
| private void executeInProcess() throws BuildException |
| { |
| try |
| { |
| Class toolClass = resolveClass(toolClassName); |
| Class threadLocalToolkitClass = resolveClass("flex2.compiler.util.ThreadLocalToolkit"); |
| |
| log("FlexTask.execute: " + cmdl, Project.MSG_DEBUG); |
| |
| int errorCount = 0; |
| |
| try |
| { |
| Method toolMethod = toolClass.getMethod(toolName, new Class[] {String[].class}); |
| toolMethod.invoke(null, new Object[] {cmdl.getArguments()}); |
| |
| Method errorCountMethod = threadLocalToolkitClass.getMethod("errorCount", (Class[]) null); |
| errorCount = ((Integer) errorCountMethod.invoke(null, (Object[]) null)).intValue(); |
| } |
| catch (Exception e) |
| { |
| StringWriter stringWriter = new StringWriter(); |
| PrintWriter printWriter = new PrintWriter(stringWriter); |
| e.printStackTrace(printWriter); |
| log(stringWriter.toString(), Project.MSG_DEBUG); |
| throw new BuildException("Unable to run " + toolName + ": " + e.getMessage(), e); |
| } |
| |
| if (errorCount > 0) |
| { |
| throw new BuildException(toolName + " task failed"); |
| } |
| } |
| finally |
| { |
| if (originalContextClassLoader != null) |
| { |
| Thread.currentThread().setContextClassLoader(originalContextClassLoader); |
| } |
| } |
| } |
| |
| private Class resolveClass(String className) |
| { |
| Class result = null; |
| |
| try |
| { |
| result = Class.forName(className, true, Thread.currentThread().getContextClassLoader()); |
| } |
| catch (ClassNotFoundException ignoredClassNotFoundException) |
| { |
| String flexHomeProperty = getProject().getProperty("FLEX_HOME"); |
| |
| if (flexHomeProperty != null) |
| { |
| File flexHome = new File(flexHomeProperty); |
| |
| if ( flexHome.exists() ) |
| { |
| File jarFile = new File(flexHome + "/lib", jarFileName); |
| |
| if (jarFile.exists()) |
| { |
| try |
| { |
| URLClassLoader urlClassLoader = new URLClassLoader(new URL[] {jarFile.toURL()}); |
| result = Class.forName(className, true, urlClassLoader); |
| originalContextClassLoader = Thread.currentThread().getContextClassLoader(); |
| Thread.currentThread().setContextClassLoader(urlClassLoader); |
| |
| if (fork) |
| { |
| super.setClasspath(new Path(getProject(), jarFile.getAbsolutePath())); |
| } |
| } |
| catch (MalformedURLException malformedURLException) |
| { |
| // We shouldn't really get here, but just in case. |
| malformedURLException.printStackTrace(); |
| } |
| catch (ClassNotFoundException classNotFoundException) |
| { |
| throw new BuildException("The class not found in jar file: " + jarFileName, |
| getLocation()); |
| } |
| } |
| else |
| { |
| throw new BuildException("File does not exist: " + jarFileName, getLocation()); |
| } |
| } |
| else |
| { |
| throw new BuildException("FLEX_HOME does not exist.", getLocation()); |
| } |
| } |
| else |
| { |
| throw new BuildException("The class, " + className + |
| ", must be in the classpath or the FLEX_HOME property must be set.", |
| getLocation()); |
| } |
| } |
| |
| return result; |
| } |
| } //End of FlexTask |