Package org.codehaus.enunciate.modules.amf

Source Code of org.codehaus.enunciate.modules.amf.AMFDeploymentModule

/*
* Copyright 2006-2008 Web Cohesion
*
* 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.codehaus.enunciate.modules.amf;

import flex.messaging.MessageBrokerServlet;
import freemarker.ext.dom.NodeModel;
import freemarker.template.*;
import net.sf.jelly.apt.decorations.JavaDoc;
import net.sf.jelly.apt.freemarker.FreemarkerJavaDoc;
import org.apache.commons.digester.RuleSet;
import org.codehaus.enunciate.EnunciateException;
import org.codehaus.enunciate.apt.EnunciateClasspathListener;
import org.codehaus.enunciate.apt.EnunciateFreemarkerModel;
import org.codehaus.enunciate.config.SchemaInfo;
import org.codehaus.enunciate.config.WsdlInfo;
import org.codehaus.enunciate.contract.HasFacets;
import org.codehaus.enunciate.contract.jaxb.TypeDefinition;
import org.codehaus.enunciate.contract.jaxws.EndpointInterface;
import org.codehaus.enunciate.contract.validation.Validator;
import org.codehaus.enunciate.main.*;
import org.codehaus.enunciate.main.webapp.BaseWebAppFragment;
import org.codehaus.enunciate.main.webapp.WebAppComponent;
import org.codehaus.enunciate.modules.FacetAware;
import org.codehaus.enunciate.modules.FlexHomeAwareModule;
import org.codehaus.enunciate.modules.FreemarkerDeploymentModule;
import org.codehaus.enunciate.modules.ProjectExtensionModule;
import org.codehaus.enunciate.modules.amf.config.AMFRuleSet;
import org.codehaus.enunciate.modules.amf.config.FlexApp;
import org.codehaus.enunciate.modules.amf.config.FlexCompilerConfig;
import org.codehaus.enunciate.modules.amf.config.License;
import org.codehaus.enunciate.template.freemarker.AccessorOverridesAnotherMethod;
import org.codehaus.enunciate.template.freemarker.ClientPackageForMethod;
import org.codehaus.enunciate.template.freemarker.ComponentTypeForMethod;
import org.codehaus.enunciate.template.freemarker.SimpleNameWithParamsMethod;
import org.codehaus.enunciate.util.FacetFilter;
import org.w3c.dom.Document;

import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.net.URL;
import java.util.*;

/**
* <h1>AMF Module</h1>
*
* <p>The AMF deployment module generates the server-side and client-side libraries used to support an
* <a href="http://en.wikipedia.org/wiki/Action_Message_Format">Action Message Format</a> API. The client-side
* library is a set of <a href="http://en.wikipedia.org/wiki/Actionscript">ActionScript</a> classes that are
* type-safe wrappers around the ActionScript remoting API that are designed to add clarity and to be easy
* to consume for Flex development.  Furthermore, the server-side support classes add an extra degree of security to
* your Data Services by ensuring that only your public methods are made available for invocation via AMF. There is
* also support for invoking the <a href="http://en.wikipedia.org/wiki/Adobe_Flex">Adobe Flex</a> compiler to compile
* a set of <a href="http://en.wikipedia.org/wiki/Adobe_Flash">Flash</a> applications that can be added to your
* Enunciate-generated web application.</p>
*
* <p>The AMF API leverages the <a href="http://labs.adobe.com/technologies/blazeds/">Blaze DS</a> package that was recently made
* available as an open source product by Adobe. To use the AMF module, you will have to have the
* <a href="http://www.adobe.com/products/flex/sdk/">Flex SDK</a> installed.</p>
*
* <p>This documentation is an overview of how to use Enunciate to build your Flex Data Services (AMF API) and associated Flash
* application(s). The reader is redirected to the <a href="http://www.adobe.com/products/flex/">documentation for Flex</a> for
* instructions on how to use Flex. There are also two sample applications you may find useful, petclinic and addressbook, that you
* will find bundled with the Enunciate distribution.</p>
*
* <ul>
* <li><a href="#steps">steps</a></li>
* <li><a href="#config">configuration</a></li>
* <li><a href="#artifacts">artifacts</a></li>
* </ul>
*
* <h1><a name="steps">Steps</a></h1>
*
* <h3>generate</h3>
*
* <p>The "generate" step generates all source code for the AMF API. This includes server-side support classes and client-side
* ActionScript classes that can be used to access the API via AMF.</p>
*
* <h3>compile</h3>
*
* <p>During the "compile" step, the AMF module compiles the code that was generated. The generated client-side ActionScript
* classes are compiled into an SWC file that is made available as an Enunciate artifact.  The SWC file can also be made
* available as a download from the deployed web application (see the configuration). It is also during the "compile" step that
* the Flex compiler is invoked on any Flex applications that are specified in the configuration.</p>
*
* <h1><a name="config">Configuration</a></h1>
*
* <p>The AMF module is configured by the "amf" element under the "modules" element of the enunciate configuration file.  <b>The
* AMF module is disabled by default because of the added constraints applied to the service endpoints and because of the additional
* dependencies required by the module.</b>  To enable AMF, be sure to specify <i>disabled="false"</i> on the "amf" element.</p>
*
* <p>The "amf" element supports the following attributes:</p>
*
* <ul>
* <li>The "flexHome" attribute <b>must</b> be supplied. It is the path to the directory where the Flex SDK is installed.</li>
* <li>The "label" attribute is used to determine the name of the client-side artifact files. The default is the Enunciate project label.</li>
* <li>The "swcName" attribute specifies the name of the compiled SWC. By default, the name is determined by the Enunciate
* project label (see the main configuration docs).</li>
* <li>The "swcDownloadable" attribute specifies whether the generated SWC is to be made available as a download from the
* generated web application.  Default: "false".</li>
* <li>The "asSourcesDownloadable" attribute specifies whether the generated ActionScript source files are downloadable from
* generated web application.  Default: "false".</li>
* <li>The "mergeServicesConfigXML" attribute specifies the services-config.xml file that is to be merged into the Enunciate-generated
* services-config.xml file. No file will be merged if none is specified.</li>
* <li>The "enforceNoFieldAccessors" attribute specifies whether to enforce that a field accessor cannot be used for AMF mapping.
* <i>Note: whether this option is enabled or disabled, there currently MUST be a getter and setter for each accessor.  This option only
* disables the compile-time validation check.</i></li>
* </ul>
*
* <h3>The "war" element</h3>
*
* <p>The "war" element under the "amf" element is used to configure the webapp that will host the AMF endpoints and Flex applications. It supports
* the following attributes:</p>
*
* <ul>
* <li>The "amfSubcontext" attribute is the subcontext at which the amf endpoints will be mounted.  Default: "/amf".</li>
* <li>The "flexAppDir" attribute is the directory in the war to which the flex applications will be put.  The default is the root of the war.</li>
* </ul>
*
* <h3>The "compiler" element</h3>
*
* <p>The "compiler" element under the "amf" element is used to configure the compiler that will be used to compile the SWC
* and the Flex applications. It supports the following attributes, associated directly to the Flex compiler options.  For details,
* see the documentation for the Flex compiler.</p>
*
* <ul>
* <li><b>contextRoot</b> (default: the Enunciate project label)</li>
* <li><b>flexConfig</b> (default: "$FLEX_SDK_HOME/frameworks/flex-config.xml")</li>
* <li><b>locale</b> (default: unspecified)</li>
* <li><b>optimize</b> (boolean, default: unspecified)</li>
* <li><b>debug</b> (boolean, default: unspecified)</li>
* <li><b>profile</b> (boolean, default: unspecified)</li>
* <li><b>strict</b> (boolean, default: unspecified)</li>
* <li><b>useNetwork</b> (boolean, default: unspecified)</li>
* <li><b>incremental</b> (boolean, default: unspecified)</li>
* <li><b>warnings</b> (boolean, default: unspecified)</li>
* <li><b>showActionscriptWarnings</b> (boolean, default: unspecified)</li>
* <li><b>showBindingWarnings</b> (boolean, default: unspecified)</li>
* <li><b>showDeprecationWarnings</b> (boolean, default: unspecified)</li>
* <li><b>flexCompileCommand</b> (default "flex2.tools.Compiler")</li>
* <li><b>swcCompileCommand</b> (default "flex2.tools.Compc")</li>
* </ul>
*
* <p>The "compiler" element also supports the following subelements:</p>
*
* <ul>
* <li>"JVMArg" (additional JVM arguments, passed in order to the JVM used to invoke the compiler, supports a single attribute: "value")</li>
* <li>"arg" (additional compiler arguments, passed in order to the compiler)</li>
* <li>"license" (supports attributes "product" and "serialNumber")</li>
* </ul>
*
* <h3>The "app" element</h3>
*
* <p>The AMF module supports the development of Flex apps that can be compiled and packaged with the generated Enunciate app.
* The "app" element supports the folowing attributes:</p>
*
* <ul>
* <li>The "name" attribute is the name of the Flex app.  This attribute is required.</li>
* <li>The "srcDir" attribute specifies the source directory for the application. This attribute is required.</li>
* <li>The "mainMxmlFile" attribute specifies the main mxml file for the app.  This attribute is required. The path to this file is resolved
* relative to the enunciate.xml file (not to the "srcDir" attribute of the app).</li>
* <li>The "outputPath" attribute specified the output directory for the application, relative to the "flexAppDir".</li>
* </ul>
*
* <h3>The "facets" element</h3>
*
* <p>The "facets" element is applicable to the AMF module to configure which facets are to be included/excluded from the AMF artifacts. For
* more information, see <a href="http://docs.codehaus.org/display/ENUNCIATE/Enunciate+API+Facets">API Facets</a></p>
*
* <h3>Example Configuration</h3>
*
* <p>As an example, consider the following configuration:</p>
*
* <code class="console">
* &lt;enunciate&gt;
* &nbsp;&nbsp;&lt;modules&gt;
* &nbsp;&nbsp;&nbsp;&nbsp;&lt;amf disabled="false" swcName="mycompany-amf.swc"
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flexHome="/home/myusername/tools/flex-sdk-2"&gt;
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;app srcDir="src/main/flexapp" name="main" mainMxmlFile="src/main/flexapp/com/mycompany/main.mxml"/&gt;
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;app srcDir="src/main/anotherapp" name="another" mainMxmlFile="src/main/anotherapp/com/mycompany/another.mxml"/&gt;
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;facets&gt;
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/facets&gt;
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
* &nbsp;&nbsp;&nbsp;&nbsp;&lt;/amf&gt;
* &nbsp;&nbsp;&lt;/modules&gt;
* &lt;/enunciate&gt;
* </code>
*
* <p>This configuration enables the AMF module and gives a specific name to the compiled SWC for the client-side ActionScript classes.</p>
*
* <p>There also two Flex applications defined. The first is located at "src/main/flexapp". The name of this app is "main". The MXML
* file that defines this app sits at "src/main/flexapp/com/mycompany/main.mxml", relative to the enunciate configuration file. The
* second application, rooted at "src/main/anotherapp", is named "another". The mxml file that defines this application sits at
* "src/main/anotherapp/com/mycompany/another.mxml".</p>
*
* <p>After the "compile" step of the AMF module, assuming everything compiles correctly, there will be two Flash applications, "main.swf" and "another.swf",
* that sit in the applications directory (see "artifacts" below).</p>
*
* <p>For a less contrived example, see the "petclinic" sample Enunciate project bundled with the Enunciate distribution.</p>
*
* <h1><a name="artifacts">Artifacts</a></h1>
*
* <ul>
* <li>The "amf.client.src.dir" artifact is the directory where the client-side source code is generated.</li>
* <li>The "amf.server.src.dir" artifact is the directory where the server-side source code is generated.</li>
* <li>The "as3.client.swc" artifact is the packaged client-side ActionScript SWC.</li>
* <li>The "flex.app.dir" artifact is the directory to which the Flex apps are compiled.</li>
* </ul>
*
* @author Ryan Heaton
* @docFileName module_amf.html
*/
public class AMFDeploymentModule extends FreemarkerDeploymentModule implements ProjectExtensionModule, FlexHomeAwareModule, EnunciateClasspathListener, FacetAware {

