Package org.apache.flex.compiler.ant

Source Code of org.apache.flex.compiler.ant.FlexTask

/*
*
*  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 org.apache.flex.compiler.ant;

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;

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.Environment.Variable;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.taskdefs.Java;

import org.apache.flex.compiler.ant.config.ConfigVariable;
import org.apache.flex.compiler.ant.config.NestedAttributeElement;
import org.apache.flex.compiler.ant.config.IOptionSource;
import org.apache.flex.compiler.ant.config.OptionSpec;

/**
* This class contains common data and logic used by all the Flex Ant tasks.
*/
public abstract class FlexTask extends Java
{
    protected static OptionSpec RUNTIME_SHARED_LIBRARY_PATH =
      new OptionSpec("runtime-shared-library-path", "rslp");

    /**
     * Constructor.
     *
     * @param taskName The name of the Ant task.
     * @param configVariables An array of ConfigVariables that will be set by attributes of the task.
     * @param toolJARFileName The build tool's jar file.
     * @param toolClassName The build tool's class name.
     * @param toolMethodName The build tool's method name.
     * @param toolFailureMethodName The build tool's method to determine
     * whether an exit code means failure.
     */
    protected FlexTask(String taskName, ConfigVariable[] configVariables,
                   String toolJARFileName, String toolClassName,
                   String toolMethodName, String toolFailureMethodName)
    {
      this.taskName = taskName;
        this.configVariables = configVariables;
        this.toolJARFileName = toolJARFileName;
        this.toolClassName = toolClassName;
        this.toolMethodName = toolMethodName;
        this.toolFailureMethodName = toolFailureMethodName;

        cmdline = new Commandline();
    }

  /**
   * The name of the Ant task.
   */
  private final String taskName;
 
    /**
     * An array of ConfigVariabes that are set by setDynamicAttribute().
     */
    protected final ConfigVariable[] configVariables;

    /**
     * The build tool's jar file name.
     */
    private final String toolJARFileName;

    /**
     * The build tool's class name.
     */
    private final String toolClassName;

    /**
     * The build tool's entry point.
     * It must be a static method that takes a String[]
     * and returns an int exit code.
     */
    private final String toolMethodName;
   
    /**
     * The build tools' method that determines whether the
     * exit code should make the Ant task fail.
     * It must be a static method that takes an int
     * and returns a boolean.
     */
    private final String toolFailureMethodName;

    /**
     * The commandline used in execute()
     */
    protected final Commandline cmdline;

    protected List<IOptionSource> nestedAttribs;

    /**
     * fork attribute
     */
    protected boolean fork;
   
    private ClassLoader originalContextClassLoader;

    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;
    }

    /*=======================================================================*
     *  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 < configVariables.length && var == null; i++)
        {
            if (configVariables[i].matches(attributeName))
                var = configVariables[i];
        }

        if (var != null)
        {
            var.set(value);
        }
        else
        {
            throw new BuildException("The <" + taskName + "> type doesn't support the \"" +
                                     attributeName + "\" attribute.", getLocation());
        }
    }

    /*=======================================================================*
     *  Dynamic Elements                                                     *
     *=======================================================================*/

    public Object createDynamicElement(String elementName)
    {
        ConfigVariable var = null;

        for (int i = 0; i < configVariables.length && var == null; i++)
        {
            if (configVariables[i].matches(elementName))
                var = configVariables[i];
        }

        if (var != null)
        {
            return createElem(elementName, var.getSpec());
        }
        else
        {
            throw new BuildException("The <" + taskName + "> type doesn't support the \"" +
                                     elementName + "\" nested element.", 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");
   
        String falconHomeProperty = getProject().getProperty("FALCON_HOME");
        if (falconHomeProperty == null)
            throw new BuildException("FALCON_HOME must be set to use the Flex Ant Tasks");
       
        System.setProperty("FLEX_HOME", flexHomeProperty);
        String flexlibProperty = flexHomeProperty.concat("/frameworks/");
    System.setProperty("flexlib", flexlibProperty);

        final Variable variable = new Variable();
        variable.setKey("flexlib");
        variable.setValue(flexHomeProperty);
    addSysproperty(variable);
       
        // This allows the tool to find the default config file.
        cmdline.createArgument().setValue("+flexlib=" + flexlibProperty);
       
        prepareCommandline();

        if (fork)
            executeOutOfProcess();
        else
            executeInProcess();
    }

    /**
     * Executes the task in a separate VM
     */
    private void executeOutOfProcess() throws BuildException
    {
        try
        {
          // Without this, the tool class won't be found by executeJava().
          Class<?> toolClass = resolveClass(toolClassName);
         
            super.setClassname(toolClassName);

            // convert arguments into a string for use by executeJava()
            // also auto-quotes arguments with spaces
            String line = Commandline.toString(cmdline.getArguments());
            super.createArg().setLine(line);

            int exitCode = super.executeJava();

            // Check exit code.
            if (isFatalFailure(toolClass, exitCode))
                throw new BuildException(taskName + " 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);

            log("FlexTask.execute: " + cmdline, Project.MSG_DEBUG);
           
            int exitCode = -1;

            try
            {
                Method toolMethod = toolClass.getMethod(toolMethodName, new Class[] {String[].class});
                Object result = toolMethod.invoke(null, new Object[] {cmdline.getArguments()});
                exitCode = ((Integer)result).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 " + toolMethodName + ": " + e.getMessage(), e);
            }

            if (isFatalFailure(toolClass, exitCode))
                throw new BuildException(taskName + " task failed");//            }
        }
        finally
        {
            if (originalContextClassLoader != null)
                Thread.currentThread().setContextClassLoader(originalContextClassLoader);
        }
    }

    private boolean isFatalFailure(Class<?> toolClass, int exitCode)
    {
      boolean fatal = true;
     
      try
      {
      Method toolFailureMethod = toolClass.getMethod(toolFailureMethodName, new Class[] {int.class});
      Object result = toolFailureMethod.invoke(null, new Object[] {exitCode});
      fatal = ((Boolean)result).booleanValue();
    }
      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 " + toolFailureMethodName + ": " + e.getMessage(), e);
    }
     
      return fatal;
    }

    private Class<?> resolveClass(String className)
    {
        Class<?> result = null;

        try
        {
            result = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
        }
        catch (ClassNotFoundException ignoredClassNotFoundException)
        {
            String flexHomeProperty = getProject().getProperty("FALCON_HOME");

            if (flexHomeProperty != null)
            {
                File flexHome = new File(flexHomeProperty);

                if ( flexHome.exists() )
                {
                    File jarFile = new File(flexHome + "/lib", toolJARFileName);

                    if (jarFile.exists())
                    {
                        try
                        {
                          URL url = jarFile.toURI().toURL();
                            URLClassLoader urlClassLoader = new URLClassLoader(new URL[] {url});
                            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 " + className + " was not found in jar file " + toolJARFileName,
                                                     getLocation());
                        }
                    }
                    else
                    {
                        throw new BuildException("File does not exist: " + toolJARFileName, getLocation());
                    }
                }
                else
                {
                    throw new BuildException("FALCON_HOME does not exist.", getLocation());
                }
            }
            else
            {
                throw new BuildException("The class, " + className +
                                         ", must be in the classpath or the FALCON_HOME property must be set.",
                                         getLocation());
            }
        }

        return result;
    }
}
TOP

Related Classes of org.apache.flex.compiler.ant.FlexTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.