blob: 55d23ffbb11a0ce186ca34c3951d432eef8990ca [file] [log] [blame]
/*
*
* 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.config;
import java.io.File;
import java.util.*;
import org.apache.flex.compiler.clients.MXMLC;
import org.apache.flex.compiler.common.IPathResolver;
import org.apache.flex.compiler.common.VersionInfo;
import org.apache.flex.compiler.config.RSLSettings.RSLAndPolicyFileURLPair;
import org.apache.flex.compiler.exceptions.ConfigurationException;
import org.apache.flex.compiler.filespecs.FileSpecification;
import org.apache.flex.compiler.filespecs.IFileSpecification;
import org.apache.flex.compiler.internal.config.CompilerProblemSettings;
import org.apache.flex.compiler.internal.config.DefaultsConfigurator;
import org.apache.flex.compiler.internal.config.FileConfigurator;
import org.apache.flex.compiler.internal.config.ICompilerSettings;
import org.apache.flex.compiler.internal.config.IConfigurator;
import org.apache.flex.compiler.internal.config.RuntimeSharedLibraryPathInfo;
import org.apache.flex.compiler.internal.config.SystemPropertyConfigurator;
import org.apache.flex.compiler.internal.config.TargetSettings;
import org.apache.flex.compiler.internal.config.localization.LocalizationManager;
import org.apache.flex.compiler.internal.config.localization.ResourceBundleLocalizer;
import org.apache.flex.compiler.internal.projects.FlexProject;
import org.apache.flex.compiler.internal.projects.FlexProjectConfigurator;
import org.apache.flex.compiler.internal.projects.SourcePathManager;
import org.apache.flex.compiler.internal.workspaces.Workspace;
import org.apache.flex.compiler.mxml.IMXMLNamespaceMapping;
import org.apache.flex.compiler.problems.ANELibraryNotAllowedProblem;
import org.apache.flex.compiler.problems.ConfigurationProblem;
import org.apache.flex.compiler.problems.ICompilerProblem;
import org.apache.flex.compiler.projects.IFlexProject;
import org.apache.flex.compiler.targets.ITargetSettings;
import org.apache.flex.compiler.targets.ITarget.TargetType;
import org.apache.flex.compiler.workspaces.IWorkspace;
import org.apache.flex.swc.ISWC;
import org.apache.flex.utils.FileUtils;
import org.apache.flex.utils.FilenameNormalization;
import org.apache.flex.utils.Trace;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
/**
* A class that allows a client change compiler settings and to
* configure projects and targets from those settings.
*/
public class Configurator implements ICompilerSettings, IConfigurator, ICompilerSettingsConstants, Cloneable
{
/**
* Marker class for RSLSettings because RSLSettings need special handling
* in getOptions().
*/
static class RSLSettingsList extends ArrayList<RSLSettings>
{
public RSLSettingsList(int size)
{
super(size);
}
public RSLSettingsList(Collection<? extends RSLSettings> c)
{
super(c);
}
private static final long serialVersionUID = 0L;
}
/**
* Ditto for conditional compilation
*/
static class CompilerDefinitionMap extends TreeMap<String, String>
{
private static final long serialVersionUID = 0L;
}
static class ApplicationDomainsList extends ArrayList<String[]>
{
private static final long serialVersionUID = 0L;
}
static class MXMLNamespaceMappingList extends ArrayList<IMXMLNamespaceMapping>
{
public MXMLNamespaceMappingList(int size)
{
super(size);
}
public MXMLNamespaceMappingList(Collection<? extends IMXMLNamespaceMapping> namespaceMappings)
{
super(namespaceMappings);
}
private static final long serialVersionUID = 0L;
}
static class ServicesContextRoot
{
public ServicesContextRoot(String path, String contextRoot)
{
this.path = path;
this.contextRoot = contextRoot;
}
public String path;
public String contextRoot;
}
/**
* Ditto for conditional compilation
*/
static class FrameLabelMap extends TreeMap<String, List<String>>
{
private static final long serialVersionUID = 0L;
}
/**
* Convert file path strings to {@code File} objects. Null values are
* discarded.
*
* @param paths List of file paths
* @return List of File objects. No null values will be returned.
*/
public static List<File> toFiles(final List<String> paths)
{
final List<File> result = new ArrayList<File>();
for (final String path : paths)
{
if (path != null)
result.add(new File(path));
}
return result;
}
/**
* Convert file path strings to {@code File} objects. Null values are
* discarded.
*
* @param paths List of file paths
* @return Array of File objects. No null values will be returned.
*/
public static List<File> toFileList(final List<String> paths)
{
final List<File> result = new ArrayList<File>();
for (final String path : paths)
{
if (path != null)
result.add(FilenameNormalization.normalize(new File(path)));
}
return result;
}
/**
* Convert {@code File} objects to {@code String}, where each {@code String} is
* the absolute file path of the file. Null values are discarded.
*
* @param files file specifications
* @return Array of File objects. No null values will be returned.
*/
public static String[] toPaths(File[] files)
{
final List<String> result = new ArrayList<String>();
for (final File file : files)
{
if (file != null)
result.add(file.getAbsolutePath());
}
return result.toArray(new String[0]);
}
/**
* Resolve a list of normalized paths to {@link IFileSpecification} objects
* from the given {@code workspace}.
*
* @param paths A list of normalized paths.
* @param workspace Workspace.
* @return A list of file specifications.
*/
public static List<IFileSpecification> toFileSpecifications(
final List<String> paths,
final Workspace workspace)
{
return Lists.transform(paths, new Function<String, IFileSpecification>()
{
@Override
public IFileSpecification apply(final String path)
{
return workspace.getFileSpecification(path);
}
});
}
// Used to generate the command line
private static final String EQUALS_STRING = "=";
private static final String PLUS_EQUALS_STRING = "+=";
private static final String COMMA_STRING = ",";
private static final String PLUS_STRING = "+";
private static final Set<String> excludes = new HashSet<String>();
static
{
excludes.add("output");
excludes.add("warnings");
excludes.add("compiler.debug");
excludes.add("compiler.profile");
excludes.add("compiler.accessible");
excludes.add("compiler.strict");
excludes.add("compiler.show-actionscript-warnings");
excludes.add("compiler.show-unused-type-selector-warnings");
excludes.add("compiler.show-deprecation-warnings");
excludes.add("compiler.show-shadowed-device-font-warnings");
excludes.add("compiler.show-binding-warnings");
excludes.add("compiler.verbose-stacktraces");
excludes.add("flex");
}
/**
* Constructor
*/
public Configurator()
{
this(Configuration.class);
}
/**
* Constructor
*/
public Configurator(Class<? extends Configuration> configurationClass)
{
this.configurationClass = configurationClass;
args = new LinkedHashMap<String, Object>();
more = new LinkedHashMap<String, Object>();
tokens = new TreeMap<String, String>();
keepLinkReport = false;
keepSizeReport = false;
keepConfigurationReport = false;
reportMissingLibraries = true;
warnOnFlexOnlyOptionUsage = false;
isConfigurationDirty = true;
configurationDefaultVariable = ICompilerSettingsConstants.FILE_SPECS_VAR; // the default variable of the configuration.
configurationPathResolver = new ConfigurationPathResolver(System.getProperty("user.dir"));
configurationProblems = new ArrayList<ICompilerProblem>();
// initialize the localization manager.
LocalizationManager.get().addLocalizer(new ResourceBundleLocalizer());
}
private ConfigurationBuffer cfgbuf;
private Configuration configuration;
private Class<? extends Configuration> configurationClass;
private Map<String, Object> args, more;
private String[] extras;
private String configurationDefaultVariable;
private boolean keepLinkReport, keepSizeReport, keepConfigurationReport;
private String mainDefinition;
private boolean reportMissingLibraries;
private boolean warnOnFlexOnlyOptionUsage;
private List<String> loadedConfigFiles;
private List<String> missingConfigFiles;
private Map<String, String> tokens;
private boolean isConfigurationDirty;
private boolean configurationSuccess;
private Collection<ICompilerProblem> configurationProblems;
private boolean extrasRequireDefaultVariable;
private IPathResolver configurationPathResolver;
//
// IConfigurator related methods
//
@Override
public List<String> getLoadedConfigurationFiles()
{
return loadedConfigFiles != null ? loadedConfigFiles :
Collections.<String>emptyList();
}
@Override
public List<String> getMissingConfigurationFiles()
{
return missingConfigFiles != null ? missingConfigFiles :
Collections.<String>emptyList();
}
@Override
public boolean applyToProject(IFlexProject project)
{
final IWorkspace workspace = project.getWorkspace();
boolean success = processConfiguration();
workspace.startIdleState();
try
{
if (configuration == null)
return false;
if (project instanceof FlexProject)
{
FlexProject flexProject = (FlexProject)project;
FlexProjectConfigurator.configure(flexProject, configuration);
setupCompatibilityVersion(flexProject);
setupConfigVariables(flexProject);
setupLocaleSettings(flexProject);
setupServices(flexProject);
setupThemeFiles(flexProject);
setupFlex(flexProject);
setupCodegenOptions(flexProject);
}
project.setRuntimeSharedLibraryPath(getRSLSettingsFromConfiguration(configuration));
if (!setupProjectLibraries(project))
success = false;
setupNamespaces(project);
}
finally
{
workspace.endIdleState(IWorkspace.NIL_COMPILATIONUNITS_TO_UPDATE);
}
if (!setupSources(project))
success = false;
return success;
}
private void setupFlex(FlexProject flexProject)
{
flexProject.setFlex(configuration.isFlex());
}
private void setupCodegenOptions(FlexProject flexProject)
{
flexProject.setEnableInlining(configuration.isInliningEnabled());
}
private String computeQNameForTargetFile()
{
List<String> computedSourcePath = new ArrayList<String>();
applySourcePathRules(computedSourcePath);
String targetSourceFileName = configuration.getTargetFile();
if (targetSourceFileName == null)
return null;
final File targetSourceFile = FilenameNormalization.normalize(new File(configuration.getTargetFile()));
for (final String sourcePathEntry : computedSourcePath)
{
final String computedQName = SourcePathManager.computeQName(new File(sourcePathEntry), targetSourceFile);
if (computedQName != null)
return computedQName;
}
return null;
}
@Override
public ITargetSettings getTargetSettings(TargetType targetType)
{
boolean wasConfigurationDirty = isConfigurationDirty;
if (!processConfiguration())
return null;
// Special handling for dump config. If dump config was specified then
// dump it out again if the configuration was not dirty. The config is
// dumped as a side-effect of validating the configuration if it gets
// processed.
try
{
if (!wasConfigurationDirty)
{
if (cfgbuf.getVar(ICompilerSettingsConstants.DUMP_CONFIG_VAR) != null)
{
// The file may have already been dumped as a side-effect of
// applyToProject() so only dump if it does not exist.
String dumpConfigPath = configuration.getDumpConfig();
if (dumpConfigPath != null && !(new File(dumpConfigPath).exists()))
configuration.validateDumpConfig(cfgbuf);
}
}
if (mainDefinition != null)
{
configuration.setMainDefinition(mainDefinition);
}
else if ((configuration.getMainDefinition() == null) && (targetType == TargetType.SWF))
{
String computedQName = computeQNameForTargetFile();
if (computedQName != null)
configuration.setMainDefinition(computedQName);
}
if (targetType == TargetType.SWC)
validateSWCConfiguration();
else
Configuration.validateNoCompcOnlyOptions(cfgbuf);
}
catch (ConfigurationException e)
{
reportConfigurationException(e);
return null;
}
return new TargetSettings(configuration);
}
@Override
public ICompilerProblemSettings getCompilerProblemSettings()
{
processConfiguration();
return new CompilerProblemSettings(configuration);
}
@Override
public Collection<ICompilerProblem> validateConfiguration(String[] args, TargetType targetType)
{
if (args == null)
throw new NullPointerException("args may not be null");
List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>();
ConfigurationBuffer configurationBuffer = createConfigurationBuffer(configurationClass);
try
{
CommandLineConfigurator.parse(configurationBuffer, null, args);
// verify SWC-only args are not used to for a SWF target.
if (targetType == TargetType.SWF)
Configuration.validateNoCompcOnlyOptions(configurationBuffer);
}
catch (ConfigurationException e)
{
final ICompilerProblem problem = new ConfigurationProblem(e);
problems.add(problem);
}
return problems;
}
@Override
public Collection<ICompilerProblem> getConfigurationProblems()
{
assert configuration != null :
"Get the configuration problems after calling applyToProject() or getTargetSettings()";
List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(configurationProblems.size() +
configuration.getConfigurationProblems().size());
problems.addAll(configurationProblems);
problems.addAll(configuration.getConfigurationProblems());
return problems;
}
@Override
public void setConfigurationPathResolver(IPathResolver pathResolver)
{
if (pathResolver == null)
throw new NullPointerException("pathResolver may not be null");
this.configurationPathResolver = pathResolver;
}
// Needed by MXMLC for now.
public Configuration getConfiguration()
{
return configuration;
}
// Needed by MXMLC for now.
public ConfigurationBuffer getConfigurationBuffer()
{
return cfgbuf;
}
/**
* Create a new configuration instance. The Configurator will need to
* create a new configuration for each new configuration. For example,
* creating a new Configurator and getting the target settings will create
* a new configuration. If later on, the configuration is modified by calling
* any of the setter methods on the Configurator, then a new configuration
* will be created the next time applyToProject() or getTargetSettings() is called.
*
* The method may be overriden to allow for greater control when creating a
* custom configuration that extends the built-in configuration.
*
* @return a new configuration instance. If the custom configuration class
* cannot be created, the default configuration class will be created instead.
*/
protected Configuration createConfiguration()
{
try
{
return configurationClass.newInstance();
}
catch (Exception e)
{
// If there is a problem initializing the configuration, then
// throw a ConfigurationException.
reportConfigurationException(new ConfigurationException.CouldNotInstantiate(configurationClass.getName()));
// Create the default configuration so we can report configuration
// problems.
try
{
return Configuration.class.newInstance();
}
catch (Exception e2)
{
// this should never fail
assert(false);
return null;
}
}
}
/**
* Initialize the configuration and the configuration buffer.
*/
protected void initializeConfiguration()
{
// Create a clean configuration and configuration buffer
configuration = createConfiguration();
cfgbuf = createConfigurationBuffer(configuration.getClass());
assert configurationPathResolver != null : "No configuration path resolver was set.";
configuration.setPathResolver(configurationPathResolver);
configuration.setReportMissingCompilerLibraries(reportMissingLibraries);
configuration.setWarnOnFlexOnlyOptionUsage(warnOnFlexOnlyOptionUsage);
}
/**
* Create a configuration buffer.
* @param configurationClass The Configuration object
* @return the configuration buffer to use
*/
protected ConfigurationBuffer createConfigurationBuffer(
Class<? extends Configuration> configurationClass)
{
return new ConfigurationBuffer(
configurationClass, Configuration.getAliases());
}
/**
* Setup theme files.
*/
protected void setupThemeFiles(FlexProject project)
{
project.setThemeFiles(toFileSpecifications(configuration.getCompilerThemeFiles(),
project.getWorkspace()));
}
/**
* Collect all of the different library paths and set them in the project.
* The libraries are ordered with RSL and external libraries having the
* highest priority.
*
* <p>Libraries are ordered highest to lowest priority:
* <ol>
* <li>External Library Path
* <li>RSL Library Path
* <li>Include Library Path
* <li>Library Path
* </ol>
* </p>
* @param project
* @return true if successful, false if there is an error.
*/
protected boolean setupProjectLibraries(IFlexProject project)
{
LinkedHashSet<File> libraries = new LinkedHashSet<File>();
// add External Library Path
List<File> externalLibraryFiles = toFileList(configuration.getCompilerExternalLibraryPath());
libraries.addAll(externalLibraryFiles);
// add RSLs
libraries.addAll(configuration.getRslExcludedLibraries());
// add Include Library Path
libraries.addAll(toFileList(configuration.getCompilerIncludeLibraries()));
// add Library Path
libraries.addAll(toFileList(configuration.getCompilerLibraryPath()));
project.setLibraries(new ArrayList<File>(libraries));
// After we set the library path we can check for ANE files more
// accurately because the library path manager in the project
// will read in all the swc files found in directories on the
// paths.
return validateNoANEFiles(project, externalLibraryFiles);
}
/**
* Validate all of the ANE files are on the external library path.
*
* @param project the project being configured.
* @param externalLibraryFiles the external library path.
* @return true if successful, false if there is an error.
*/
private boolean validateNoANEFiles(IFlexProject project,
List<File>externalLibraryFiles)
{
// Get all the library files in the project.
List<ISWC> libraries = project.getLibraries();
for (ISWC library : libraries)
{
if (library.isANE())
{
// must be on the external library path
if (!isOnExternalLibrayPath(library, externalLibraryFiles))
{
configurationProblems.add(
new ANELibraryNotAllowedProblem(
library.getSWCFile().getAbsolutePath()));
return false;
}
}
}
return true;
}
/**
* Test if the SWC is explicitly on the external library path.
*
* @param library
* @param externalLibraryFiles
* @return true if the library is on the external library path, false otherwise.
*/
private boolean isOnExternalLibrayPath(ISWC library, List<File> externalLibraryFiles)
{
File aneFile = library.getSWCFile();
for (File file : externalLibraryFiles)
{
if (file.equals(aneFile))
return true;
}
return false;
}
/**
* Setup {@code -compatibility-version} level. Falcon only support Flex 3+.
* @param project
*/
protected void setupCompatibilityVersion(FlexProject project)
{
final int compatibilityVersion = configuration.getCompilerMxmlCompatibilityVersion();
if (compatibilityVersion < Configuration.MXML_VERSION_3_0)
throw new UnsupportedOperationException("Unsupported compatibility version: " + configuration.getCompilerCompatibilityVersionString());
project.setCompatibilityVersion(configuration.getCompilerMxmlMajorCompatibilityVersion(),
configuration.getCompilerMxmlMinorCompatibilityVersion(),
configuration.getCompilerMxmlRevisionCompatibilityVersion());
}
/**
* Transfers configuration settings to the project. Handles:
* -services
* -context-root
*
*/
protected void setupServices(FlexProject project)
{
if (configuration.getCompilerServices() != null)
project.setServicesXMLPath(configuration.getCompilerServices().getPath(), configuration.getCompilerContextRoot());
}
/**
* Setup the source paths.
*
* @return true if successful, false otherwise.
*/
protected boolean setupSources(IFlexProject project)
{
// -source-path
List<String> sourcePath = new ArrayList<String>();
applySourcePathRules(sourcePath);
project.setSourcePath(toFiles(sourcePath));
// -include-sources
try
{
project.setIncludeSources(toFileList(configuration.getIncludeSources()));
}
catch (InterruptedException e)
{
assert false : "InterruptedException should never be thrown here";
return false;
}
return true;
}
/**
* Apply the follow source-path rules:
*
* 1. If source-path is empty, the target file's directory will be added to
* source-path.
* 2. If source-path is not empty and if the target file's directory is a
* sub-directory of one of the directories in source-path, source-path
* remains unchanged.
* 3. If source-path is not empty and if the target file's directory is not
* a sub-directory of any one of the directories in source-path, the target
* file's directory is prepended to source-path.
*
* @param sourcePath the source path to apply the rules to.
*/
protected void applySourcePathRules(List<String> sourcePath)
{
String targetFileDirectory = configuration.getTargetFileDirectory();
List<String> configuredSourcePath = configuration.getCompilerSourcePath();
if (targetFileDirectory != null)
{
// This method is called with an empty sourcePath so any additions will
// have the effect of prepending to the sourcePath.
if (configuredSourcePath.isEmpty() ||
(!configuredSourcePath.contains(targetFileDirectory) &&
!isSubdirectoryOf(targetFileDirectory, configuredSourcePath)))
{
sourcePath.add(targetFileDirectory);
}
}
// The configuration system provides additional source paths.
sourcePath.addAll(configuredSourcePath);
}
/**
* Check whether the provided path is a subdirectory of the list of
* directories and vice versa.
*
* @param path - absolute path name of directory to test.
* @param directories - {@link Iterable} of directories to test.
* @return true if path is a subdirectory, false otherwise
*/
private static boolean isSubdirectoryOf(String path, Iterable<String> directories)
{
final File pathFile = FileUtils.canonicalFile(new File(path));
for (String directoryName : directories)
{
final File dirFile = FileUtils.canonicalFile(new File(directoryName));
final long dirFilenameLength = dirFile.getAbsolutePath().length();
File parentFile = pathFile.getParentFile();
while (parentFile != null)
{
if (dirFile.equals(parentFile))
return true;
// if the dirFilenameLength is greater than the parentFilename length
// then break out and try the next path, rather than going all the
// way up to the root, as it can't be a sub directory.
if (dirFilenameLength > parentFile.getAbsolutePath().length())
break;
parentFile = parentFile.getParentFile();
}
}
return false;
}
protected void setupConfigVariables(IFlexProject project)
{
final Map<String, String> compilerDefine = configuration.getCompilerDefine();
if (compilerDefine != null)
project.setDefineDirectives(compilerDefine);
}
protected void setupNamespaces(IFlexProject project)
{
final List<? extends IMXMLNamespaceMapping> configManifestMappings =
configuration.getCompilerNamespacesManifestMappings();
if (configManifestMappings != null)
{
project.setNamespaceMappings(configManifestMappings);
}
}
/**
* Setups the locale related settings.
*/
protected void setupLocaleSettings(IFlexProject project)
{
project.setLocales(configuration.getCompilerLocales());
project.setLocaleDependentResources(configuration.getLocaleDependentSources());
}
public static List<RSLSettings> getRSLSettingsFromConfiguration(Configuration configuration)
{
List<RuntimeSharedLibraryPathInfo> infoList = configuration.getRslPathInfo();
if (infoList == null || infoList.size() == 0)
{
return Collections.emptyList();
}
boolean verifyDigests = configuration.getVerifyDigests();
List<RSLSettings> rslSettingsList = new ArrayList<RSLSettings>(infoList.size());
for (RuntimeSharedLibraryPathInfo info : infoList)
{
// For each loop, convert an RSL and its failovers into
// the RSLSettings class.
RSLSettings rslSettings = new RSLSettings(info.getSWCFile());
List<String> rslURLs = info.getRSLURLs();
List<String> policyFileURLs = info.getPolicyFileURLs();
int n = info.getRSLURLs().size();
for (int i = 0; i < n; i++)
{
rslSettings.addRSLURLAndPolicyFileURL(rslURLs.get(i), policyFileURLs.get(i));
}
rslSettings.setVerifyDigest(verifyDigests);
String swcPath = info.getSWCFile().getPath();
rslSettings.setApplicationDomain(configuration.getApplicationDomain(swcPath));
rslSettings.setForceLoad(configuration.getForceRsls().contains(swcPath));
// Add an RSL to the list of RSL settings.
rslSettingsList.add(rslSettings);
}
return rslSettingsList;
}
/**
* Wrapper around the real processConfiguration.
*
* @return true if success, false otherwise.
*/
protected boolean processConfiguration()
{
boolean success = true;
if (isConfigurationDirty)
{
configurationProblems.clear();
try
{
success = processConfiguration(getOptions(args, more, processExtras(extras)));
}
catch (ConfigurationException e)
{
reportConfigurationException(e);
success = false;
}
}
else
{
success = configurationSuccess;
}
isConfigurationDirty = false;
configurationSuccess = success;
return success;
}
/**
* Does all the work to set the command line arguments info the
* configuration object.
*
* @param argsArray - command line arguments
*
* @return true if successful, false otherwise.
*/
protected boolean processConfiguration(String[] argsArray)
{
initializeConfiguration();
boolean success = true;
try
{
loadDefaults(cfgbuf);
// TODO This is needed until we can defer
// the default style loading in loadDefaults().
byPassConfigurationsRequiringFlexSDK();
SystemPropertyConfigurator.load(cfgbuf, "flex");
// Parse the command line a first time, to peak at stuff like
// "flexlib" and "load-config". The first parse is thrown
// away after that and we intentionally parse a second time
// below. See note below.
CommandLineConfigurator.parse(cfgbuf, configurationDefaultVariable, argsArray);
overrideDefaults();
// Return if "-version" is present so the command line can print the
// version.
if (cfgbuf.getVar("version") != null)
return false;
// Return so the command line can print help if "-help" is present.
final List<ConfigurationValue> helpVar = cfgbuf.getVar("help");
if (helpVar != null)
return false;
// Load configurations from files.
if (!loadConfig())
success = false;
if (!loadProjectConfig())
success = false;
// The command line needs to take precedence over all defaults and config files.
// By simply re-merging the command line back on top,
// we will get the behavior we want.
cfgbuf.clearSourceVars(CommandLineConfigurator.source);
CommandLineConfigurator.parse(cfgbuf, configurationDefaultVariable, argsArray);
// commit() reports problems instead of throwing an exception. This
// allows us to process all the options in a configuration that
// are correct in the hopes that it will be enough to configure a
// project.
if (!cfgbuf.commit(configuration, configurationProblems))
success = false;
configuration.validate(cfgbuf);
}
catch (ConfigurationException e)
{
reportConfigurationException(e);
success = false;
}
return success;
}
/**
* Load the default values into the passed in config buffer
* @param cfgbuf the config buffer to set the default values in
* @throws ConfigurationException
*/
protected void loadDefaults (ConfigurationBuffer cfgbuf) throws ConfigurationException
{
DefaultsConfigurator.loadDefaults(cfgbuf);
}
/**
* Do the validatation that the old COMPCConfiguration used to do.
*/
protected void validateSWCConfiguration() throws ConfigurationException
{
validateSWCInputs();
// verify that if -include-inheritance-dependencies is set that
// -include-classes is not null
if (configuration.getIncludeInheritanceDependenciesOnly() &&
configuration.getIncludeClasses().size() == 0)
{
throw new ConfigurationException.MissingIncludeClasses();
}
}
/**
* Basic validation of compc options. This code used to be
* in the old compiler's CompcConfiguration.
*
* @throws ConfigurationException
*/
protected void validateSWCInputs() throws ConfigurationException
{
if (configuration.getIncludeSources().isEmpty() &&
configuration.getIncludeClasses().isEmpty() &&
configuration.getIncludeNamespaces().isEmpty() &&
((configuration.getCompilerIncludeLibraries() == null) ||
(configuration.getCompilerIncludeLibraries().size() == 0)) &&
configuration.getIncludeFiles().isEmpty() &&
configuration.getIncludeResourceBundles().isEmpty())
{
throw new ConfigurationException.NoSwcInputs( null, null, -1 );
}
}
/**
* By-pass the configurations that requires Flex SDK.
*/
protected void byPassConfigurationsRequiringFlexSDK() throws ConfigurationException
{
if (System.getProperty("flexlib") == null &&
System.getProperty("application.home") == null)
{
cfgbuf.clearVar("load-config", null, -1);
cfgbuf.clearVar("compiler.theme", null, -1);
}
}
/**
* Override default values.
*/
protected void overrideDefaults() throws ConfigurationException
{
String flexlib = cfgbuf.getToken("flexlib");
if (flexlib == null)
{
final String appHome = System.getProperty("application.home");
if (appHome == null)
cfgbuf.setToken("flexlib", ".");
else
cfgbuf.setToken("flexlib", appHome + File.separator + "frameworks");
}
// Framework Type: halo, gumbo, interop...
String framework = cfgbuf.getToken("framework");
if (framework == null)
cfgbuf.setToken("framework", "halo");
String configname = cfgbuf.getToken("configname");
if (configname == null)
cfgbuf.setToken("configname", "flex");
String buildNumber = cfgbuf.getToken("build.number");
if (buildNumber == null)
{
if ("".equals(VersionInfo.getBuild()))
buildNumber = "workspace";
else
buildNumber = VersionInfo.getBuild();
cfgbuf.setToken("build.number", buildNumber);
}
}
/**
* Load configuration XML file specified in {@code -load-config} option on
* command-line.
*
* @return true if successful, false otherwise.
*/
protected boolean loadConfig()
{
boolean success = true;
List<ConfigurationValue> configs;
try
{
configs = cfgbuf.peekConfigurationVar("load-config");
if (configs != null)
{
for (ConfigurationValue cv : configs)
{
for (String path : cv.getArgs())
{
File configFile = configurationPathResolver.resolve(path);
if (!configFile.exists())
{
success = false;
if (missingConfigFiles == null)
missingConfigFiles = new ArrayList<String>();
missingConfigFiles.add(path);
}
else
{
if (!loadConfigFromFile(
cfgbuf,
configFile,
new File(configFile.getPath()).getParent(),
"flex-config",
false))
{
success = false;
}
}
}
}
}
}
catch (ConfigurationException e)
{
reportConfigurationException(e);
success = false;
}
return success;
}
/**
* Load a configuration from file. {@code FileConfigurator.load()} is
* wrapped in this method because we want to print a message after loading
* using {@link MXMLC#println(String)}.
*
* @return true if successful, false otherwise.
*/
protected final boolean loadConfigFromFile(final ConfigurationBuffer buffer,
final File fileSpec,
final String context,
final String rootElement,
final boolean ignoreUnknownItems)
{
boolean success = true;
try
{
FileConfigurator.load(buffer,
new FileSpecification(fileSpec.getAbsolutePath()),
context, rootElement, ignoreUnknownItems);
}
catch (ConfigurationException e)
{
// record exception
reportConfigurationException(e);
success = false;
}
if (loadedConfigFiles == null)
loadedConfigFiles = new ArrayList<String>();
loadedConfigFiles.add(fileSpec.getPath());
return success;
}
/**
* Convert conifguration exceptions to problems and collect them for
* reporting.
*
* @param e
*/
protected void reportConfigurationException(ConfigurationException e)
{
final ICompilerProblem problem = new ConfigurationProblem(e);
configurationProblems.add(problem);
}
/**
* Load project specific configuration. The configuration XML file is at the
* project root with naming convention of [project name]-config.xml.
*
* @return true if successful, false otherwise.
*/
protected boolean loadProjectConfig()
{
boolean success = true;
// Load project file, if any...
List<ConfigurationValue> fileValues = cfgbuf.getVar(ICompilerSettingsConstants.FILE_SPECS_VAR);
if ((fileValues != null) && (fileValues.size() > 0))
{
ConfigurationValue cv = fileValues.get(fileValues.size() - 1);
if (cv.getArgs().size() > 0)
{
String val = cv.getArgs().get(cv.getArgs().size() - 1);
int index = val.lastIndexOf('.');
if (index != -1)
{
String project = val.substring(0, index) + "-config.xml";
File projectFile = configurationPathResolver.resolve(project);
if (projectFile.exists())
{
if (!loadConfigFromFile(
cfgbuf,
projectFile,
new File(project).getParent(),
"flex-config",
false))
{
success = false;
}
}
}
}
}
return success;
}
//
// Configuration related methods
//
protected String[] getOptions(Map<String, Object> args, Map<String, Object> more,
String[] extras)
{
ArrayList<String> buffer = new ArrayList<String>();
for (Map.Entry<String, String> tokenEntry : tokens.entrySet())
{
buffer.add(PLUS_STRING + tokenEntry.getKey() + EQUALS_STRING + tokenEntry.getValue());
}
for (Map.Entry<String, Object> arg : args.entrySet())
{
String key = arg.getKey();
Object value = arg.getValue();
if (value instanceof Boolean)
{
buffer.add(key + EQUALS_STRING + value);
}
else if (value instanceof Number)
{
buffer.add(key);
buffer.add(value.toString());
}
else if (COMPILER_CONTEXT_ROOT.equals(key) && value instanceof String)
{
buffer.add(key);
buffer.add((String)value);
}
else if (value instanceof String)
{
if (!"".equals(value))
{
buffer.add(key);
buffer.add((String)value);
}
else
{
buffer.add(key + EQUALS_STRING);
}
}
else if (value instanceof File)
{
String p = ((File) value).getPath();
if (!"".equals(p))
{
buffer.add(key);
buffer.add(p);
}
else
{
buffer.add(key + EQUALS_STRING);
}
}
else if (value instanceof java.util.Date)
{
buffer.add(key);
buffer.add(value.toString());
}
else if (value instanceof MXMLNamespaceMappingList)
{
addNamespaceMappingsToBuffer(buffer, (MXMLNamespaceMappingList)value, false);
}
else if (value instanceof RSLSettingsList)
{
addRSLSettingsToBuffer(buffer, (RSLSettingsList)value, false);
}
else if (value instanceof CompilerDefinitionMap)
{
final CompilerDefinitionMap defs = (CompilerDefinitionMap)value;
for (Map.Entry<String, String> entry : defs.entrySet())
{
// String.valueOf will help turn null into "null"
String name = entry.getKey();
String val = entry.getValue();
// handle empty-string values
// technically, name should not ever be empty length (value can be),
// but we don't want to do error handling, CompilerConfiguration.cfgDefine()
// will do it for us later
if (name.length() == 0)
{
name = "\"\"";
}
if (val.length() == 0)
{
val = "\"\"";
}
/* note '+=': defines from all flex-config.xmls will be collected (just '=' would
* always ignore all but the most recent definitions), hopefully in a meaningful
* order (flex-config, user-config, commandline) since we now allow re-definitions.
*/
buffer.add(COMPILER_DEFINE + PLUS_EQUALS_STRING + name + COMMA_STRING + val);
}
}
else if (value instanceof Map)
{
@SuppressWarnings("unchecked")
Map<String, ?> m = (Map<String, ?>) value;
for (Map.Entry<String, ?>entry : m.entrySet())
{
String k = entry.getKey();
Object v = entry.getValue();
if (v instanceof String)
{
buffer.add(key);
buffer.add(k);
buffer.add((String)v);
}
else if (v instanceof File)
{
buffer.add(key);
buffer.add(k);
buffer.add(((File) v).getPath());
}
else if (v instanceof Collection)
{
buffer.add(key);
buffer.add(k);
Collection<?> list = (Collection<?>)v;
for (Object next : list)
{
if (next != null)
buffer.add(next.toString());
}
}
else if (v != null)
{
assert false;
}
}
}
else if (value instanceof int[])
{
int[] a = (int[]) value;
buffer.add(key);
buffer.add(String.valueOf(a[0]));
buffer.add(String.valueOf(a[1]));
}
else if (value instanceof Collection)
{
Collection<Object> list = new LinkedList<Object>((Collection<?>)args.get(key));
int length = list.size();
if (length > 0)
{
buffer.add(key);
}
else if (!LOAD_CONFIG.equals(key))
{
buffer.add(key + EQUALS_STRING);
}
for (Object obj : list)
{
if (obj instanceof String)
{
buffer.add((String)obj);
}
else if (obj instanceof File)
{
buffer.add(((File)obj).getPath());
}
}
}
else if (value != null)
{
assert false;
}
else
{
// System.err.println("unprocessed compiler options: " + key + EQUALS_STRING + value);
}
}
for (Map.Entry<String, Object> moreEntry : more.entrySet())
{
String key = moreEntry.getKey();
Object value = moreEntry.getValue();
if (value instanceof Collection)
{
buffer.add(key + PLUS_EQUALS_STRING + toCommaSeparatedString((Collection<?>)value));
}
else if (value instanceof Map)
{
@SuppressWarnings("unchecked")
Map<String, ?> m = (Map<String, ?>) value;
for (Map.Entry<String, ?>entry : m.entrySet())
{
String k = entry.getKey();
Object v = entry.getValue();
if (v instanceof Collection)
{
buffer.add(key + PLUS_EQUALS_STRING + k + COMMA_STRING +
toCommaSeparatedString((Collection<?>)v));
}
else if (v != null)
{
assert false;
}
}
}
else if (value instanceof MXMLNamespaceMappingList)
{
addNamespaceMappingsToBuffer(buffer, (MXMLNamespaceMappingList)value, true);
}
else if (value instanceof RSLSettingsList)
{
addRSLSettingsToBuffer(buffer, (RSLSettingsList)value, true);
}
else if (value != null)
{
assert false;
}
else
{
// System.err.println("unprocessed compiler options: " + key + EQUALS_STRING + value);
}
}
// Append extra command line args to the buffer.
if (extras != null && extras.length > 0)
{
for (int i = 0, length = extras == null ? 0 : extras.length; i < length; i++)
{
if (extras[i] != null)
{
buffer.add(extras[i]);
}
}
}
String[] options = new String[buffer.size()];
buffer.toArray(options);
if (Trace.config)
Trace.trace("Configurator: options = " + buffer.toString());
return options;
}
/**
* Do special case handling of extra arguments for Flash Builder. FB needs
* special handling for some arguments because it sets them using the
* Configurator API and they can also be entered by a user in
* "additional compiler arguments". When both are entered the
* "additional" arguments win. This code isn't pretty but it mimics the behavior
* of the old compiler.
*
* @param extraOptions
*
* @return new array of extra arguments to use. Returns null if
* extraOptions is null.
* @throws ConfigurationException
*/
protected String[] processExtras(String[] extraOptions) throws ConfigurationException
{
// If the extraOptions have default variables then don't process them
// because stripping out options can introduce problems parsing the
// options. One specific case is
// "-source-path . -output comps.swc MyComboBox.mxml MyButton.mxml"
// This is not ambiguous. Stripping out the "output" option leaves
// us with -source-path . MyComboBox.mxml MyButton.mxml" which is
// ambiguous.
if (extraOptions == null || extrasRequireDefaultVariable)
return extraOptions;
List<Object> newArgs = new ArrayList<Object>();
ConfigurationBuffer extrasBuffer = createConfigurationBuffer(configurationClass);
CommandLineConfigurator.parse(extrasBuffer, null, extraOptions);
List<Object[]> positions = extrasBuffer.getPositions();
for (int i = 0, length = positions.size(); i < length; i++)
{
Object[] a = positions.get(i);
String var = (String) a[0];
if ("link-report".equals(var))
{
keepLinkReport(true);
}
else if ("compiler.debug".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
String debugPassword = extrasBuffer.peekSimpleConfigurationVar("debug-password");
if ("true".equals(value))
{
enableDebugging(true, debugPassword);
}
else if ("false".equals(value))
{
enableDebugging(false, debugPassword);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("compiler.verbose-stacktraces".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
enableVerboseStacktraces(true);
}
else if ("false".equals(value))
{
enableVerboseStacktraces(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("compiler.accessible".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
enableAccessibility(true);
}
else if ("false".equals(value))
{
enableAccessibility(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("compiler.strict".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
enableStrictChecking(true);
}
else if ("false".equals(value))
{
enableStrictChecking(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("output".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
setOutput(new File(value));
}
catch (ConfigurationException ex)
{
}
}
else if ("size-report".equals(var))
{
keepSizeReport(true);
}
else if ("warnings".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
showActionScriptWarnings(true);
showBindingWarnings(true);
showDeprecationWarnings(true);
showUnusedTypeSelectorWarnings(true);
}
else if ("false".equals(value))
{
showActionScriptWarnings(false);
showBindingWarnings(false);
showDeprecationWarnings(false);
showUnusedTypeSelectorWarnings(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("compiler.show-actionscript-warnings".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
showActionScriptWarnings(true);
}
else if ("false".equals(value))
{
showActionScriptWarnings(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("compiler.show-deprecation-warnings".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
showDeprecationWarnings(true);
}
else if ("false".equals(value))
{
showDeprecationWarnings(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("compiler.show-binding-warnings".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
showBindingWarnings(true);
}
else if ("false".equals(value))
{
showBindingWarnings(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("compiler.show-unused-type-selector-warnings".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
showUnusedTypeSelectorWarnings(true);
}
else if ("false".equals(value))
{
showUnusedTypeSelectorWarnings(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("compiler.show-multiple-definition-warnings".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
showMultipleDefinitionWarnings(true);
}
else if ("false".equals(value))
{
showMultipleDefinitionWarnings(false);
}
}
catch (ConfigurationException ex)
{
}
}
else if ("flex".equals(var))
{
try
{
String value = extrasBuffer.peekSimpleConfigurationVar(var);
if ("true".equals(value))
{
setFlex(true);
}
else if ("false".equals(value))
{
setFlex(false);
}
}
catch (ConfigurationException ex)
{
}
}
if (!excludes.contains(var))
{
// keep this variable
int iStart = ((Integer) a[1]).intValue();
int iEnd = ((Integer) a[2]).intValue();
for (int j = iStart; j < iEnd; j++)
{
newArgs.add(extraOptions[j]);
}
}
}
extraOptions = new String[newArgs.size()];
newArgs.toArray(extraOptions);
return extraOptions;
}
/**
* Add namespace mappings to the command line buffer.
*
* @param buffer
* @param valueList
* @param append true to use append the command in the buffer, otherwise set the command.
*/
private void addNamespaceMappingsToBuffer(ArrayList<String> buffer, MXMLNamespaceMappingList valueList,
boolean append)
{
if (valueList.isEmpty())
{
StringBuilder sb = new StringBuilder(COMPILER_NAMESPACES_NAMESPACE);
sb.append(append ? PLUS_EQUALS_STRING : EQUALS_STRING);
buffer.add(sb.toString());
return;
}
for (IMXMLNamespaceMapping value : valueList)
{
StringBuilder sb = new StringBuilder(COMPILER_NAMESPACES_NAMESPACE);
sb.append(append ? PLUS_EQUALS_STRING : EQUALS_STRING);
sb.append(value.getURI());
sb.append(COMMA_STRING);
sb.append(value.getManifestFileName());
buffer.add(sb.toString());
}
}
/**
* Append RSLSettings to the command line buffer.
*
* @param buffer
* @param value
* @param append true if the values should be appended to existing RSL settings ("+="), false
* for override existing RSL settings ("=").
*/
private void addRSLSettingsToBuffer(ArrayList<String> buffer, RSLSettingsList valueList,
boolean append)
{
// if the list is empty, override any config files.
if (valueList.isEmpty())
{
StringBuilder sb = new StringBuilder(RUNTIME_SHARED_LIBRARY_PATH);
sb.append(append ? PLUS_EQUALS_STRING : EQUALS_STRING);
buffer.add(sb.toString());
return;
}
// runtime-shared-library-path=path-element,rsl-url,policy-file-url,...
for (RSLSettings settings : valueList)
{
StringBuilder sb = new StringBuilder(RUNTIME_SHARED_LIBRARY_PATH);
sb.append(append ? PLUS_EQUALS_STRING : EQUALS_STRING);
sb.append(settings.getLibraryFile().getPath());
for (RSLAndPolicyFileURLPair urls : settings.getRSLURLs())
{
sb.append(COMMA_STRING);
sb.append(urls.getRSLURL());
sb.append(COMMA_STRING);
sb.append(urls.getPolicyFileURL());
}
buffer.add(sb.toString());
// application-domain=path-element,application-domain-target
if (settings.getApplicationDomain() != ApplicationDomainTarget.DEFAULT)
{
sb = new StringBuilder(RUNTIME_SHARED_LIBRARY_SETTINGS_APPLICATION_DOMAIN);
sb.append(append ? PLUS_EQUALS_STRING : EQUALS_STRING);
sb.append(settings.getLibraryFile().getPath());
sb.append(COMMA_STRING);
sb.append(settings.getApplicationDomain().getApplicationDomainValue());
buffer.add(sb.toString());
}
// force-rsls=path-element
if (settings.isForceLoad())
{
sb = new StringBuilder(RUNTIME_SHARED_LIBRARY_SETTINGS_FORCE_RSLS);
sb.append(append ? PLUS_EQUALS_STRING : EQUALS_STRING);
sb.append(settings.getLibraryFile().getPath());
buffer.add(sb.toString());
}
}
}
/**
* Enables accessibility in the application.
* This is equivalent to using <code>mxmlc/compc --compiler.accessible</code>.<p>
* By default, this is disabled.
*
* @param b boolean value
*/
@Override
public void enableAccessibility(boolean b)
{
args.put(COMPILER_ACCESSIBLE, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Sets the ActionScript file encoding. The compiler will use this encoding to read
* the ActionScript source files.
* This is equivalent to using <code>mxmlc/compc --compiler.actionscript-file-encoding</code>.<p>
* By default, the encoding is <code>UTF-8</code>.
*
* @param encoding charactere encoding, e.g. <code>UTF-8</code>, <code>Big5</code>
*/
@Override
public void setActionScriptFileEncoding(String encoding)
{
args.put(COMPILER_ACTIONSCRIPT_FILE_ENCODING, encoding);
isConfigurationDirty = true;
}
/**
* Allows some source path directories to be subdirectories of the other.
* This is equivalent to using <code>mxmlc/compc --compiler.allow-source-path-overlap</code>.<p>
* By default, this is disabled.<p>
*
* In some J2EE settings, directory overlapping should be allowed. For example,
*
* <pre>
* wwwroot/MyAppRoot
* wwwroot/WEB-INF/flex/source_path1
* </pre>
*
* @param b boolean value
*/
@Override
public void allowSourcePathOverlap(boolean b)
{
args.put(COMPILER_ALLOW_SOURCE_PATH_OVERLAP, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Sets the context root path so that the compiler can replace <code>{context.root}</code> tokens for
* service channel endpoints. This is equivalent to using the <code>compiler.context-root</code> option
* for the mxmlc or compc compilers.
*
* <p>
* By default, this value is undefined.
*
* @param path An instance of String.
*/
@Override
public void setContextRoot(String path)
{
args.put(COMPILER_CONTEXT_ROOT, path);
isConfigurationDirty = true;
}
/**
* Enables debugging in the application.
* This is equivalent to using <code>mxmlc/compc --compiler.debug</code> and <code>--debug-password</code>.<p>
* By default, debug is <code>false</code> and the debug password is "".
*
* @param b boolean value
* @param debugPassword a password that is embedded in the application.
*/
@Override
public void enableDebugging(boolean b, String debugPassword)
{
args.put(COMPILER_DEBUG, b ? Boolean.TRUE : Boolean.FALSE);
args.put(DEBUG_PASSWORD, debugPassword);
isConfigurationDirty = true;
}
/**
* Enable or disable runtime shared libraries in the application.
*
* This is equivalent to using <code>mxmlc --static-link-runtime-shared-libraries</code>.<p>
*
* @param b boolean value
*/
public void setStaticLinkRuntimeSharedLibraries(boolean b)
{
args.put(STATIC_LINK_RUNTIME_SHARED_LIBRARIES, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Sets the location of the default CSS file.
* This is equivalent to using <code>mxmlc/compc --compiler.defaults-css-url</code>.
*
* @param url an instance of <code>java.io.File</code>.
*/
public void setDefaultCSS(File url)
{
args.put(COMPILER_DEFAULTS_CSS_URL, url);
isConfigurationDirty = true;
}
/**
* Sets the list of SWC files or directories to compile against but to omit from linking.
* This is equivalent to using <code>mxmlc/compc --compiler.external-library-path</code>.
*
* @param paths <code>File.isDirectory()</code> should return <code>true</code> or <code>File</code> instances should represent SWC files.
*/
@Override
public void setExternalLibraryPath(Collection<File> paths)
{
removeNativeJSLibrariesIfNeeded(paths);
args.put(COMPILER_EXTERNAL_LIBRARY_PATH, paths);
more.remove(COMPILER_EXTERNAL_LIBRARY_PATH);
isConfigurationDirty = true;
}
private void removeNativeJSLibrariesIfNeeded(Collection<File> paths) {
Iterator<File> fileIterator = paths.iterator();
while (fileIterator.hasNext()) {
final File file = fileIterator.next();
final boolean isNativeJS = file.getAbsolutePath().contains("js/libs");
boolean excludeNativeJS = false;
try {
excludeNativeJS = cfgbuf.peekSimpleConfigurationVar("exclude-native-js-libraries").equals(Boolean.TRUE.toString());
} catch (ConfigurationException e) {
e.printStackTrace();
}
if (isNativeJS && excludeNativeJS) {
fileIterator.remove();
}
}
}
/**
* Adds to the existing list of SWC files.
*
* @see #setExternalLibraryPath
* @param paths <code>File.isDirectory()</code> should return <code>true</code> or <code>File</code> instances should represent SWC files.
*/
@Override
public void addExternalLibraryPath(Collection<File> paths)
{
removeNativeJSLibrariesIfNeeded(paths);
addFiles(COMPILER_EXTERNAL_LIBRARY_PATH, paths);
isConfigurationDirty = true;
}
/**
* Sets the AS3 metadata the compiler should keep in the SWF.
* This is equivalent to using <code>mxmlc --compiler.keep-as3-metadata</code>.
*
* <p>
* The default value is <code>{Bindable, Managed, ChangeEvent, NonCommittingChangeEvent, Transient}</code>.
*
* @param md an array of AS3 metadata names
*/
public void setASMetadataNames(String[] md)
{
args.put(COMPILER_KEEP_AS3_METADATA, md);
more.remove(COMPILER_KEEP_AS3_METADATA);
isConfigurationDirty = true;
}
/**
* Adds the list of AS3 metadata names to the existing list of AS3 metadata the compiler should
* keep in the SWF.
*
* @param md an array of AS3 metadata names
*/
public void addASMetadataNames(Collection<String> md)
{
addStrings(COMPILER_KEEP_AS3_METADATA, md);
isConfigurationDirty = true;
}
/**
* Disables the pruning of unused type selectors.
* This is equivalent to using <code>mxmlc/compc --compiler.keep-all-type-selectors</code>.
* By default, it is set to <code>false</code>.
*
* @param b boolean value
*/
public void keepAllTypeSelectors(boolean b)
{
args.put(COMPILER_KEEP_ALL_TYPE_SELECTORS, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Instructs the linker to keep a report of the content that is included in the application.
* Callers may use <code>Report.writeLinkReport()</code> to retrieve the linker report.
*
* @param b boolean value
*/
public void keepLinkReport(boolean b)
{
keepLinkReport = b;
isConfigurationDirty = true;
}
public boolean keepLinkReport()
{
return keepLinkReport;
}
/**
* Instructs the linker to keep a SWF size report.
* Callers may use <code>Report.writeSizeReport()</code> to retrieve the size report.
*
* @param b boolean value
*/
public void keepSizeReport(boolean b)
{
keepSizeReport = b;
isConfigurationDirty = true;
}
public boolean keepSizeReport()
{
return keepSizeReport;
}
/**
* Instructs the compiler to keep a report of the compiler configuration settings.
* Callers may use <code>Report.writeConfigurationReport()</code> to retrieve the configuration report.
*
* @param b boolean value
*/
public void keepConfigurationReport(boolean b)
{
keepConfigurationReport = b;
isConfigurationDirty = true;
}
public boolean keepConfigurationReport()
{
return keepConfigurationReport;
}
/**
* Instructs the compiler to report missing Libraries as a configuration error.
*
* @param b boolean value
*/
public void reportMissingsLibraries(boolean b)
{
reportMissingLibraries = b;
isConfigurationDirty = true;
}
/**
* Controls if the compiler warns when "Flex only" configuration options
* are used in the compiler.
*
* @param value True to enable warnings, false to disable warnings. The
* default is to not warn.
*/
public void setWarnOnFlexOnlyOptionUsage(boolean value)
{
this.warnOnFlexOnlyOptionUsage = value;
isConfigurationDirty = true;
}
/**
* Includes a list of libraries (SWCs) to completely include in the application
* This is equivalent to using <code>mxmlc/compc --compiler.include-libraries</code>.
*
* @param libraries a collection of <code>java.io.File</code> (<code>File.isDirectory()</code> should return <code>true</code> or instances must represent SWC files).
*/
@Override
public void setIncludeLibraries(Collection<File> libraries)
{
args.put(COMPILER_INCLUDE_LIBRARIES, libraries);
isConfigurationDirty = true;
}
/**
* Sets a list of resource bundles to include in the swf.
* This is equivalent to using <code>mxmlc/compc --include-resource-bundle</code>.
*
* @param bundles an array of <code>java.lang.String</code>
*/
@Override
public void setIncludeResourceBundles(Collection<String> bundles)
{
args.put(INCLUDE_RESOURCE_BUNDLES, bundles);
isConfigurationDirty = true;
}
/**
* Adds a list of resource bundles to the existing list.
*
* @see #setIncludeResourceBundles
* @param bundles an array of <code>java.lang.String</code>
*/
public void addIncludeResourceBundles(Collection<String> bundles)
{
addStrings(INCLUDE_RESOURCE_BUNDLES, bundles);
isConfigurationDirty = true;
}
/**
* Sets a list of SWC files or directories that contain SWC files.
* This is equivalent to using <code>mxmlc/compc --compiler.library-path</code>.
*
* @param paths an array of <code>File</code>. <code>File.isDirectory()</code> should return <code>true</code> or instances must represent SWC files.
*/
@Override
public void setLibraryPath(Collection<File> paths)
{
removeNativeJSLibrariesIfNeeded(paths);
args.put(COMPILER_LIBRARY_PATH, paths);
more.remove(COMPILER_LIBRARY_PATH);
isConfigurationDirty = true;
}
/**
* Adds a list of SWC files or directories to the default library path.
*
* @param paths an array of <code>File</code>. <code>File.isDirectory()</code> should return <code>true</code> or instances must represent SWC files.
* @see #setLibraryPath
*/
public void addLibraryPath(Collection<File> paths)
{
removeNativeJSLibrariesIfNeeded(paths);
addFiles(COMPILER_LIBRARY_PATH, paths);
isConfigurationDirty = true;
}
/**
* Sets the locales that the compiler would use to replace <code>{locale}</code> tokens that appear in some configuration values.
* This is equivalent to using <code>mxmlc/compc --compiler.locale</code>.
* For example,
*
* <pre>
* addSourcePath(new File[] { "locale/{locale}" });
* addLocale(new String[] { "en_US" });
* </pre>
*
* The <code>locale/en_US</code> directory will be added to the source path.
* @since 3.0
*/
public void setLocale(String[] locales)
{
args.put(COMPILER_LOCALE, locales);
isConfigurationDirty = true;
}
@Override
public void setNamespaceMappings(List<? extends IMXMLNamespaceMapping> namespaceMappings)
{
args.put(COMPILER_NAMESPACES_NAMESPACE,
namespaceMappings != null ? new MXMLNamespaceMappingList(namespaceMappings) : null);
more.remove(COMPILER_NAMESPACES_NAMESPACE);
isConfigurationDirty = true;
}
@Override
public void addNamespaceMappings(Collection<IMXMLNamespaceMapping> namespaceMappings)
{
MXMLNamespaceMappingList currentSettings = (MXMLNamespaceMappingList)more.get(COMPILER_NAMESPACES_NAMESPACE);
if (currentSettings == null)
currentSettings = new MXMLNamespaceMappingList(namespaceMappings.size());
currentSettings.addAll(namespaceMappings);
isConfigurationDirty = true;
}
/**
* Enables post-link optimization. This is equivalent to using <code>mxmlc/compc --compiler.optimize</code>.
* Application sizes are usually smaller with this option enabled.
* By default, it is set to <code>true</code>.
*
* @param b boolean value
*/
@Override
public void optimize(boolean b)
{
args.put(COMPILER_OPTIMIZE, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
@Override
public void compress(boolean b)
{
args.put(COMPILER_COMPRESS, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
@Override
public void setServicesXMLPath(String path, String contextRoot)
{
if (path == null || contextRoot == null)
throw new NullPointerException("path and contenxtRoot may not be null.");
args.put(COMPILER_SERVICES, new ServicesContextRoot(path, contextRoot));
isConfigurationDirty = true;
}
/**
* Runs the ActionScript compiler in a mode that detects legal but potentially incorrect code.
* This is equivalent to using <code>mxmlc/compc --compiler.show-actionscript-warnings</code>.
* By default, it is set to <code>true</code>.
*
* @param b boolean value
* @see #checkActionScriptWarning(int, boolean)
*/
@Override
public void showActionScriptWarnings(boolean b)
{
args.put(COMPILER_SHOW_ACTIONSCRIPT_WARNINGS, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Toggles whether warnings generated from data binding code are displayed.
* This is equivalent to using <code>mxmlc/compc --compiler.show-binding-warnings</code>.
* By default, it is set to <code>true</code>.
*
* @param b boolean value
*/
@Override
public void showBindingWarnings(boolean b)
{
args.put(COMPILER_SHOW_BINDING_WARNINGS, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Toggles whether the use of deprecated APIs generates a warning.
* This is equivalent to using <code>mxmlc/compc --compiler.show-deprecation-warnings</code>.
* By default, it is set to <code>true</code>.
*
* @param b boolean value
*/
@Override
public void showDeprecationWarnings(boolean b)
{
args.put(COMPILER_SHOW_DEPRECATION_WARNINGS, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Toggles whether warnings generated from unused type selectors are displayed.
* This is equivalent to using <code>mxmlc/compc --compiler.show-unused-type-selector-warnings</code>.
* By default, it is set to <code>true</code>.
*
* @param b boolean value
*/
@Override
public void showUnusedTypeSelectorWarnings(boolean b)
{
args.put(COMPILER_SHOW_UNUSED_TYPE_SELECTOR_WARNINGS, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
@Override
public void showMultipleDefinitionWarnings(boolean b)
{
args.put(COMPILER_SHOW_MULTIPLE_DEFINITION_WARNINGS, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Sets a list of path elements that form the roots of ActionScript class hierarchies.
* This is equivalent to using <code>mxmlc/compc --compiler.source-path</code>.
*
* @param paths an array of <code>java.io.File</code> (<code>File.isDirectory()</code> must return <code>true</code>).
*/
@Override
public void setSourcePath(List<File> paths)
{
args.put(COMPILER_SOURCE_PATH, paths);
more.remove(COMPILER_SOURCE_PATH);
isConfigurationDirty = true;
}
/**
* Adds a list of path elements to the existing source path list.
*
* @param paths an array of <code>java.io.File</code> (<code>File.isDirectory()</code> must return <code>true</code>).
* @see #setSourcePath
*/
@Override
public void addSourcePath(Collection<File> paths)
{
addFiles(COMPILER_SOURCE_PATH, paths);
isConfigurationDirty = true;
}
/**
* Runs the ActionScript compiler in strict error checking mode.
* This is equivalent to using <code>mxmlc/compc --compiler.strict</code>.
* By default, it is set to <code>true</code>.
*
* @param b boolean value
*/
@Override
public void enableStrictChecking(boolean b)
{
args.put(COMPILER_STRICT, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Sets a list of CSS or SWC files to apply as a theme.
* This is equivalent to using <code>mxmlc/compc --compiler.theme</code>.
*
* @param files an array of <code>java.io.File</code>
*/
@Override
public void setTheme(List<File> files)
{
args.put(COMPILER_THEME, files);
more.remove(COMPILER_THEME);
isConfigurationDirty = true;
}
/**
* Adds a list of CSS or SWC files to the existing list of theme files.
*
* @param files an array of <code>java.io.File</code>
* @see #setTheme
*/
@Override
public void addTheme(List<File> files)
{
addFiles(COMPILER_THEME, files);
isConfigurationDirty = true;
}
/**
* Determines whether resources bundles are included in the application.
* This is equivalent to using <code>mxmlc/compc --compiler.use-resource-bundle-metadata</code>.
* By default, it is set to <code>true</code>.
*
* @param b boolean value
*/
@Override
public void useResourceBundleMetaData(boolean b)
{
args.put(COMPILER_USE_RESOURCE_BUNDLE_METADATA, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Generates bytecodes that include line numbers. When a run-time error occurs,
* the stacktrace shows these line numbers. Enabling this option generates larger SWF files.
* This is equivalent to using <code>mxmlc/compc --compiler.verbose-stacktraces</code>.
* By default, it is set to <code>false</code>.
*
* @param b boolean value
*/
public void enableVerboseStacktraces(boolean b)
{
args.put(COMPILER_VERBOSE_STACKTRACES, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Enables the removal of RSLs associated with libraries
* that are not used by an application.
* This is equivalent to using the
* <code>remove-unused-rsls</code> option of the mxmlc compiler.
*
* <p>
* The default value is <code>false</code>.
*
* @param b Boolean value that enables or disables the removal.
*
* @since 4.5
*/
@Override
public void removeUnusedRuntimeSharedLibraryPaths(boolean b)
{
args.put(REMOVE_UNUSED_RSLS, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Enables checking of ActionScript warnings. They are:
*
* <pre>
* --compiler.warn-array-tostring-changes
* --compiler.warn-assignment-within-conditional
* --compiler.warn-bad-array-cast
* --compiler.warn-bad-bool-assignment
* --compiler.warn-bad-date-cast
* --compiler.warn-bad-es3-type-method
* --compiler.warn-bad-es3-type-prop
* --compiler.warn-bad-nan-comparison
* --compiler.warn-bad-null-assignment
* --compiler.warn-bad-null-comparison
* --compiler.warn-bad-undefined-comparison
* --compiler.warn-boolean-constructor-with-no-args
* --compiler.warn-changes-in-resolve
* --compiler.warn-class-is-sealed
* --compiler.warn-const-not-initialized
* --compiler.warn-constructor-returns-value
* --compiler.warn-deprecated-event-handler-error
* --compiler.warn-deprecated-function-error
* --compiler.warn-deprecated-property-error
* --compiler.warn-duplicate-argument-names
* --compiler.warn-duplicate-variable-def
* --compiler.warn-for-var-in-changes
* --compiler.warn-import-hides-class
* --compiler.warn-instance-of-changes
* --compiler.warn-internal-error
* --compiler.warn-level-not-supported
* --compiler.warn-missing-namespace-decl
* --compiler.warn-negative-uint-literal
* --compiler.warn-no-constructor
* --compiler.warn-no-explicit-super-call-in-constructor
* --compiler.warn-no-type-decl
* --compiler.warn-number-from-string-changes
* --compiler.warn-scoping-change-in-this
* --compiler.warn-slow-text-field-addition
* --compiler.warn-unlikely-function-value
* --compiler.warn-xml-class-has-changed
* </pre>
*
* @param warningCode warning code
* @param b boolean value
* @see #WARN_ARRAY_TO_STRING_CHANGES
* @see #WARN_ASSIGNMENT_WITHIN_CONDITIONAL
* @see #WARN_BAD_ARRAY_CAST
* @see #WARN_BAD_BOOLEAN_ASSIGNMENT
* @see #WARN_BAD_DATE_CAST
* @see #WARN_BAD_ES3_TYPE_METHOD
* @see #WARN_BAD_ES3_TYPE_PROP
* @see #WARN_BAD_NAN_COMPARISON
* @see #WARN_BAD_NULL_ASSIGNMENT
* @see #WARN_BAD_NULL_COMPARISON
* @see #WARN_BAD_UNDEFINED_COMPARISON
* @see #WARN_BOOLEAN_CONSTRUCTOR_WITH_NO_ARGS
* @see #WARN_CHANGES_IN_RESOLVE
* @see #WARN_CLASS_IS_SEALED
* @see #WARN_CONST_NOT_INITIALIZED
* @see #WARN_CONSTRUCTOR_RETURNS_VALUE
* @see #WARN_DEPRECATED_EVENT_HANDLER_ERROR
* @see #WARN_DEPRECATED_FUNCTION_ERROR
* @see #WARN_DEPRECATED_PROPERTY_ERROR
* @see #WARN_DUPLICATE_ARGUMENT_NAMES
* @see #WARN_DUPLICATE_VARIABLE_DEF
* @see #WARN_FOR_VAR_IN_CHANGES
* @see #WARN_IMPORT_HIDES_CLASS
* @see #WARN_INSTANCEOF_CHANGES
* @see #WARN_INTERNAL_ERROR
* @see #WARN_LEVEL_NOT_SUPPORTED
* @see #WARN_MISSING_NAMESPACE_DECL
* @see #WARN_NEGATIVE_UINT_LITERAL
* @see #WARN_NO_CONSTRUCTOR
* @see #WARN_NO_EXPLICIT_SUPER_CALL_IN_CONSTRUCTOR
* @see #WARN_NO_TYPE_DECL
* @see #WARN_NUMBER_FROM_STRING_CHANGES
* @see #WARN_SCOPING_CHANGE_IN_THIS
* @see #WARN_SLOW_TEXTFIELD_ADDITION
* @see #WARN_UNLIKELY_FUNCTION_VALUE
* @see #WARN_XML_CLASS_HAS_CHANGED
*/
@Override
public void checkActionScriptWarning(int warningCode, boolean b)
{
String key = null;
switch (warningCode)
{
case WARN_ARRAY_TO_STRING_CHANGES:
key = COMPILER_WARN_ARRAY_TOSTRING_CHANGES;
break;
case WARN_ASSIGNMENT_WITHIN_CONDITIONAL:
key = COMPILER_WARN_ASSIGNMENT_WITHIN_CONDITIONAL;
break;
case WARN_BAD_ARRAY_CAST:
key = COMPILER_WARN_BAD_ARRAY_CAST;
break;
case WARN_BAD_BOOLEAN_ASSIGNMENT:
key = COMPILER_WARN_BAD_BOOL_ASSIGNMENT;
break;
case WARN_BAD_DATE_CAST:
key = COMPILER_WARN_BAD_DATE_CAST;
break;
case WARN_BAD_ES3_TYPE_METHOD:
key = COMPILER_WARN_BAD_ES3_TYPE_METHOD;
break;
case WARN_BAD_ES3_TYPE_PROP:
key = COMPILER_WARN_BAD_ES3_TYPE_PROP;
break;
case WARN_BAD_NAN_COMPARISON:
key = COMPILER_WARN_BAD_NAN_COMPARISON;
break;
case WARN_BAD_NULL_ASSIGNMENT:
key = COMPILER_WARN_BAD_NULL_ASSIGNMENT;
break;
case WARN_BAD_NULL_COMPARISON:
key = COMPILER_WARN_BAD_NULL_COMPARISON;
break;
case WARN_BAD_UNDEFINED_COMPARISON:
key = COMPILER_WARN_BAD_UNDEFINED_COMPARISON;
break;
case WARN_BOOLEAN_CONSTRUCTOR_WITH_NO_ARGS:
key = COMPILER_WARN_BOOLEAN_CONSTRUCTOR_WITH_NO_ARGS;
break;
case WARN_CHANGES_IN_RESOLVE:
key = COMPILER_WARN_CHANGES_IN_RESOLVE;
break;
case WARN_CLASS_IS_SEALED:
key = COMPILER_WARN_CLASS_IS_SEALED;
break;
case WARN_CONST_NOT_INITIALIZED:
key = COMPILER_WARN_CONST_NOT_INITIALIZED;
break;
case WARN_CONSTRUCTOR_RETURNS_VALUE:
key = COMPILER_WARN_CONSTRUCTOR_RETURNS_VALUE;
break;
case WARN_DEPRECATED_EVENT_HANDLER_ERROR:
key = COMPILER_WARN_DEPRECATED_EVENT_HANDLER_ERROR;
break;
case WARN_DEPRECATED_FUNCTION_ERROR:
key = COMPILER_WARN_DEPRECATED_FUNCTION_ERROR;
break;
case WARN_DEPRECATED_PROPERTY_ERROR:
key = COMPILER_WARN_DEPRECATED_PROPERTY_ERROR;
break;
case WARN_DUPLICATE_ARGUMENT_NAMES:
key = COMPILER_WARN_DUPLICATE_ARGUMENT_NAMES;
break;
case WARN_DUPLICATE_VARIABLE_DEF:
key = COMPILER_WARN_DUPLICATE_VARIABLE_DEF;
break;
case WARN_FOR_VAR_IN_CHANGES:
key = COMPILER_WARN_FOR_VAR_IN_CHANGES;
break;
case WARN_IMPORT_HIDES_CLASS:
key = COMPILER_WARN_IMPORT_HIDES_CLASS;
break;
case WARN_INSTANCEOF_CHANGES:
key = COMPILER_WARN_INSTANCE_OF_CHANGES;
break;
case WARN_INTERNAL_ERROR:
key = COMPILER_WARN_INTERNAL_ERROR;
break;
case WARN_LEVEL_NOT_SUPPORTED:
key = COMPILER_WARN_LEVEL_NOT_SUPPORTED;
break;
case WARN_MISSING_NAMESPACE_DECL:
key = COMPILER_WARN_MISSING_NAMESPACE_DECL;
break;
case WARN_NEGATIVE_UINT_LITERAL:
key = COMPILER_WARN_NEGATIVE_UINT_LITERAL;
break;
case WARN_NO_CONSTRUCTOR:
key = COMPILER_WARN_NO_CONSTRUCTOR;
break;
case WARN_NO_EXPLICIT_SUPER_CALL_IN_CONSTRUCTOR:
key = COMPILER_WARN_NO_EXPLICIT_SUPER_CALL_IN_CONSTRUCTOR;
break;
case WARN_NO_TYPE_DECL:
key = COMPILER_WARN_NO_TYPE_DECL;
break;
case WARN_NUMBER_FROM_STRING_CHANGES:
key = COMPILER_WARN_NUMBER_FROM_STRING_CHANGES;
break;
case WARN_SCOPING_CHANGE_IN_THIS:
key = COMPILER_WARN_SCOPING_CHANGE_IN_THIS;
break;
case WARN_SLOW_TEXTFIELD_ADDITION:
key = COMPILER_WARN_SLOW_TEXT_FIELD_ADDITION;
break;
case WARN_UNLIKELY_FUNCTION_VALUE:
key = COMPILER_WARN_UNLIKELY_FUNCTION_VALUE;
break;
case WARN_XML_CLASS_HAS_CHANGED:
key = COMPILER_WARN_XML_CLASS_HAS_CHANGED;
break;
}
if (key != null)
{
args.put(key, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
}
/**
* Sets the default background color (may be overridden by the application code).
* This is equivalent to using <code>mxmlc/compc --default-background-color</code>.
* The default value is <code>0x869CA7</code>.
*
* @param color RGB value
*/
public void setDefaultBackgroundColor(int color)
{
args.put(DEFAULT_BACKGROUND_COLOR, new Integer(color));
isConfigurationDirty = true;
}
/**
* Sets the default frame rate to be used in the application.
* This is equivalent to using <code>mxmlc/compc --default-frame-rate</code>.
* The default value is <code>24</code>.
*
* @param rate frames per second
*/
public void setDefaultFrameRate(int rate)
{
args.put(DEFAULT_FRAME_RATE, new Integer(rate));
isConfigurationDirty = true;
}
/**
* Sets the default script execution limits (may be overridden by root attributes).
* This is equivalent to using <code>mxmlc/compc --default-script-limits</code>.
* The default maximum recursion depth is <code>1000</code>.
* The default maximum execution time is <code>60</code>.
*
* @param maxRecursionDepth recursion depth
* @param maxExecutionTime execution time in seconds.
*/
public void setDefaultScriptLimits(int maxRecursionDepth, int maxExecutionTime)
{
args.put(DEFAULT_SCRIPT_LIMITS, new int[] { maxRecursionDepth, maxExecutionTime });
isConfigurationDirty = true;
}
/**
* Sets the default window size.
* This is equivalent to using <code>mxmlc/compc --default-size</code>.
* The default width is <code>500</code>.
* The default height is <code>375</code>.
*
* @param width width in pixels
* @param height height in pixels
*/
public void setDefaultSize(int width, int height)
{
args.put(DEFAULT_SIZE, new int[] { width, height });
isConfigurationDirty = true;
}
/**
* Sets a list of definitions to omit from linking when building an application.
* This is equivalent to using <code>mxmlc/compc --externs</code>.
*
* @param definitions An array of definitions (e.g. classes, functions, variables, namespaces, etc.)
*/
@Override
public void setExterns(Collection<String> definitions)
{
args.put(EXTERNS, definitions);
more.remove(EXTERNS);
isConfigurationDirty = true;
}
/**
* Adds a list of definitions to the existing list of definitions.
*
* @see #setExterns
* @param definitions an array of definitions (e.g. classes, functions, variables, namespaces, etc.)
*/
public void addExterns(Collection<String> definitions)
{
addStrings(EXTERNS, definitions);
isConfigurationDirty = true;
}
/**
* Loads a file containing configuration options. The file format follows the format of <code>flex-config.xml</code>.
* This is equivalent to using <code>mxmlc/compc --load-config</code>.
*
* @param file an instance of <code>java.io.File</code>
*/
public void setConfiguration(File file)
{
args.put(LOAD_CONFIG, file);
more.remove(LOAD_CONFIG);
isConfigurationDirty = true;
}
/**
* Adds a file to the existing list of configuration files.
*
* @see #setConfiguration(File)
* @param file a configuration file
*/
public void addConfiguration(File file)
{
addFiles(LOAD_CONFIG, Collections.singleton(file));
isConfigurationDirty = true;
}
/**
* Sets the configuration parameters. The input should be valid <code>mxmlc/compc</code> command-line arguments.<p>
*
* @param args <code>mxmlc/compc</code> command-line arguments
* @param defaultVariable the default variable of the configuration.
*/
public void setConfiguration(String[] args, String defaultVariable)
{
setConfiguration(args, defaultVariable, true);
}
/**
* Sets the configuration parameters. The input should be valid
* <code>mxmlc/compc</code> command-line arguments.
* <p>
*
* @param args <code>mxmlc/compc</code> command-line arguments
* @param defaultVariable the default variable of the configuration.
* @param argsRequireDefaultVariable true if the default variable must be
* set in order to parse the args, false otherwise.
*/
public void setConfiguration(String[] args, String defaultVariable,
boolean argsRequireDefaultVariable)
{
extras = args;
extrasRequireDefaultVariable = argsRequireDefaultVariable;
configurationDefaultVariable = defaultVariable;
isConfigurationDirty = true;
}
/**
* Sets a list of definitions to omit from linking when building an application.
* This is equivalent to using <code>mxmlc/compc --load-externs</code>.
* This option is similar to <code>setExterns(String[])</code>. The following is an example of
* the file format:
*
* <pre>
* &lt;script>
* &lt;!-- use 'dep', 'pre' or 'dep' to specify a definition to be omitted from linking. -->
* &lt;def id="mx.skins:ProgrammaticSkin"/>
* &lt;pre id="mx.core:IFlexDisplayObject"/>
* &lt;dep id="String"/>
* &lt;/script>
* </pre>
*
* @param files an array of <code>java.io.File</code>
*/
public void setLoadExterns(Collection<File> files)
{
args.put(LOAD_EXTERNS, files);
more.remove(LOAD_EXTERNS);
isConfigurationDirty = true;
}
/**
* Adds a list of files to the existing list of definitions to be omitted from linking.
*
* @see #setLoadExterns
* @see #setExterns
* @param files an array of <code>java.io.File</code>.
*/
public void addLoadExterns(Collection<File> files)
{
addFiles(LOAD_EXTERNS, files);
isConfigurationDirty = true;
}
/**
* Sets a SWF frame label with a sequence of classnames that will be linked onto the frame.
* This is equivalent to using <code>mxmlc/compc --frames.frame</code>.
*
* @param label A string
* @param classNames a collection of class names
*/
public void setFrameLabel(String label, Collection<String> classNames)
{
if (!args.containsKey(FRAMES_FRAME))
{
args.put(FRAMES_FRAME, new TreeMap<String, Collection<String>>());
}
// I am ONLY doing this because we set it three lines above
@SuppressWarnings("unchecked")
Map<String, Collection<String>> map = (Map<String, Collection<String>>) args.get(FRAMES_FRAME);
map.put(label, classNames);
isConfigurationDirty = true;
}
/**
* Sets a list of definitions to always link in when building an application.
* This is equivalent to using <code>mxmlc/compc --includes</code>.
*
* @param definitions an array of definitions (e.g. classes, functions, variables, namespaces, etc).
*/
public void setIncludes(Collection<String> definitions)
{
args.put(INCLUDES, definitions);
more.remove(INCLUDES);
isConfigurationDirty = true;
}
/**
* Adds a list of definitions to the existing list of definitions.
*
* @see #setIncludes
* @param definitions an array of definitions (e.g. classes, functions, variables, namespaces, etc.)
*/
public void addIncludes(Collection<String> definitions)
{
addStrings(INCLUDES, definitions);
isConfigurationDirty = true;
}
/**
* Specifies the licenses that the compiler has to validate before compiling.
* This is equivalent to using <code>mxmlc/compc --licenses.license</code>
*
* @param productName a string
* @param serialNumber a serial number
*/
public void setLicense(String productName, String serialNumber)
{
if (!args.containsKey(LICENSES_LICENSE))
{
args.put(LICENSES_LICENSE, new TreeMap<String, String>());
}
// I am ONLY doing this because we set it three lines above
@SuppressWarnings("unchecked")
Map<String, String> map = (Map<String, String>) args.get(LICENSES_LICENSE);
map.put(productName, serialNumber);
isConfigurationDirty = true;
}
/**
* Sets the metadata section of the application SWF. This option is equivalent to using the following <code>mxmlc/compc</code>
* command-line options:
*
* <pre>
* --metadata.contributor
* --metadata.creator
* --metadata.date
* --metadata.description
* --metadata.language
* --metadata.localized-description
* --metadata.localized-title
* --metadata.publisher
* --metadata.title
* </pre>
*
* The valid fields and types of value are specified below:
*
* <pre>
* CONTRIBUTOR java.lang.String
* CREATOR java.lang.String
* DATE java.util.Date
* DESCRIPTION java.util.Map<String, String>
* TITLE java.util.Map<String, String>
* LANGUAGE java.lang.String
* PUBLISHER java.lang.String
* </pre>
*
* For example,
*
* <pre>
* Map titles = new HashMap();
* titles.put("EN", "Apache Flex 4.8.0 Application");
*
* Map descriptions = new HashMap();
* descriptions.put("EN", "http://www.adobe.com/products/flex");
*
* setSWFMetaData(Configuration.LANGUAGE, "EN");
* setSWFMetaData(Configuration.TITLE, titles);
* setSWFMetaData(Configuration.DESCRIPTION, descriptions);
* </pre>
*
* @param field CONTRIBUTOR, CREATOR, DATE, DESCRIPTION, TITLE, LANGUAGE, PUBLISHER
* @param value String, Date or Map
* @see #CONTRIBUTOR
* @see #CREATOR
* @see #DATE
* @see #DESCRIPTION
* @see #TITLE
* @see #LANGUAGE
* @see #PUBLISHER
*/
@Override
public void setSWFMetadata(int field, Object value)
{
switch (field)
{
case CONTRIBUTOR:
args.put(METADATA_CONTRIBUTOR, value);
break;
case CREATOR:
args.put(METADATA_CREATOR, value);
break;
case DATE:
args.put(METADATA_DATE, value);
break;
case DESCRIPTION:
args.put(METADATA_LOCALIZED_DESCRIPTION, value);
break;
case TITLE:
args.put(METADATA_LOCALIZED_TITLE, value);
break;
case LANGUAGE:
args.put(METADATA_LANGUAGE, value);
break;
case PUBLISHER:
args.put(METADATA_PUBLISHER, value);
break;
}
args.remove(RAW_METADATA);
isConfigurationDirty = true;
}
/**
* Sets the metadata section of the application SWF.
* This is equivalent to using <code>mxmlc/compc --raw-metadata</code>.
* This option overrides everything set by the <code>setSWFMetaData</code> method.
*
* @see #setSWFMetadata(int, Object)
* @param xml a well-formed XML fragment
*/
@Override
public void setSWFMetadata(String xml)
{
args.put(RAW_METADATA, xml);
args.remove(METADATA_CONTRIBUTOR);
args.remove(METADATA_CREATOR);
args.remove(METADATA_DATE);
args.remove(METADATA_LOCALIZED_DESCRIPTION);
args.remove(METADATA_LOCALIZED_TITLE);
args.remove(METADATA_LANGUAGE);
args.remove(METADATA_PUBLISHER);
isConfigurationDirty = true;
}
/**
* Sets a list of runtime shared library URLs to be loaded before the application starts.
* This is equivalent to using <code>mxmlc/compc --runtime-shared-libraries</code>.
*
* @param libraries an array of <code>java.lang.String</code>.
*/
@Override
public void setRuntimeSharedLibraries(List<String> libraries)
{
args.put(RUNTIME_SHARED_LIBRARIES, libraries);
more.remove(RUNTIME_SHARED_LIBRARIES);
isConfigurationDirty = true;
}
/**
* Adds a list of runtime shared library URLs to the existing list.
*
* @see #setRuntimeSharedLibraries
* @param libraries an array of <code>java.lang.String</code>
*/
public void addRuntimeSharedLibraries(List<String> libraries)
{
addStrings(RUNTIME_SHARED_LIBRARIES, libraries);
isConfigurationDirty = true;
}
/**
* Toggles whether the application SWF is flagged for access to network resources.
* This is equivalent to using <code>mxmlc/compc --use-network</code>.
* By default, it is set to <code>true</code>.
*
* @param b boolean value
*/
public void useNetwork(boolean b)
{
args.put(USE_NETWORK, b ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
/**
* Defines a token. mxmlc and compc support token substitutions. For example,
*
* <pre>
* mxmlc +flexlib=path1 +foo=bar --var=${foo}
* </pre>
*
* <code>var=bar</code> after the substitution of <code>${foo}</code>.
*
* @param name The name of the token.
* @param value The value of the token.
*/
@Override
public void setToken(String name, String value)
{
tokens.put(name, value);
isConfigurationDirty = true;
}
/**
* Set the class name of the main definition
*
* @param name of the main definition
*/
public void setMainDefinition(String name)
{
mainDefinition = name;
isConfigurationDirty = true;
}
/**
*
* @param key
* @param files
*/
private void addFiles(String key, Collection<File> files)
{
addFiles(more, key, files);
}
/**
*
* @param more
* @param key
* @param files
*/
@SuppressWarnings("unchecked")
private void addFiles(Map<String, Object> more, String key, Collection<File> files)
{
Collection<File> existing = null;
if (more.containsKey(key))
{
Object obj = more.get(key);
existing = (Collection<File>) obj;
}
if (existing != null)
{
existing.addAll(files);
files = existing;
}
more.put(key, files);
}
/**
*
* @param key
* @param strings
*/
private void addStrings(String key, Collection<String> strings)
{
addStrings(more, key, strings);
}
/**
*
* @param more
* @param key
* @param strings
*/
@SuppressWarnings("unchecked")
private void addStrings(Map<String, Object> more, String key, Collection<String> strings)
{
Collection<String> existing = null;
if (more.containsKey(key))
{
existing = (Collection<String>) more.get(key);
}
if (existing != null)
{
existing.addAll(strings);
strings = existing;
}
more.put(key, strings);
}
/**
*
*/
@Override
public String toString()
{
String[] options;
try
{
options = getOptions(args, more, processExtras(extras));
}
catch (ConfigurationException e)
{
options = new String[0];
}
StringBuilder b = new StringBuilder();
for (int i = 0; i < options.length; i++)
{
b.append(options[i]);
b.append(' ');
}
return b.toString();
}
private String toCommaSeparatedString(Collection<?> values)
{
StringBuilder b = new StringBuilder();
int length = values.size();
int i = 0;
for (Object value : values)
{
String valueString = null;
if (value instanceof String)
{
valueString = (String)value;
}
else if (value instanceof File)
{
valueString = ((File)value).getPath();
}
if (valueString != null)
b.append(valueString);
if (i++ < length - 1)
{
b.append(COMMA_STRING);
}
}
return b.toString();
}
@Override
public void setTargetPlayer(int major, int minor, int revision)
{
args.put(TARGET_PLAYER, major + "." + minor + "." + revision);
isConfigurationDirty = true;
}
@Override
public void setCompatibilityVersion(int major, int minor, int revision)
{
if (!(major == 0 && minor == 0 && revision == 0))
{
args.put(COMPILER_MXML_COMPATIBILITY, major + "." + minor + "." + revision);
}
isConfigurationDirty = true;
}
@Override
public void enableDigestVerification(boolean verify)
{
args.put(VERIFY_DIGESTS, verify ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
@Override
public void setDefineDirectives(Map<String, String> defines)
{
if (defines == null)
{
args.remove(COMPILER_DEFINE);
}
else
{
final CompilerDefinitionMap defs = new CompilerDefinitionMap();
defs.putAll(defines);
args.put(COMPILER_DEFINE, defs);
}
isConfigurationDirty = true;
}
@SuppressWarnings("unchecked")
public Map<String, List<String>> getExtensions() {
if( !args.containsKey( COMPILER_EXTENSIONS ) ) {
args.put( COMPILER_EXTENSIONS, new LinkedHashMap<String, List<String>>() );
}
return (Map<String, List<String>>) args.get( COMPILER_EXTENSIONS );
}
public void addExtensionLibraries( File extension, List<String> parameter )
{
getExtensions().put( extension.getAbsolutePath(), parameter );
isConfigurationDirty = true;
}
@Override
public void setExtensionLibraries( Map<File, List<String>> extensions)
{
getExtensions().clear();
Set<File> keys = extensions.keySet();
for ( File key : keys )
{
addExtensionLibraries( key, extensions.get( key ) );
}
isConfigurationDirty = true;
}
@Override
public Configurator clone()
{
Configurator cloneConfig;
try
{
cloneConfig = (Configurator) super.clone();
}
catch ( CloneNotSupportedException e )
{
throw new RuntimeException(e);//wont happen
}
cloneConfig.args = new LinkedHashMap<String, Object>(args);
cloneConfig.more = new LinkedHashMap<String, Object>(more);
cloneConfig.tokens = new LinkedHashMap<String, String>(tokens);
cloneConfig.configurationClass = configurationClass;
cloneConfig.keepLinkReport = keepLinkReport;
cloneConfig.keepSizeReport = keepSizeReport;
cloneConfig.keepConfigurationReport = keepConfigurationReport;
cloneConfig.reportMissingLibraries = reportMissingLibraries;
cloneConfig.warnOnFlexOnlyOptionUsage = warnOnFlexOnlyOptionUsage;
cloneConfig.mainDefinition = mainDefinition;
cloneConfig.isConfigurationDirty = true;
if (extras != null)
{
cloneConfig.extras = new String[extras.length];
System.arraycopy(extras, 0, cloneConfig.extras, 0, extras.length);
}
return cloneConfig;
}
@Override
public void setRuntimeSharedLibraryPath(List<RSLSettings> rslSettings)
{
args.put(RUNTIME_SHARED_LIBRARY_PATH,
rslSettings != null ? new RSLSettingsList(rslSettings) : null);
more.remove(RUNTIME_SHARED_LIBRARY_PATH);
isConfigurationDirty = true;
}
@Override
public void addRuntimeSharedLibraryPath(List<RSLSettings> rslSettings)
{
RSLSettingsList currentSettings = (RSLSettingsList)more.get(RUNTIME_SHARED_LIBRARY_PATH);
if (currentSettings == null)
currentSettings = new RSLSettingsList(rslSettings.size());
currentSettings.addAll(rslSettings);
isConfigurationDirty = true;
}
@Override
public void setLocales(Collection<String> locales)
{
args.put(COMPILER_LOCALE, locales);
more.remove(COMPILER_LOCALE);
isConfigurationDirty = true;
}
@Override
public void addLocales(Collection<String> locales)
{
addStrings(COMPILER_LOCALE, locales);
isConfigurationDirty = true;
}
@Override
public void setOutput(File output)
{
args.put(OUTPUT, output);
isConfigurationDirty = true;
}
//
// Library Settings
//
@Override
public void setIncludeClasses(Collection<String> classes)
{
args.put(INCLUDE_CLASSES, classes);
isConfigurationDirty = true;
}
@Override
public void setIncludeFiles(Map<String, File> files)
{
args.put(INCLUDE_FILE, files);
isConfigurationDirty = true;
}
@Override
public void setIncludeNamespaces(Collection<String> namespaces)
{
args.put(INCLUDE_NAMESPACES, namespaces);
isConfigurationDirty = true;
}
@Override
public void setIncludeSources(Collection<File> sources)
{
args.put(INCLUDE_SOURCES, sources);
isConfigurationDirty = true;
}
@Override
public void setIncludeStyleSheet(Map<String, File> styleSheets)
{
args.put(INCLUDE_STYLESHEET, styleSheets);
isConfigurationDirty = true;
}
@Override
public void enableIncludeLookupOnly(boolean include)
{
args.put(INCLUDE_LOOKUP_ONLY, include ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
@Override
public void setFlex(boolean value)
{
args.put(FLEX, value ? Boolean.TRUE : Boolean.FALSE);
isConfigurationDirty = true;
}
@Override
public void setExcludeNativeJSLibraries(boolean value)
{
args.put(EXCLUDE_NATIVE_JS_LIBRARIES, value ? Boolean.TRUE : Boolean.TRUE);
}
//
// End of Configuration settings.
//
}