  private String amfSubcontext = "/amf/";
  private String flexAppDir = null;
  private final List<FlexApp> flexApps = new ArrayList<FlexApp>();
  private final AMFRuleSet configurationRules = new AMFRuleSet();

  private String label = null;
  private String flexHome = System.getProperty("flex.home") == null ? System.getenv("FLEX_HOME") : System.getProperty("flex.home");
  private FlexCompilerConfig compilerConfig = new FlexCompilerConfig();
  private String swcName;
  private boolean swcDownloadable = false;
  private boolean asSourcesDownloadable = false;
  private boolean amfRtFound = false;
  private boolean springDIFound = false;
  private boolean enforceNoFieldAccessors = true;
  private String mergeServicesConfigXML;
  private Set<String> facetIncludes = new TreeSet<String>();
  private Set<String> facetExcludes = new TreeSet<String>(Arrays.asList("org.codehaus.enunciate.modules.amf.AMFTransient"));

  /**
   * @return "amf"
   */
  @Override
  public String getName() {
    return "amf";
  }

  @Override
  public void init(Enunciate enunciate) throws EnunciateException {
    super.init(enunciate);

    if (!isDisabled()) {
      if (this.flexHome == null && (isSwcDownloadable() || !flexApps.isEmpty())) {
        throw new EnunciateException("To compile a flex app you must specify the Flex SDK home directory, either in configuration, by setting the FLEX_HOME environment variable, or setting the 'flex.home' system property.");
      }

      for (FlexApp flexApp : flexApps) {
        if (flexApp.getName() == null) {
          throw new EnunciateException("A flex app must have a name.");
        }

        String srcPath = flexApp.getSrcDir();
        if (srcPath == null) {
          throw new EnunciateException("A source directory for the flex app '" + flexApp.getName() + "' must be supplied with the 'srcDir' attribute.");
        }

        File srcDir = enunciate.resolvePath(srcPath);
        if (!srcDir.exists()) {
          throw new EnunciateException("Source directory for the flex app '" + flexApp.getName() + "' doesn't exist.");
        }
      }
    }
  }

