/* * * 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 flex2.tools; import static org.apache.flex.compiler.clients.MXMLJSC.JSOutputType.FLEXJS_DUAL; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.util.*; import org.apache.flex.compiler.clients.COMPC; import org.apache.flex.compiler.clients.MXMLC; import org.apache.flex.compiler.clients.MXMLJSC.JSOutputType; import org.apache.flex.compiler.clients.problems.ProblemQuery; import org.apache.flex.compiler.clients.problems.ProblemQueryProvider; import org.apache.flex.compiler.config.Configuration; import org.apache.flex.compiler.config.ConfigurationBuffer; import org.apache.flex.compiler.config.ConfigurationValue; import org.apache.flex.compiler.filespecs.FileSpecification; import org.apache.flex.compiler.internal.config.FileConfigurator; import org.apache.flex.compiler.problems.CompilerProblemSeverity; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.problems.annotations.DefaultSeverity; import org.apache.flex.utils.ArgumentUtil; import flash.localization.LocalizationManager; import flex2.compiler.Logger; import flex2.compiler.config.ConfigurationException; import flex2.compiler.util.CompilerMessage; import flex2.compiler.util.CompilerMessage.CompilerError; import flex2.compiler.util.ConsoleLogger; import flex2.compiler.util.ThreadLocalToolkit; import flex2.tools.oem.Message; /** * Common base class for most flex tools. */ public class Tool { protected static Class<? extends MXMLC> COMPILER; protected static Class<? extends MxmlJSC> JS_COMPILER; protected static int compile(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { int exitCode; final String value = ArgumentUtil.getValue(args, "-js-output-type"); JSOutputType jsOutputType = null; if (value != null) { jsOutputType = JSOutputType.fromString(value); } if (jsOutputType != null) { ArgumentBag bag = prepareJs(new ArgumentBag(args)); MxmlJSC mxmlJSC = JS_COMPILER.newInstance(); exitCode = mxmlJSC.execute(bag.args); if (!mxmlJSC.getProblemQuery().hasErrors()) { if (jsOutputType.equals(FLEXJS_DUAL)) { prepareAs3(bag); exitCode = flexCompile(bag.args); } } else { processProblemReport(mxmlJSC); } } else { exitCode = flexCompile(args); } return exitCode; } protected static ArgumentBag prepareJs(ArgumentBag bag) { SwitchDefineToCompileJs(bag); prepareJsOutput(bag); return bag; } protected static ArgumentBag prepareAs3(ArgumentBag bag) { SwitchDefineToCompileAs3(bag); prepareAs3Output(bag); removeNativeJSLibraries(bag); return bag; } private static void removeNativeJSLibraries(ArgumentBag bag) { final List<String> argList = new ArrayList<String>(Arrays.asList(bag.args)); argList.add("--exclude-native-js-libraries=true"); bag.args = argList.toArray(new String[argList.size()]); } private static void prepareJsOutput(ArgumentBag bag) { bag.isCommandLineOutput = true; bag.oldOutputPath = ArgumentUtil.getValue(bag.args, "-output"); if (bag.oldOutputPath == null) { bag.oldOutputPath = ArgumentUtil.getValue(bag.args, "-o"); if (bag.oldOutputPath != null) { bag.outputAlias = "-o"; } } else { bag.outputAlias = "-output"; } if (bag.oldOutputPath == null) { bag.isCommandLineOutput = false; List<ConfigurationBuffer> flexConfigs = null; try { flexConfigs = loadConfig(bag.args); for (ConfigurationBuffer flexConfig : flexConfigs) { if (bag.oldOutputPath == null) { final List<ConfigurationValue> output = flexConfig != null ? flexConfig.getVar("output") : null; final ConfigurationValue configurationValue = output != null ? output.get(0) : null; bag.oldOutputPath = configurationValue != null ? configurationValue.getArgs().get(0) : bag.oldOutputPath; } } } catch (org.apache.flex.compiler.exceptions.ConfigurationException ignored) { } } if (bag.oldOutputPath != null) { final int lastIndexOf = Math.max(bag.oldOutputPath.lastIndexOf("/"), bag.oldOutputPath.lastIndexOf("\\")); if (lastIndexOf > -1) { bag.newOutputPath = bag.oldOutputPath.substring(0, lastIndexOf) + File.separator + "js" + File.separator + "out"; if (bag.isCommandLineOutput) { ArgumentUtil.setValue(bag.args, bag.outputAlias, bag.newOutputPath); } else { bag.args = ArgumentUtil.addValue(bag.args, "-output", bag.newOutputPath); } } } } private static void SwitchDefineToCompileJs(ArgumentBag bag) { final Collection<String> defines = ArgumentUtil.getValues(bag.args, "-define"); if (defines.contains("COMPILE::AS3,AUTO") && defines.contains("COMPILE::JS,AUTO")) { bag.args = ArgumentUtil.removeElementWithValue(bag.args, "-define", "COMPILE::JS,AUTO"); bag.args = ArgumentUtil.removeElementWithValue(bag.args, "-define", "COMPILE::AS3,AUTO"); bag.args = ArgumentUtil.addValue(bag.args, "-define", "COMPILE::JS,true", true); bag.args = ArgumentUtil.addValue(bag.args, "-define", "COMPILE::AS3,false", true); bag.args = ArgumentUtil.addValue(bag.args, "-keep-asdoc", null); } } private static void prepareAs3Output(ArgumentBag bag) { if (bag.oldOutputPath != null) { if (bag.isCommandLineOutput) { ArgumentUtil.setValue(bag.args, bag.outputAlias, bag.oldOutputPath); } else { bag.args = ArgumentUtil.removeElement(bag.args, "-output"); } } if (COMPILER.getName().equals(COMPC.class.getName())) { bag.args = ArgumentUtil.addValue(bag.args, "-include-file", "js" + File.separator + "out" + File.separator + "*," + bag.newOutputPath); } } private static void SwitchDefineToCompileAs3(ArgumentBag bag) { final Collection<String> defines = ArgumentUtil.getValues(bag.args, "-define"); if (defines.contains("COMPILE::AS3,false") && defines.contains("COMPILE::JS,true")) { bag.args = ArgumentUtil.removeElement(bag.args, "-keep-asdoc"); bag.args = ArgumentUtil.removeElementWithValue(bag.args, "-define", "COMPILE::AS3,false"); bag.args = ArgumentUtil.removeElementWithValue(bag.args, "-define", "COMPILE::JS,true"); bag.args = ArgumentUtil.addValue(bag.args, "-define", "COMPILE::JS,false", true); bag.args = ArgumentUtil.addValue(bag.args, "-define", "COMPILE::AS3,true", true); } bag.args = ArgumentUtil.removeElement(bag.args, "-js-output-type"); } private static List<ConfigurationBuffer> loadConfig(String[] args) throws org.apache.flex.compiler.exceptions.ConfigurationException { List<ConfigurationBuffer> configurationBuffers = null; final Collection<String> configFilePaths = ArgumentUtil.getValues(args, "-load-config"); if (configFilePaths != null) { for (String configFilePath : configFilePaths) { final File configFile = new File(configFilePath); final FileSpecification fileSpecification = new FileSpecification(configFile.getAbsolutePath()); final ConfigurationBuffer cfgbuf = createConfigurationBuffer(Configuration.class); FileConfigurator.load(cfgbuf, fileSpecification, new File(configFile.getPath()).getParent(), "flex-config", false); if (configurationBuffers == null) { configurationBuffers = new ArrayList<ConfigurationBuffer>(0); } configurationBuffers.add(cfgbuf); } } return configurationBuffers; } private static ConfigurationBuffer createConfigurationBuffer(Class<? extends Configuration> configurationClass) { return new ConfigurationBuffer(configurationClass, Configuration.getAliases()); } protected static int flexCompile(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { int exitCode; MXMLC mxmlc = COMPILER.newInstance(); exitCode = mxmlc.execute(args); processProblemReport(new CompilerRequestableProblems(mxmlc)); return exitCode; } public static Map<String, String> getLicenseMapFromFile(String fileName) throws ConfigurationException { Map<String, String> result = null; FileInputStream in = null; try { in = new FileInputStream(fileName); Properties properties = new Properties(); properties.load(in); Enumeration enumeration = properties.propertyNames(); if (enumeration.hasMoreElements()) { result = new HashMap<String, String>(); while (enumeration.hasMoreElements()) { String propertyName = (String) enumeration.nextElement(); result.put(propertyName, properties.getProperty(propertyName)); } } } catch (IOException ioException) { LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager(); throw new ConfigurationException(l10n.getLocalizedTextString(new FailedToLoadLicenseFile(fileName))); } finally { if (in != null) { try { in.close(); } catch (IOException ioe) { } } } return result; } public static class FailedToLoadLicenseFile extends CompilerError { private static final long serialVersionUID = -2980033917773108328L; public String fileName; public FailedToLoadLicenseFile(String fileName) { super(); this.fileName = fileName; } } public static void processProblemReport(ProblemQueryProvider requestableProblems) { for (ICompilerProblem problem : requestableProblems.getProblemQuery().getProblems()) { Class aClass = problem.getClass(); Annotation[] annotations = aClass.getAnnotations(); for (Annotation annotation : annotations) { if (annotation instanceof DefaultSeverity) { DefaultSeverity myAnnotation = (DefaultSeverity) annotation; CompilerProblemSeverity cps = myAnnotation.value(); String level; if (cps.equals(CompilerProblemSeverity.ERROR)) level = Message.ERROR; else if (cps.equals(CompilerProblemSeverity.WARNING)) level = Message.WARNING; else break; // skip if IGNORE? CompilerMessage msg = new CompilerMessage(level, problem.getSourcePath(), problem.getLine() + 1, problem.getColumn()); try { String errText = (String) aClass.getField("DESCRIPTION").get(aClass); while (errText.contains("${")) { int start = errText.indexOf("${"); int end = errText.indexOf("}", start); String token = errText.substring(start + 2, end); String value = (String) aClass.getField(token).get(problem); token = "${" + token + "}"; errText = errText.replace(token, value); } msg.setMessage(errText); logMessage(msg); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } private static void logMessage(CompilerMessage msg) { Logger logger = ThreadLocalToolkit.getLogger() != null ? ThreadLocalToolkit.getLogger() : new ConsoleLogger(); try { if (msg.getLevel().equals(Message.INFO)) { logger.logInfo(msg.getPath(), msg.getLine(), msg.getColumn(), msg.getMessage()); } else if (msg.getLevel().equals(Message.WARNING)) { logger.logWarning(msg.getPath(), msg.getLine(), msg.getColumn(), msg.getMessage()); } else if (msg.getLevel().equals(Message.ERROR)) { logger.logError(msg.getPath(), msg.getLine(), msg.getColumn(), msg.getMessage()); } } catch (Exception e) { System.out.println(msg.getMessage()); } } public static class NoUpdateMessage extends CompilerMessage.CompilerInfo { private static final long serialVersionUID = 6943388392279226490L; public String name; public NoUpdateMessage(String name) { this.name = name; } } static class CompilerRequestableProblems implements ProblemQueryProvider { private MXMLC mxmlc; public CompilerRequestableProblems(MXMLC mxmlc) { this.mxmlc = mxmlc; } @Override public ProblemQuery getProblemQuery() { return mxmlc.getProblems(); } } protected static class ArgumentBag { public String[] args; public String outputAlias; public String oldOutputPath; public String newOutputPath; public boolean isCommandLineOutput; public ArgumentBag(String[] args) { this.args = args; } } }