  @Override
  public void initModel(EnunciateFreemarkerModel model) {
    super.initModel(model);

    if (!isDisabled()) {
      if (!amfRtFound) {
        warn("WARNING! The AMF module is enabled, but the Enunciate AMF runtime libraries were found on the Enunciate classpath. " +
          "Application startup will fail unless the Enunciate AMF runtime libraries are on the classpath.");
      }
    }
  }

  public void onClassesFound(Set<String> classes) {
    amfRtFound |= classes.contains("org.codehaus.enunciate.modules.amf.AMFEndpointImpl");
    springDIFound |= classes.contains("org.springframework.beans.factory.annotation.Autowired");
  }

  @Override
  public void doFreemarkerGenerate() throws IOException, TemplateException, EnunciateException {
    File serverGenerateDir = getServerSideGenerateDir();
    File clientGenerateDir = getClientSideGenerateDir();
    File xmlGenerateDir = getXMLGenerateDir();

    Enunciate enunciate = getEnunciate();
    if (!enunciate.isUpToDateWithSources(serverGenerateDir) ||
      !enunciate.isUpToDateWithSources(clientGenerateDir) ||
      !enunciate.isUpToDateWithSources(xmlGenerateDir)) {

      //load the references to the templates....
      URL amfEndpointTemplate = getTemplateURL("amf-endpoint.fmt");
      URL amfTypeTemplate = getTemplateURL("amf-type.fmt");
      URL amfTypeMapperTemplate = getTemplateURL("amf-type-mapper.fmt");

      EnunciateFreemarkerModel model = getModel();
      model.setFileOutputDirectory(serverGenerateDir);
      model.put("useSpringDI", this.springDIFound);

      TreeMap<String, String> packages = new TreeMap<String, String>(new Comparator<String>() {
        public int compare(String package1, String package2) {
          int comparison = package1.length() - package2.length();
          if (comparison == 0) {
            return package1.compareTo(package2);
          }
          return comparison;
        }
      });

      for (SchemaInfo schemaInfo : model.getNamespacesToSchemas().values()) {
        for (TypeDefinition typeDefinition : schemaInfo.getTypeDefinitions()) {
          if (!isFacetExcluded(typeDefinition)) {
            String packageName = typeDefinition.getPackage().getQualifiedName();
            packages.put(packageName, packageName + ".amf");
          }
        }
      }

      debug("Generating the AMF externalizable types and their associated mappers...");
      AMFClassnameForMethod amfClassnameForMethod = new AMFClassnameForMethod(packages);
      model.put("simpleNameFor", new SimpleNameWithParamsMethod(amfClassnameForMethod));
      model.put("classnameFor", amfClassnameForMethod);
      for (SchemaInfo schemaInfo : model.getNamespacesToSchemas().values()) {
        for (TypeDefinition typeDefinition : schemaInfo.getTypeDefinitions()) {
          if (!isFacetExcluded(typeDefinition)) {
            model.put("type", typeDefinition);
            processTemplate(amfTypeTemplate, model);
            processTemplate(amfTypeMapperTemplate, model);
          }
        }
      }

      debug("Generating the AMF endpoint beans...");
      for (WsdlInfo wsdlInfo : model.getNamespacesToWSDLs().values()) {
        for (EndpointInterface ei : wsdlInfo.getEndpointInterfaces()) {
          if (!isFacetExcluded(ei)) {
            model.put("endpointInterface", ei);
            processTemplate(amfEndpointTemplate, model);
          }
        }
      }

      URL endpointTemplate = getTemplateURL("as3-endpoint.fmt");
      URL typeTemplate = getTemplateURL("as3-type.fmt");
      URL enumTypeTemplate = getTemplateURL("as3-enum-type.fmt");

      //build up the list of as3Aliases...
      HashMap<String, String> as3Aliases = new HashMap<String, String>();
      for (SchemaInfo schemaInfo : model.getNamespacesToSchemas().values()) {
        for (TypeDefinition typeDefinition : schemaInfo.getTypeDefinitions()) {
          if (!isFacetExcluded(typeDefinition)) {
            as3Aliases.put(amfClassnameForMethod.convert(typeDefinition), typeDefinition.getClientSimpleName());
          }
        }
      }

      model.setFileOutputDirectory(clientGenerateDir);
      HashMap<String, String> conversions = new HashMap<String, String>();
      //todo: accept client-side package mappings?
      ClientPackageForMethod as3PackageFor = new ClientPackageForMethod(conversions);
      as3PackageFor.setUseClientNameConversions(true);
      model.put("packageFor", as3PackageFor);
      AS3UnqualifiedClassnameForMethod as3ClassnameFor = new AS3UnqualifiedClassnameForMethod(conversions);
      as3ClassnameFor.setUseClientNameConversions(true);
      model.put("classnameFor", as3ClassnameFor);
      model.put("simpleNameFor", new SimpleNameWithParamsMethod(as3ClassnameFor));
      ComponentTypeForMethod as3ComponentTypeFor = new ComponentTypeForMethod(conversions);
      as3ComponentTypeFor.setUseClientNameConversions(true);
      model.put("componentTypeFor", as3ComponentTypeFor);
      model.put("amfClassnameFor", amfClassnameForMethod);
      model.put("amfComponentTypeFor", new ComponentTypeForMethod(packages));
      model.put("forEachAS3Import", new ForEachAS3ImportTransform(null, as3ClassnameFor));
      model.put("accessorOverridesAnother", new AccessorOverridesAnotherMethod());
      model.put("as3Aliases", as3Aliases);

      debug("Generating the ActionScript types...");
      for (SchemaInfo schemaInfo : model.getNamespacesToSchemas().values()) {
        for (TypeDefinition typeDefinition : schemaInfo.getTypeDefinitions()) {
          if (!isFacetExcluded(typeDefinition)) {
            model.put("type", typeDefinition);
            URL template = typeDefinition.isEnum() ? enumTypeTemplate : typeTemplate;
            processTemplate(template, model);
          }
        }
      }

      for (WsdlInfo wsdlInfo : model.getNamespacesToWSDLs().values()) {
        for (EndpointInterface ei : wsdlInfo.getEndpointInterfaces()) {
          if (!isFacetExcluded(ei)) {
            model.put("endpointInterface", ei);
            processTemplate(endpointTemplate, model);
          }
        }
      }

      File servicesConfigXML = new File(xmlGenerateDir, "services-config.xml");
      URL servicesConfigTemplate = getTemplateURL("services-config-xml.fmt");

      model.setFileOutputDirectory(xmlGenerateDir);
      debug("Generating the configuration files.");
      processTemplate(servicesConfigTemplate, model);

      File mergeTarget = new File(xmlGenerateDir, "merged-services-config.xml");
      if (this.mergeServicesConfigXML != null) {
        URL servicesConfigXmlToMerge = enunciate.resolvePath(this.mergeServicesConfigXML).toURL();

        try {
          model.put("source1", loadMergeXmlModel(servicesConfigXmlToMerge.openStream()));
          model.put("source2", loadMergeXmlModel(new FileInputStream(servicesConfigXML)));
          processTemplate(getMergeServicesConfigXmlTemplateURL(), model);
        }
        catch (TemplateException e) {
          throw new EnunciateException("Error while merging services-config xml files.", e);
        }

        debug("Merged %s and %s into %s...", servicesConfigXmlToMerge, servicesConfigXML, mergeTarget);
      }
      else {
        enunciate.copyFile(servicesConfigXML, mergeTarget);
      }
     
      if (!mergeTarget.exists()) {
          throw new EnunciateException("Error: " + mergeTarget + " doesn't exist.");
        }
    }
    else {
      info("Skipping generation of AMF support as everything appears up-to-date...");
    }

    this.enunciate.addArtifact(new FileArtifact(getName(), "amf.client.src.dir", clientGenerateDir));
    this.enunciate.addArtifact(new FileArtifact(getName(), "amf.server.src.dir", serverGenerateDir));

    this.enunciate.addAdditionalSourceRoot(serverGenerateDir);
  }
 
  /**
   * Loads the node model for merging xml.
   *
   * @param inputStream The input stream of the xml.
   * @return The node model.
   */
  protected NodeModel loadMergeXmlModel(InputStream inputStream) throws EnunciateException {
    try {
      DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
      builderFactory.setNamespaceAware(false); //no namespace for the merging...
      Document doc = builderFactory.newDocumentBuilder().parse(inputStream);
      NodeModel.simplify(doc);
      return NodeModel.wrap(doc.getDocumentElement());
    }
    catch (Exception e) {
      throw new EnunciateException("Error parsing web.xml file for merging", e);
    }
  }

  /**
   * Invokes the flex compiler on the apps specified in the configuration file.
   */
  protected void doFlexCompile() throws EnunciateException, IOException {
    File swcFile = null;
    File asSources = null;
    Enunciate enunciate = getEnunciate();
    if (isSwcDownloadable() || !flexApps.isEmpty()) {
      if (this.flexHome == null) {
        throw new EnunciateException("To compile a flex app you must specify the Flex SDK home directory, either in configuration, by setting the FLEX_HOME environment variable, or setting the 'flex.home' system property.");
      }

      File flexHomeDir = new File(this.flexHome);
      if (!flexHomeDir.exists()) {
        throw new EnunciateException("Flex home not found ('" + flexHomeDir.getAbsolutePath() + "').");
      }

      File javaBinDir = new File(System.getProperty("java.home"), "bin");
      File javaExecutable = new File(javaBinDir, "java");
      if (!javaExecutable.exists()) {
        //append the "exe" for windows users.
        javaExecutable = new File(javaBinDir, "java.exe");
      }

      String javaCommand = javaExecutable.getAbsolutePath();
      if (!javaExecutable.exists()) {
        warn("No java executable found in %s.  We'll just hope the environment is set up to execute 'java'...", javaBinDir.getAbsolutePath());
        javaCommand = "java";
      }

      int compileCommandIndex;
      int outputFileIndex;
      int sourcePathIndex;
      int mainMxmlPathIndex;
      List<String> commandLine = new ArrayList<String>();
      int argIndex = 0;
      commandLine.add(argIndex++, javaCommand);
      for (String jvmarg : this.compilerConfig.getJVMArgs()) {
        commandLine.add(argIndex++, jvmarg);
      }
      commandLine.add(argIndex++, "-cp");
      File flexHomeLib = new File(flexHomeDir, "lib");
      if (!flexHomeLib.exists()) {
        throw new EnunciateException("File not found: " + flexHomeLib);
      }
      else {
        StringBuilder builder = new StringBuilder();
        Iterator<File> flexLibIt = Arrays.asList(flexHomeLib.listFiles()).iterator();
        while (flexLibIt.hasNext()) {
          File flexJar = flexLibIt.next();
          if (flexJar.getAbsolutePath().endsWith("jar")) {
            builder.append(flexJar.getAbsolutePath());
            if (flexLibIt.hasNext()) {
              builder.append(File.pathSeparatorChar);
            }
          }
          else {
            debug("File %s will not be included on the classpath because it's not a jar.", flexJar);
          }
        }
        commandLine.add(argIndex++, builder.toString());
      }

      compileCommandIndex = argIndex;
      commandLine.add(argIndex++, null);

      commandLine.add(argIndex++, "-output");
      outputFileIndex = argIndex;
      commandLine.add(argIndex++, null);

      if (compilerConfig.getFlexConfig() == null) {
        compilerConfig.setFlexConfig(new File(new File(flexHome, "frameworks"), "flex-config.xml"));
      }

      if (compilerConfig.getFlexConfig().exists()) {
        commandLine.add(argIndex++, "-load-config");
        commandLine.add(argIndex++, compilerConfig.getFlexConfig().getAbsolutePath());
      }
      else {
        warn("Configured flex configuration file %s doesn't exist.  Ignoring...", compilerConfig.getFlexConfig());
      }

      if (compilerConfig.getContextRoot() == null) {
        if (getEnunciate().getConfig().getLabel() != null) {
          compilerConfig.setContextRoot("/" + getEnunciate().getConfig().getLabel());
        }
        else {
          compilerConfig.setContextRoot("/enunciate");
        }
      }

      commandLine.add(argIndex++, "-compiler.context-root");
      commandLine.add(argIndex++, compilerConfig.getContextRoot());

      if (compilerConfig.getLocale() != null) {
        commandLine.add(argIndex++, "-compiler.locale");
        commandLine.add(argIndex++, compilerConfig.getLocale());
      }

      if (compilerConfig.getLicenses().size() > 0) {
        commandLine.add(argIndex++, "-licenses.license");
        for (License license : compilerConfig.getLicenses()) {
          commandLine.add(argIndex++, license.getProduct());
          commandLine.add(argIndex++, license.getSerialNumber());
        }
      }

      if (compilerConfig.getOptimize() != null && compilerConfig.getOptimize()) {
        commandLine.add(argIndex++, "-compiler.optimize");
      }

      if (compilerConfig.getDebug() != null && compilerConfig.getDebug()) {
        commandLine.add(argIndex++, "-compiler.debug=true");
      }

      if (compilerConfig.getStrict() != null && compilerConfig.getStrict()) {
        commandLine.add(argIndex++, "-compiler.strict");
      }

      if (compilerConfig.getUseNetwork() != null && compilerConfig.getUseNetwork()) {
        commandLine.add(argIndex++, "-use-network");
      }

      if (compilerConfig.getIncremental() != null && compilerConfig.getIncremental()) {
        commandLine.add(argIndex++, "-compiler.incremental");
      }

      if (compilerConfig.getShowActionscriptWarnings() != null && compilerConfig.getShowActionscriptWarnings()) {
        commandLine.add(argIndex++, "-show-actionscript-warnings");
      }

      if (compilerConfig.getShowBindingWarnings() != null && compilerConfig.getShowBindingWarnings()) {
        commandLine.add(argIndex++, "-show-binding-warnings");
      }

      if (compilerConfig.getShowDeprecationWarnings() != null && compilerConfig.getShowDeprecationWarnings()) {
        commandLine.add(argIndex++, "-show-deprecation-warnings");
      }

      for (String arg : this.compilerConfig.getArgs()) {
        commandLine.add(argIndex++, arg);
      }

      commandLine.add(argIndex++, "-compiler.services");
      File xmlGenerateDir = getXMLGenerateDir();
      commandLine.add(argIndex++, new File(xmlGenerateDir, "merged-services-config.xml").getAbsolutePath());

      commandLine.add(argIndex, "-include-sources");
      File clientSideGenerateDir = getClientSideGenerateDir();
      commandLine.add(argIndex + 1, clientSideGenerateDir.getAbsolutePath());

      String swcName = getSwcName();

      if (swcName == null) {
        String label = "enunciate";
        if (getLabel() != null) {
          label = getLabel();
        }
        else if ((enunciate.getConfig() != null) && (enunciate.getConfig().getLabel() != null)) {
          label = enunciate.getConfig().getLabel();
        }

        swcName = label + "-as3-client.swc";
      }

      File swcCompileDir = getSwcCompileDir();
      swcFile = new File(swcCompileDir, swcName);
      boolean swcUpToDate = swcFile.exists() &&
        enunciate.isUpToDate(xmlGenerateDir, swcCompileDir) &&
        enunciate.isUpToDate(clientSideGenerateDir, swcCompileDir);

      if (!swcUpToDate) {
        commandLine.set(compileCommandIndex, compilerConfig.getSwcCompileCommand());
        commandLine.set(outputFileIndex, swcFile.getAbsolutePath());
        debug("Compiling %s for the client-side ActionScript classes...", swcFile.getAbsolutePath());
        if (enunciate.isDebug()) {
          StringBuilder command = new StringBuilder();
          for (String commandPiece : commandLine) {
            command.append(' ').append(commandPiece);
          }
          debug("Executing SWC compile for client-side actionscript with the command: %s", command);
        }
        compileSwc(commandLine);
      }
      else {
        info("Skipping compilation of %s as everything appears up-to-date...", swcFile.getAbsolutePath());
      }

      //swc is compiled
      while (commandLine.size() > argIndex) {
        //remove the compc-specific options...
        commandLine.remove(argIndex);
      }

      if (compilerConfig.getProfile() != null && compilerConfig.getProfile()) {
        commandLine.add(argIndex++, "-compiler.profile");
      }

      if (compilerConfig.getWarnings() != null && compilerConfig.getWarnings()) {
        commandLine.add(argIndex++, "-warnings");
      }

      commandLine.add(argIndex++, "-source-path");
      commandLine.add(argIndex++, clientSideGenerateDir.getAbsolutePath());

      commandLine.add(argIndex++, "-source-path");
      sourcePathIndex = argIndex;
      commandLine.add(argIndex++, null);

      commandLine.add(argIndex++, "--");
      mainMxmlPathIndex = argIndex;
      commandLine.add(argIndex++, null);

      commandLine.set(compileCommandIndex, compilerConfig.getFlexCompileCommand());

      File outputDirectory = getSwfCompileDir();
      debug("Creating output directory: " + outputDirectory);
      outputDirectory.mkdirs();

      for (FlexApp flexApp : flexApps) {
        String mainMxmlPath = flexApp.getMainMxmlFile();
        if (mainMxmlPath == null) {
          throw new EnunciateException("A main MXML file for the flex app '" + flexApp.getName() + "' must be supplied with the 'mainMxmlFile' attribute.");
        }

        File mainMxmlFile = enunciate.resolvePath(mainMxmlPath);
        if (!mainMxmlFile.exists()) {
          throw new EnunciateException("Main MXML file for the flex app '" + flexApp.getName() + "' doesn't exist.");
        }

        File swfDir = outputDirectory;
        if (flexApp.getOutputPath() != null && !"".equals(flexApp.getOutputPath())) {
          swfDir = new File(outputDirectory, flexApp.getOutputPath());
          swfDir.mkdirs();
        }
        File swfFile = new File(swfDir, flexApp.getName() + ".swf");
        File appSrcDir = enunciate.resolvePath(flexApp.getSrcDir());
        String swfFilePath = swfFile.getAbsolutePath();

        boolean swfUpToDate = swfFile.exists()
          && mainMxmlFile.lastModified() < swfFile.lastModified()
          && enunciate.isUpToDate(appSrcDir, swfFile);

        if (!swfUpToDate) {
          commandLine.set(outputFileIndex, swfFilePath);
          commandLine.set(mainMxmlPathIndex, mainMxmlFile.getAbsolutePath());
          commandLine.set(sourcePathIndex, appSrcDir.getAbsolutePath());

          debug("Compiling %s ...", swfFilePath);
          if (enunciate.isDebug()) {
            StringBuilder command = new StringBuilder();
            for (String commandPiece : commandLine) {
              command.append(' ').append(commandPiece);
            }
            debug("Executing flex compile for module %s with the command: %s", flexApp.getName(), command);
          }

          ProcessBuilder processBuilder = new ProcessBuilder(commandLine.toArray(new String[commandLine.size()]));
          processBuilder.directory(getSwfCompileDir());
          processBuilder.redirectErrorStream(true);
          Process process = processBuilder.start();
          BufferedReader procReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
          String line = procReader.readLine();
          while (line != null) {
            info(line);
            line = procReader.readLine();
          }
          int procCode;
          try {
            procCode = process.waitFor();
          }
          catch (InterruptedException e1) {
            throw new EnunciateException("Unexpected inturruption of the Flex compile process.");
          }

          if (procCode != 0) {
            throw new EnunciateException("Flex compile failed for module " + flexApp.getName());
          }
        }
        else {
          info("Skipping compilation of %s as everything appears up-to-date...", swfFilePath);
        }
      }
    }

    if (isAsSourcesDownloadable()) {
      String label = "enunciate";
      if ((enunciate.getConfig() != null) && (enunciate.getConfig().getLabel() != null)) {
        label = enunciate.getConfig().getLabel();
      }

      asSources = new File(new File(getCompileDir(), "src"), label + "-as3-sources.zip");
      enunciate.zip(asSources, getClientSideGenerateDir());
    }

    if (swcFile != null || asSources != null) {
      List<ArtifactDependency> clientDeps = new ArrayList<ArtifactDependency>();
      BaseArtifactDependency as3Dependency = new BaseArtifactDependency();
      as3Dependency.setId("flex-sdk");
      as3Dependency.setArtifactType("zip");
      as3Dependency.setDescription("The flex SDK.");
      as3Dependency.setURL("http://www.adobe.com/products/flex/");
      as3Dependency.setVersion("2.0.1");
      clientDeps.add(as3Dependency);

      ClientLibraryArtifact as3ClientArtifact = new ClientLibraryArtifact(getName(), "as3.client.library", "ActionScript 3 Client Library");
      as3ClientArtifact.setPlatform("Adobe Flex");
      //read in the description from file:
      as3ClientArtifact.setDescription(readResource("library_description.fmt"));
      as3ClientArtifact.setDependencies(clientDeps);

      if (swcFile != null) {
        NamedFileArtifact clientArtifact = new NamedFileArtifact(getName(), "as3.client.swc", swcFile);
        clientArtifact.setDescription("The compiled SWC.");
        clientArtifact.setPublic(false);
        clientArtifact.setArtifactType(ArtifactType.binaries);
        as3ClientArtifact.addArtifact(clientArtifact);
        enunciate.addArtifact(clientArtifact);
      }

      if (asSources != null) {
        NamedFileArtifact clientArtifact = new NamedFileArtifact(getName(), "as3.client.sources", asSources);
        clientArtifact.setDescription("The client-side ActionScript sources.");
        clientArtifact.setPublic(false);
        clientArtifact.setArtifactType(ArtifactType.sources);
        as3ClientArtifact.addArtifact(clientArtifact);
        enunciate.addArtifact(clientArtifact);
      }

      enunciate.addArtifact(as3ClientArtifact);
    }
  }

  /**
   * Compiles the SWC.
   *
   * @param commandLine The command line.
   */
  protected void compileSwc(List<String> commandLine) throws IOException, EnunciateException {
    getSwcCompileDir().mkdirs();
    Process process = new ProcessBuilder(commandLine).directory(getSwcCompileDir()).redirectErrorStream(true).start();
    BufferedReader procReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    String line = procReader.readLine();
    while (line != null) {
      info(line);
      line = procReader.readLine();
    }
    int procCode;
    try {
      procCode = process.waitFor();
    }
    catch (InterruptedException e1) {
      throw new EnunciateException("Unexpected inturruption of the Flex compile process.");
    }

    if (procCode != 0) {
      throw new EnunciateException("SWC compile failed.");
    }
  }

  @Override
  protected void doCompile() throws EnunciateException, IOException {
    Enunciate enunciate = getEnunciate();

    if (isSwcDownloadable() || this.flexApps.size() > 0 || isAsSourcesDownloadable()) {
      doFlexCompile();
      if (this.flexApps.size() > 0) {
        enunciate.addArtifact(new FileArtifact(getName(), "flex.app.dir", getSwfCompileDir()));
      }
    }
  }

  @Override
  protected void doBuild() throws EnunciateException, IOException {
    //assemble the server-side webapp fragment
    BaseWebAppFragment webAppFragment = new BaseWebAppFragment(getName());

    //base webapp dir...
    File webappDir = new File(getBuildDir(), "webapp");
    webappDir.mkdirs();
    File servicesConfigFile = new File(getXMLGenerateDir(), "merged-services-config.xml");
    if (servicesConfigFile.exists()) {
      getEnunciate().copyFile(servicesConfigFile, new File(new File(new File(webappDir, "WEB-INF"), "flex"), "services-config.xml"));
    }
    else {
      throw new FileNotFoundException("File not found: " + servicesConfigFile.getAbsolutePath());
    }

    File swfCompileDir = getSwfCompileDir();
    if ((this.flexApps.size() > 0) && (swfCompileDir != null) && (swfCompileDir.exists())) {
      File flexAppDir = webappDir;
      if ((getFlexAppDir() != null) && (!"".equals(getFlexAppDir()))) {
        debug("Flex applications will be put into the %s subdirectory of the web application.", getFlexAppDir());
        flexAppDir = new File(webappDir, getFlexAppDir());
      }
      getEnunciate().copyDir(swfCompileDir, flexAppDir);
    }
    else {
      debug("No flex apps were found.");
    }
    webAppFragment.setBaseDir(webappDir);

    //servlets.
    WebAppComponent messageServlet = new WebAppComponent();
    messageServlet.setClassname(MessageBrokerServlet.class.getName());
    messageServlet.setName("AMFMessageServlet");
    TreeSet<String> urlMappings = new TreeSet<String>();
    for (WsdlInfo wsdlInfo : getModel().getNamespacesToWSDLs().values()) {
      for (EndpointInterface ei : wsdlInfo.getEndpointInterfaces()) {
        urlMappings.add(getAmfSubcontext() + ei.getServiceName());
      }
    }
    messageServlet.setUrlMappings(urlMappings);
    TreeMap<String, String> initParams = new TreeMap<String, String>();
    initParams.put("services.configuration.file", "/WEB-INF/flex/services-config.xml");
    initParams.put("flex.write.path", "/WEB-INF/flex");
    messageServlet.setInitParams(initParams);
    webAppFragment.setServlets(Arrays.asList(messageServlet));

    getEnunciate().addWebAppFragment(webAppFragment);
  }

  /**
   * Reads a resource into string form.
   *
   * @param resource The resource to read.
   * @return The string form of the resource.
   */
  protected String readResource(String resource) throws IOException, EnunciateException {
    HashMap<String, Object> model = new HashMap<String, Object>();
    model.put("sample_service_method", getModelInternal().findExampleWebMethod());
    model.put("sample_resource", getModelInternal().findExampleResourceMethod());

    URL res = AMFDeploymentModule.class.getResource(resource);
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    PrintStream out = new PrintStream(bytes);
    try {
      processTemplate(res, model, out);
      out.flush();
      bytes.flush();
      return bytes.toString("utf-8");
    }
    catch (TemplateException e) {
      throw new EnunciateException(e);
    }
  }

  /**
   * Whether the given type declaration is AMF-transient.
   *
   * @param declaration The type declaration.
   * @return Whether the given tyep declaration is AMF-transient.
   */
  protected boolean isFacetExcluded(HasFacets declaration) {
    return !FacetFilter.accept(declaration);
  }

  /**
   * Get a template URL for the template of the given name.
   *
   * @param template The specified template.
   * @return The URL to the specified template.
   */
  protected URL getTemplateURL(String template) {
    return AMFDeploymentModule.class.getResource(template);
  }

  /**
   * Get the generate directory for server-side AMF classes.
   *
   * @return The generate directory for server-side AMF classes.
   */
  public File getServerSideGenerateDir() {
    return new File(getGenerateDir(), "server");
  }

  /**
   * Get the generate directory for client-side AMF classes.
   *
   * @return The generate directory for client-side AMF classes.
   */
  public File getClientSideGenerateDir() {
    return new File(getGenerateDir(), "client");
  }

  /**
   * Get the generate directory for XML configuration.
   *
   * @return The generate directory for the XML configuration.
   */
  public File getXMLGenerateDir() {
    return new File(getGenerateDir(), "xml");
  }

  /**
   * The directory for the destination for the SWC.
   *
   * @return The directory for the destination for the SWC.
   */
  public File getSwcCompileDir() {
    return new File(getCompileDir(), "swc");
  }

  /**
   * The directory for the destination for the SWF.
   *
   * @return The directory for the destination for the SWF.
   */
  public File getSwfCompileDir() {
    return new File(getCompileDir(), "swf");
  }

  /**
   * AMF configuration rule set.
   *
   * @return AMF configuration rule set.
   */
  @Override
  public RuleSet getConfigurationRules() {
    return this.configurationRules;
  }

  /**
   * AMF validator.
   *
   * @return AMF validator.
   */
  @Override
  public Validator getValidator() {
    return new AMFValidator( this.enforceNoFieldAccessors );
  }

  @Override
  protected ObjectWrapper getObjectWrapper() {
    return new DefaultObjectWrapper() {
      @Override
      public TemplateModel wrap(Object obj) throws TemplateModelException {
        if (obj instanceof JavaDoc) {
          return new FreemarkerJavaDoc((JavaDoc) obj);
        }

        return super.wrap(obj);
      }
    };
  }

  /**
   * The amf home directory
   *
   * @return The amf home directory
   */
  public String getFlexHome() {
    return flexHome;
  }

  /**
   * Set the path to the AMF home directory.
   *
   * @param flexHome The amf home directory
   */
  public void setFlexHome(String flexHome) {
    this.flexHome = flexHome;
  }

  /**
   * The amf apps to compile.
   *
   * @return The amf apps to compile.
   */
  public List<FlexApp> getFlexApps() {
    return flexApps;
  }

  /**
   * Adds a flex app to be compiled.
   *
   * @param flexApp The flex app to be compiled.
   */
  public void addFlexApp(FlexApp flexApp) {
    this.flexApps.add(flexApp);
  }

  /**
   * The compiler configuration.
   *
   * @return The compiler configuration.
   */
  public FlexCompilerConfig getCompilerConfig() {
    return compilerConfig;
  }

  /**
   * The compiler configuration.
   *
   * @param compilerConfig The compiler configuration.
   */
  public void setCompilerConfig(FlexCompilerConfig compilerConfig) {
    this.compilerConfig = compilerConfig;
  }
 
  /**
   * @return The URL to "web.xml.fmt"
   */
  protected URL getMergeServicesConfigXmlTemplateURL() {
    return this.getClass().getResource("merge-services-config-xml.fmt");
  }

  /**
   * The name of the swc file.
   *
   * @return The name of the swc file.
   */
  public String getSwcName() {
    return swcName;
  }

  /**
   * The name of the swc file.
   *
   * @param swcName The name of the swc file.
   */
  public void setSwcName(String swcName) {
    this.swcName = swcName;
  }

  /**
   * Whether the swc is downloadable.
   *
   * @return Whether the swc is downloadable.
   */
  public boolean isSwcDownloadable() {
    return swcDownloadable;
  }

  /**
   * Whether the swc is downloadable.
   *
   * @param swcDownloadable Whether the swc is downloadable.
   */
  public void setSwcDownloadable(boolean swcDownloadable) {
    this.swcDownloadable = swcDownloadable;
  }

  /**
   * Whether the generated ActionScript sources are downloadable.
   *
   * @return Whether the generated ActionScript sources are downloadable.
   */
  public boolean isAsSourcesDownloadable() {
    return asSourcesDownloadable;
  }

  /**
   * Whether the generated ActionScript sources are downloadable.
   *
   * @param asSourcesDownloadable Whether the generated ActionScript sources are downloadable.
   */
  public void setAsSourcesDownloadable(boolean asSourcesDownloadable) {
    this.asSourcesDownloadable = asSourcesDownloadable;
  }
 
  /**
   * The services-config.xml file that is to be merged into the Enunciate-generated
   * services-config.xml file.
   *
   * @return the services-config.xml file that is to be merged into the Enunciate-generated
   * services-config.xml file.
   */
  public String getMergeServicesConfigXML() {
      return this.mergeServicesConfigXML;
  }
 
  /**
   * Specifies the services-config.xml file that is to be merged into the Enunciate-generated
   * services-config.xml file.
   *
   * @param mergeServicesConfigXML the services-config.xml file that is to be merged into the
   * Enunciate-generated services-config.xml file.
   */
  public void setMergeServicesConfigXML(String mergeServicesConfigXML) {
      this.mergeServicesConfigXML = mergeServicesConfigXML;
  }

  /**
   * The amf subcontext.
   *
   * @return The amf subcontext.
   */
  public String getAmfSubcontext() {
    return amfSubcontext;
  }

  /**
   * The amf subcontext.
   *
   * @param amfSubcontext The amf subcontext.
   */
  public void setAmfSubcontext(String amfSubcontext) {
    if (amfSubcontext == null) {
      throw new IllegalArgumentException("The AMF context must not be null.");
    }

    if ("".equals(amfSubcontext)) {
      throw new IllegalArgumentException("The AMF context must not be the emtpy string.");
    }

    if (!amfSubcontext.startsWith("/")) {
      amfSubcontext = "/" + amfSubcontext;
    }

    if (!amfSubcontext.endsWith("/")) {
      amfSubcontext = amfSubcontext + "/";
    }

    this.amfSubcontext = amfSubcontext;
  }

  /**
   * The flex app dir.
   *
   * @return The flex app dir.
   */
  public String getFlexAppDir() {
    return flexAppDir;
  }

  /**
   * The flex app dir.
   *
   * @param flexAppDir The flex app dir.
   */
  public void setFlexAppDir(String flexAppDir) {
    this.flexAppDir = flexAppDir;
  }

  /**
   * The label for the ActionScript API.
   *
   * @return The label for the ActionScript API.
   */
  public String getLabel() {
    return label;
  }

  /**
   * The label for the ActionScript API.
   *
   * @param label The label for the ActionScript API.
   */
  public void setLabel(String label) {
    this.label = label;
  }

  /**
   * The set of facets to include.
   *
   * @return The set of facets to include.
   */
  public Set<String> getFacetIncludes() {
    return facetIncludes;
  }

  /**
   * Add a facet include.
   *
   * @param name The name.
   */
  public void addFacetInclude(String name) {
    if (name != null) {
      this.facetIncludes.add(name);
    }
  }

  /**
   * The set of facets to exclude.
   *
   * @return The set of facets to exclude.
   */
  public Set<String> getFacetExcludes() {
    return facetExcludes;
  }

  /**
   * Add a facet exclude.
   *
   * @param name The name.
   */
  public void addFacetExclude(String name) {
    if (name != null) {
      this.facetExcludes.add(name);
    }
  }

  // Inherited.
  @Override
  public boolean isDisabled() {
    if (super.isDisabled()) {
      return true;
    }
    else if (getModelInternal() != null && getModelInternal().getNamespacesToWSDLs().isEmpty() && getModelInternal().getNamespacesToSchemas().isEmpty()) {
      debug("AMF module is disabled because there are no endpoint interfaces nor any schema objects.");
      return true;
    }

    return false;
  }

  public List<File> getProjectSources() {
    List<File> sources = new ArrayList<File>(Arrays.asList(getClientSideGenerateDir(), getServerSideGenerateDir()));
    for (FlexApp flexApp : getFlexApps()) {
      sources.add(getEnunciate().resolvePath(flexApp.getSrcDir()));
    }
    return sources;
  }

  public List<File> getProjectTestSources() {
    return Collections.emptyList();
  }

  public List<File> getProjectResourceDirectories() {
    return Collections.emptyList();
  }

  public List<File> getProjectTestResourceDirectories() {
    return Collections.emptyList();
  }

  /**
   * Whether to enforce that field accessors can't be used.
   *
   * @return Whether to enforce that field accessors can't be used.
   */
  public boolean isEnforceNoFieldAccessors() {
    return enforceNoFieldAccessors;
  }

  /**
   * Whether to enforce that field accessors can't be used.
   *
   * @param enforceNoFieldAccessors Whether to enforce that field accessors can't be used.
   */
  public void setEnforceNoFieldAccessors(boolean enforceNoFieldAccessors) {
    this.enforceNoFieldAccessors = enforceNoFieldAccessors;
  }


}
TOP

Related Classes of org.codehaus.enunciate.modules.amf.AMFDeploymentModule

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.