| /* |
| * |
| * 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.oem; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.FilenameFilter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.RandomAccessFile; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import flash.util.Trace; |
| import flex2.compiler.CompilerAPI; |
| import flex2.compiler.CompilationUnit; |
| import flex2.compiler.CompilerException; |
| import flex2.compiler.CompilerSwcContext; |
| import flex2.compiler.FileSpec; |
| import flex2.compiler.ResourceBundlePath; |
| import flex2.compiler.ResourceContainer; |
| import flex2.compiler.Source; |
| import flex2.compiler.SourceList; |
| import flex2.compiler.SourcePath; |
| import flex2.compiler.SubCompiler; |
| import flex2.compiler.SymbolTable; |
| import flex2.compiler.Transcoder; |
| import flex2.compiler.common.CompilerConfiguration; |
| import flex2.compiler.common.FontsConfiguration; |
| import flex2.compiler.config.ConfigurationException; |
| import flex2.compiler.extensions.ExtensionManager; |
| import flex2.compiler.extensions.IApplicationExtension; |
| import flex2.compiler.i18n.I18nUtils; |
| import flex2.compiler.io.FileUtil; |
| import flex2.compiler.io.LocalFile; |
| import flex2.compiler.io.VirtualFile; |
| import flex2.compiler.swc.SwcCache; |
| import flex2.compiler.swc.SwcException; |
| import flex2.compiler.util.Benchmark; |
| import flex2.compiler.util.CompilerControl; |
| import flex2.compiler.util.MimeMappings; |
| import flex2.compiler.util.NameMappings; |
| import flex2.compiler.util.PerformanceData; |
| import flex2.compiler.util.QName; |
| import flex2.compiler.util.ThreadLocalToolkit; |
| import flex2.linker.LinkerAPI; |
| import flex2.linker.ConsoleApplication; |
| import flex2.linker.FlexMovie; |
| import flex2.linker.LinkerException; |
| import flex2.linker.SimpleMovie; |
| import flex2.tools.Mxmlc; |
| import flex2.tools.PostLink; |
| import flex2.tools.PreLink; |
| import flex2.tools.ToolsConfiguration; |
| import flex2.tools.WebTierAPI; |
| import flex2.tools.oem.internal.ApplicationCompilerConfiguration; |
| import flex2.tools.oem.internal.ApplicationData; |
| import flex2.tools.oem.internal.OEMConfiguration; |
| import flex2.tools.oem.internal.OEMReport; |
| import flex2.tools.oem.internal.OEMUtil; |
| import macromedia.asc.util.ContextStatics; |
| |
| /** |
| * The <code>Application</code> class represents a Flex application. It implements the <code>Builder</code> interface |
| * which allows for building the application incrementally. There are many ways to define |
| * a Flex application. The most common way is specify the location of the target source file |
| * on disk: |
| * |
| * <pre> |
| * Application app = new Application(new File("MyApp.mxml")); |
| * </pre> |
| * |
| * Before the <code>Application</code> object starts the compilation, it must be configured. The most common methods that the client |
| * calls are <code>setLogger()</code>, <code>setConfiguration()</code>, and <code>setOutput()</code>. |
| * |
| * A logger must implement <code>flex2.tools.oem.Logger</code> and use the implementation as the Logger |
| * for the compilation. The following is an example <code>Logger</code> implementation: |
| * |
| * <pre> |
| * app.setLogger(new flex2.tools.oem.Logger() |
| * { |
| * public void log(Message message, int errorCode, String source) |
| * { |
| * System.out.println(message); |
| * } |
| * }); |
| * </pre> |
| * |
| * To specify compiler options for the <code>Application</code> object, the client |
| * must get a <code>Configuration</code> object populated with default values. Then, the client can set |
| * compiler options programmatically. |
| * |
| * The <code>setOutput()</code> method lets clients specify where the <code>Application</code> object should write |
| * the output to. If you call the <code>setOutput()</code> method, the <code>build(boolean)</code> method builds and |
| * writes directly to the location specified by the <code>setOutput()</code> method. For example: |
| * |
| * <pre> |
| * app.setOutput(new File("MyApp.swf")); |
| * app.build(true); |
| * </pre> |
| * |
| * If you do not call the <code>setOutput()</code> method, the client can use the <code>build(OutputStream, boolean)</code> method |
| * which requires the client to provide a buffered output stream. For example: |
| * |
| * <pre> |
| * app.build(new BufferedOutputStream(new FileOutputStream("MyApp.swf")), true); |
| * </pre> |
| * |
| * Before the <code>Application</code> object is thrown away, it is possible to save the compilation |
| * data for reuse by using the <code>save(OutputStream)</code> method. Subsequent compilations can use the |
| * <code>load(OutputStream)</code> method to get the old data into the <code>Application</code> object. |
| * |
| * <pre> |
| * app.save(new BufferedOutputStream(new FileOutputStream("MyApp.incr"))); |
| * </pre> |
| * |
| * When a cache file (such as <code>MyApp.incr</code>) is available from a previous compilation, the client can |
| * call the <code>load(OutputStream)</code> method before calling the <code>build(boolean)</code> method. For example: |
| * |
| * <pre> |
| * app.load(new BufferedInputStream(FileInputStream("MyApp.incr"))); |
| * app.build(); |
| * </pre> |
| * |
| * The <code>build(false)</code> and <code>build(OutputStream, false)</code> methods always rebuild the application. If the <code>Application</code> |
| * object is new, the first <code>build(true)/build(OutputStream, true)</code> method call performs a full build, which |
| * is equivalent to <code>build(false)/build(OutputStream, false)</code>, respectively. After a call to the <code>clean()</code> method, |
| * the <code>Application</code> object always performs a full build. |
| * |
| * <p> |
| * The <code>clean()</code> method not only cleans up compilation data in the <code>Application</code> object, but also the output |
| * file if the <code>setOutput()</code> method was called. |
| * |
| * <p> |
| * The <code>Application</code> class also supports building applications from a combination of source |
| * files from the file system and in-memory, dynamically-generated source objects. The client |
| * must use the <code>Application(String, VirtualLocalFile)</code> or <code>Application(String, VirtualLocalFile[])</code> constructors. |
| * |
| * <p> |
| * The <code>Application</code> class can be part of a <code>Project</code>. For more information, see the <code>Project</code> class's description. |
| * |
| * @see flex2.tools.oem.Configuration |
| * @see flex2.tools.oem.Project |
| * @version 2.0.1 |
| */ |
| public class Application implements Builder |
| { |
| static |
| { |
| // find all the compiler temp files. |
| File[] list = null; |
| try |
| { |
| File tempDir = File.createTempFile("Flex2_", "").getParentFile(); |
| list = tempDir.listFiles(new FilenameFilter() |
| { |
| public boolean accept(File dir, String name) |
| { |
| return name.startsWith("Flex2_"); |
| } |
| }); |
| } |
| catch (Throwable e) |
| { |
| } |
| |
| // get rid of compiler temp files. |
| for (int i = 0, len = list == null ? 0 : list.length; i < len; i++) |
| { |
| try { list[i].delete(); } catch (Throwable t) {} |
| } |
| |
| // use the protection domain to find the location of flex-compiler-oem.jar. |
| URL url = Application.class.getProtectionDomain().getCodeSource().getLocation(); |
| try |
| { |
| File f = new File(new URI(url.toExternalForm())); |
| if (f.getAbsolutePath().endsWith("flex-compiler-oem.jar")) |
| { |
| // use the location of flex-compiler-oem.jar to set application.home |
| // assume that the jar file is in <application.home>/lib/flex-compiler-oem.jar |
| String applicationHome = f.getParentFile().getParent(); |
| System.setProperty("application.home", applicationHome); |
| } |
| } |
| catch (URISyntaxException ex) |
| { |
| } |
| catch (IllegalArgumentException ex) |
| { |
| } |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param file The target source file. |
| * @throws FileNotFoundException Thrown when the specified source file does not exist. |
| */ |
| public Application(File file) throws FileNotFoundException |
| { |
| this(file, null); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param file The target source file. |
| * @param libraryCache A reference to a LibraryCache object. After |
| * building this Application object the cache may be saved |
| * and used to compile another Application object that uses |
| * a similar library path. |
| * @throws FileNotFoundException Thrown when the specified source file does not exist. |
| * @since 3.0 |
| */ |
| public Application(File file, LibraryCache libraryCache) throws FileNotFoundException |
| { |
| if (file.exists()) |
| { |
| init(new VirtualFile[] { new LocalFile(FileUtil.getCanonicalFile(file)) }); |
| } |
| else |
| { |
| throw new FileNotFoundException(FileUtil.getCanonicalPath(file)); |
| } |
| |
| this.libraryCache = libraryCache; |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param file An in-memory source object. |
| */ |
| public Application(VirtualLocalFile file) |
| { |
| init(new VirtualFile[] { file }); |
| } |
| |
| /** |
| * Constructor. |
| * |
| * @param files An array of in-memory source objects. The last element in the array is the target source object. |
| */ |
| public Application(VirtualLocalFile[] files) |
| { |
| init(files); |
| } |
| |
| /** |
| * Constructor. Use to build resource modules which don't have a target |
| * source file. |
| * |
| */ |
| public Application() |
| { |
| init(new VirtualFile[0]); |
| } |
| |
| /** |
| * |
| * @param files |
| */ |
| private void init(VirtualFile[] files) |
| { |
| this.files = new ArrayList(files.length); |
| for (int i = 0, length = files.length; i < length; i++) |
| { |
| this.files.add(files[i]); |
| } |
| oemConfiguration = null; |
| logger = null; |
| output = null; |
| mimeMappings = new MimeMappings(); |
| meter = null; |
| resolver = null; |
| cc = new CompilerControl(); |
| isGeneratedTargetFile = false; |
| |
| data = null; |
| cacheName = null; |
| configurationReport = null; |
| messages = new ArrayList<Message>(); |
| } |
| |
| private List<VirtualFile> files; |
| private OEMConfiguration oemConfiguration; |
| private Logger logger; |
| private File output; |
| private MimeMappings mimeMappings; |
| private ProgressMeter meter; |
| protected PathResolver resolver; |
| private CompilerControl cc; |
| private boolean isGeneratedTargetFile; |
| private ApplicationCache applicationCache; |
| private LibraryCache libraryCache; |
| |
| // clean() would null out the following variables. |
| private ApplicationData data; |
| private String cacheName, configurationReport; |
| private List<Message> messages; |
| private HashMap<String, PerformanceData[]> compilerBenchmarks; |
| private Benchmark benchmark; |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setConfiguration(Configuration configuration) |
| { |
| oemConfiguration = (OEMConfiguration) configuration; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Configuration getDefaultConfiguration() |
| { |
| return getDefaultConfiguration(false); |
| } |
| |
| /** |
| * |
| * @param processDefaults |
| * @return |
| */ |
| private Configuration getDefaultConfiguration(boolean processDefaults) |
| { |
| return OEMUtil.getApplicationConfiguration(constructCommandLine(null), false, false, |
| OEMUtil.getLogger(logger, messages), resolver, |
| mimeMappings, processDefaults); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Map<String, PerformanceData[]> getCompilerBenchmarks() |
| { |
| return compilerBenchmarks; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Benchmark getBenchmark() |
| { |
| return benchmark; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Configuration getConfiguration() |
| { |
| return oemConfiguration; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setLogger(Logger logger) |
| { |
| this.logger = logger; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Logger getLogger() |
| { |
| return logger; |
| } |
| |
| /** |
| * Sets the location of the compiler's output. This method is necessary if you call the <code>build(boolean)</code> method. |
| * If you use the <code>build(OutputStream, boolean)</code> method, in which an output stream |
| * is provided, there is no need to use this method. |
| * |
| * @param output An instance of the <code>java.io.File</code> class. |
| */ |
| public void setOutput(File output) |
| { |
| this.output = output; |
| } |
| |
| /** |
| * Gets the output destination. This method returns <code>null</code> if the <code>setOutput()</code> method was not called. |
| * |
| * @return An instance of the <code>java.io.File</code> class, or <code>null</code> if you did not call the <code>setOutput()</code> method. |
| */ |
| public File getOutput() |
| { |
| return output; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setSupportedFileExtensions(String mimeType, String[] extensions) |
| { |
| mimeMappings.set(mimeType, extensions); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setProgressMeter(ProgressMeter meter) |
| { |
| this.meter = meter; |
| } |
| |
| /** |
| * @inheritDoc |
| * @since 3.0 |
| */ |
| public void setPathResolver(PathResolver resolver) |
| { |
| this.resolver = resolver; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| // IMPORTANT: If you make changes here, you probably want to mirror them in Library.build() |
| public long build(boolean incremental) throws IOException |
| { |
| if (output != null) |
| { |
| InputStream tempIn = null; |
| ByteArrayOutputStream tempOut = null; |
| OutputStream out = null; |
| long size = 0; |
| |
| //TODO PERFORMANCE: A lot of unnecessary recopying and buffering here |
| try |
| { |
| int result = compile(incremental); |
| |
| if (result == SKIP || result == LINK || result == OK) |
| { |
| // write to a temp buffer... |
| tempOut = new ByteArrayOutputStream(); |
| size = (result == OK || result == LINK) ? link(tempOut) : encode(tempOut); |
| tempOut.flush(); |
| |
| if (size > 0) |
| { |
| tempIn = new ByteArrayInputStream(tempOut.toByteArray()); |
| out = new BufferedOutputStream(new FileOutputStream(output)); |
| FileUtil.streamOutput(tempIn, out); |
| } |
| } |
| |
| return size; |
| } |
| catch (Throwable t) |
| { |
| ThreadLocalToolkit.logError(t.getLocalizedMessage()); |
| return 0; |
| } |
| finally |
| { |
| if (tempIn != null) { try { tempIn.close(); } catch (Exception ex) {} } |
| if (tempOut != null) { try { tempOut.close(); } catch (Exception ex) {} } |
| if (out != null) { try { out.close(); } catch (Exception ex) {} } |
| |
| if ((benchmark != null) && benchmark.hasStarted(Benchmark.POSTCOMPILE)) |
| { |
| benchmark.stopTime(Benchmark.POSTCOMPILE, false); |
| } |
| |
| runExtensions(); |
| |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| } |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| private void runExtensions() |
| { |
| if (oemConfiguration != null) |
| { |
| Set<IApplicationExtension> extensions = ExtensionManager.getApplicationExtensions(oemConfiguration.getExtensions()); |
| |
| for ( IApplicationExtension extension : extensions ) |
| { |
| if (ThreadLocalToolkit.errorCount() == 0) |
| { |
| extension.run( (Configuration) oemConfiguration.clone() ); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public long build(OutputStream out, boolean incremental) throws IOException |
| { |
| try |
| { |
| int result = compile(incremental); |
| if (result == OK || result == LINK) |
| { |
| runExtensions(); |
| return link(out); |
| } |
| else if (result == SKIP) |
| { |
| runExtensions(); |
| return encode(out); |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| finally |
| { |
| if ((benchmark != null) && benchmark.hasStarted(Benchmark.POSTCOMPILE)) |
| { |
| benchmark.stopTime(Benchmark.POSTCOMPILE, false); |
| } |
| |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void stop() |
| { |
| cc.stop(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void clean() |
| { |
| clean(true /* cleanData */, |
| true /* cleanCache */, |
| true /* cleanOutput */, |
| true /* cleanConfig */, |
| true /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void load(InputStream in) throws IOException |
| { |
| try |
| { |
| cacheName = OEMUtil.load(in, cacheName); |
| } |
| finally |
| { |
| clean(true /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public long save(OutputStream out) throws IOException |
| { |
| return OEMUtil.save(out, cacheName, data); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Report getReport() |
| { |
| OEMUtil.setupLocalizationManager(); |
| return new OEMReport(data == null ? null : data.sources, |
| data == null ? null : data.movie, |
| data == null ? null : data.configuration, |
| data == null ? null : data.sourceList, |
| configurationReport, |
| messages); |
| } |
| |
| private void setupFontManager(OEMConfiguration localOEMConfiguration) |
| { |
| if (localOEMConfiguration != null && data != null) |
| { |
| FontsConfiguration fontsConfiguration = localOEMConfiguration.configuration.getCompilerConfiguration().getFontsConfiguration(); |
| fontsConfiguration.setTopLevelManager(data.fontManager); |
| } |
| } |
| |
| /** |
| * @param configuration |
| * @return true, unless a CompilerException occurs. |
| */ |
| private boolean setupSourceContainers(OEMConfiguration localOEMConfiguration) |
| { |
| ToolsConfiguration configuration = localOEMConfiguration.configuration; |
| CompilerConfiguration compilerConfig = configuration.getCompilerConfiguration(); |
| VirtualFile[] asClasspath = compilerConfig.getSourcePath(); |
| boolean result = false; |
| |
| try |
| { |
| // If there are no files that means this is a resource module and this |
| // is the first time compiling the module. When the |
| // ApplicationCompilerConfiguration was generated the validate() would |
| // have failed if there were no source files and no included resource |
| // bundles. See ApplicationCompilerConfiguration.getTargetFile() to |
| // see how the resource module is initially generated. |
| if (files.size() == 0) |
| { |
| ApplicationCompilerConfiguration acc = (ApplicationCompilerConfiguration)localOEMConfiguration.configuration; |
| files.add(CompilerAPI.getVirtualFile(acc.getTargetFile(), true)); |
| isGeneratedTargetFile = true; |
| } |
| else if (isGeneratedTargetFile) |
| { |
| // The resource module file has already been generated but we need to |
| // regenerate it to do a fresh compile. This file is impacted if |
| // either the locales or bundleNames have changed. |
| I18nUtils.regenerateResourceModule((ApplicationCompilerConfiguration)localOEMConfiguration.configuration); |
| } |
| |
| VirtualFile targetFile = (VirtualFile) files.get(files.size() - 1); |
| |
| WebTierAPI.checkSupportedTargetMimeType(targetFile); |
| |
| // create a FileSpec... |
| data.fileSpec = new FileSpec(Collections.<VirtualFile>emptyList(), WebTierAPI.getFileSpecMimeTypes()); |
| |
| // create a SourceList |
| data.sourceList = new SourceList(files, asClasspath, targetFile, WebTierAPI.getSourcePathMimeTypes()); |
| |
| // create a SourcePath... |
| data.sourcePath = new SourcePath(asClasspath, targetFile, WebTierAPI.getSourcePathMimeTypes(), |
| compilerConfig.allowSourcePathOverlap()); |
| |
| // create a ResourceContainer... |
| data.resources = new ResourceContainer(); |
| |
| if (applicationCache != null) |
| { |
| if (applicationCache.isConsistent(localOEMConfiguration.configuration)) |
| { |
| data.resources.setApplicationCache(applicationCache); |
| data.sourceList.applyApplicationCache(applicationCache); |
| data.sourcePath.setApplicationCache(applicationCache); |
| } |
| else |
| { |
| applicationCache.clear(); |
| } |
| } |
| |
| // create a ResourceBundlePath... |
| data.bundlePath = new ResourceBundlePath(compilerConfig, targetFile); |
| |
| // clear these... |
| if (data.sources != null) data.sources.clear(); |
| if (data.units != null) data.units.clear(); |
| if (data.swcDefSignatureChecksums != null) data.swcDefSignatureChecksums.clear(); |
| if (data.swcFileChecksums != null) data.swcFileChecksums.clear(); |
| |
| result = true; |
| } |
| catch (CompilerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| catch (ConfigurationException e) |
| { |
| ThreadLocalToolkit.logInfo(e.getMessage()); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Swap in cached sources from previous compiles, which occurred |
| * within the same workspace. |
| */ |
| private boolean loadCachedSources(Map<String, Source> sources) |
| { |
| boolean relink = false; |
| |
| for (Map.Entry<String, Source> entry : sources.entrySet()) |
| { |
| String className = entry.getKey(); |
| Source source = entry.getValue(); |
| Source cachedSource = applicationCache.getSource(className); |
| |
| if ((cachedSource != null) && !cachedSource.isUpdated()) |
| { |
| CompilationUnit compilationUnit = source.getCompilationUnit(); |
| VirtualFile pathRoot = source.getPathRoot(); |
| CompilationUnit cachedCompilationUnit = cachedSource.getCompilationUnit(); |
| VirtualFile cachedSourcePathRoot = cachedSource.getPathRoot(); |
| |
| if ((((pathRoot == null) && (cachedSourcePathRoot == null)) || |
| ((pathRoot != null) && pathRoot.equals(cachedSource.getPathRoot()))) && |
| (compilationUnit != null) && !compilationUnit.hasTypeInfo && |
| (cachedCompilationUnit != null) && cachedCompilationUnit.hasTypeInfo) |
| { |
| Source.copyCompilationUnit(cachedCompilationUnit, compilationUnit, true); |
| source.setFileTime(cachedSource.getFileTime()); |
| source.reused(); |
| relink = true; |
| } |
| } |
| } |
| |
| return relink; |
| } |
| |
| /** |
| * @param configuration |
| * @return true, unless an IOException occurs and the source containers can't be setup. |
| */ |
| private boolean loadCompilationUnits(OEMConfiguration localOEMConfiguration, CompilerSwcContext swcContext, int[] checksums) |
| { |
| ToolsConfiguration configuration = localOEMConfiguration.configuration; |
| |
| if (data.cacheName == null) // note: NOT (cacheName == null) |
| { |
| return true; |
| } |
| |
| RandomAccessFile cacheFile = null; |
| |
| try |
| { |
| cacheFile = new RandomAccessFile(data.cacheName, "r"); |
| CompilerAPI.loadCompilationUnits(configuration, data.fileSpec, data.sourceList, data.sourcePath, |
| data.resources, data.bundlePath, data.sources = new ArrayList<Source>(), |
| data.units = new ArrayList<CompilationUnit>(), checksums, |
| data.swcDefSignatureChecksums = new HashMap<QName, Long>(), |
| data.swcFileChecksums = new HashMap<String, Long>(), |
| cacheFile, data.cacheName, data.fontManager); |
| } |
| catch (FileNotFoundException ex) |
| { |
| ThreadLocalToolkit.logInfo(ex.getMessage()); |
| } |
| catch (IOException ex) |
| { |
| ThreadLocalToolkit.logInfo(ex.getMessage()); |
| |
| if (!setupSourceContainers(localOEMConfiguration)) |
| { |
| return false; |
| } |
| } |
| finally |
| { |
| if (cacheFile != null) try { cacheFile.close(); } catch (IOException ex) {} |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Compiles the <code>Application</code> object. This method does not link the <code>Application</code>. |
| * |
| * @param incremental If <code>true</code>, build incrementally; if <code>false</code>, rebuild. |
| * @return {@link Builder#OK} if this method call resulted in compilation of some/all parts of the application; |
| * {@link Builder#LINK} if this method call did not compile anything in the application but advise the caller to link again; |
| * {@link Builder#SKIP} if this method call did not compile anything in the application; |
| * {@link Builder#FAIL} if this method call encountered errors during compilation. |
| */ |
| protected int compile(boolean incremental) |
| { |
| try |
| { |
| messages.clear(); |
| |
| // if there is no configuration, use the default... but don't populate this.configuration. |
| OEMConfiguration tempOEMConfiguration; |
| if (oemConfiguration == null) |
| { |
| tempOEMConfiguration = (OEMConfiguration) getDefaultConfiguration(true); |
| } |
| else |
| { |
| tempOEMConfiguration = OEMUtil.getApplicationConfiguration(constructCommandLine(oemConfiguration), |
| oemConfiguration.keepLinkReport(), |
| oemConfiguration.keepSizeReport(), |
| OEMUtil.getLogger(logger, messages), |
| resolver, mimeMappings); |
| } |
| |
| // if c is null, which indicates problems, this method will return. |
| if (tempOEMConfiguration == null) |
| { |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| return FAIL; |
| } |
| else if (oemConfiguration != null && oemConfiguration.keepConfigurationReport()) |
| { |
| configurationReport = OEMUtil.formatConfigurationBuffer(tempOEMConfiguration.cfgbuf); |
| } |
| |
| setupFontManager(tempOEMConfiguration); |
| |
| if (oemConfiguration != null) |
| { |
| oemConfiguration.cfgbuf = tempOEMConfiguration.cfgbuf; |
| } |
| |
| if (tempOEMConfiguration.configuration.benchmark()) |
| { |
| benchmark = CompilerAPI.runBenchmark(); |
| benchmark.setTimeFilter(tempOEMConfiguration.configuration.getBenchmarkTimeFilter()); |
| benchmark.startTime(Benchmark.PRECOMPILE); |
| } |
| else |
| { |
| CompilerAPI.disableBenchmark(); |
| } |
| |
| // initialize some ThreadLocal variables... |
| cc.run(); |
| OEMUtil.init(OEMUtil.getLogger(logger, messages), mimeMappings, meter, resolver, cc); |
| |
| Map licenseMap = OEMUtil.getLicenseMap(tempOEMConfiguration.configuration); |
| |
| if (data == null || !incremental) |
| { |
| String compilationType = (cacheName != null) ? "inactive" : "full"; |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Starting " + compilationType + " compile for " + getOutput(), true); |
| } |
| |
| int returnValue = recompile(false, licenseMap, tempOEMConfiguration); |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending " + compilationType + " compile for " + getOutput(), true); |
| } |
| |
| clean(returnValue == FAIL /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| return returnValue; |
| } |
| |
| CompilerAPI.setupHeadless(tempOEMConfiguration.configuration); |
| |
| CompilerConfiguration compilerConfig = tempOEMConfiguration.configuration.getCompilerConfiguration(); |
| NameMappings mappings = CompilerAPI.getNameMappings(tempOEMConfiguration.configuration); |
| |
| Transcoder[] transcoders = WebTierAPI.getTranscoders(tempOEMConfiguration.configuration); |
| SubCompiler[] compilers = WebTierAPI.getCompilers(compilerConfig, mappings, transcoders); |
| |
| CompilerSwcContext swcContext = new CompilerSwcContext(true); |
| try |
| { |
| swcContext.load( compilerConfig.getLibraryPath(), |
| flex2.compiler.common.Configuration.getAllExcludedLibraries(compilerConfig, tempOEMConfiguration.configuration), |
| compilerConfig.getThemeFiles(), |
| compilerConfig.getIncludeLibraries(), |
| mappings, |
| I18nUtils.getTranslationFormat(compilerConfig), |
| data.swcCache ); |
| } |
| catch (SwcException ex) |
| { |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| return FAIL; |
| } |
| |
| // save the generated cache if the caller provided a libraryCache. |
| if (libraryCache != null) |
| { |
| libraryCache.setSwcCache(data.swcCache); |
| } |
| |
| data.includes = new HashSet<String>(swcContext.getIncludes()); |
| data.excludes = new HashSet<String>(swcContext.getExterns()); |
| tempOEMConfiguration.configuration.addExterns( swcContext.getExterns() ); |
| tempOEMConfiguration.configuration.addIncludes( swcContext.getIncludes() ); |
| tempOEMConfiguration.configuration.getCompilerConfiguration().addThemeCssFiles( swcContext.getThemeStyleSheets() ); |
| |
| // recompile or incrementally compile... |
| if (OEMUtil.isRecompilationNeeded(data, swcContext, tempOEMConfiguration)) |
| { |
| data.resources = new ResourceContainer(); |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Starting full compile for " + getOutput(), true); |
| } |
| |
| clean(true /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| int returnValue = recompile(true, licenseMap, tempOEMConfiguration); |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending full compile for " + getOutput(), true); |
| } |
| |
| clean(returnValue == FAIL /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| return returnValue; |
| } |
| |
| if (benchmark != null) |
| { |
| // We aren't really starting the compile here, but it's |
| // the earliest that we know that it's going to be an |
| // active compilation. |
| benchmark.benchmark2("Starting active compile for " + getOutput(), true); |
| } |
| |
| boolean relink = false; |
| |
| if (applicationCache != null) |
| { |
| ContextStatics contextStatics = applicationCache.getContextStatics(); |
| data.perCompileData = contextStatics; |
| |
| if (applicationCache.isConsistent(tempOEMConfiguration.configuration)) |
| { |
| relink = (loadCachedSources(data.resources.sources()) || |
| loadCachedSources(data.sourceList.sources()) || |
| loadCachedSources(data.sourcePath.sources())); |
| } |
| else |
| { |
| applicationCache.clear(); |
| } |
| } |
| |
| // Clear out ASC's userDefined, so definitions from a |
| // previous compilation don't spill over into this one. |
| data.perCompileData.userDefined.clear(); |
| |
| data.sourcePath.clearCache(); |
| data.bundlePath.clearCache(); |
| data.resources.refresh(); |
| |
| // validate CompilationUnits |
| final int count = CompilerAPI.validateCompilationUnits(data.fileSpec, data.sourceList, data.sourcePath, data.bundlePath, |
| data.resources, swcContext, data.perCompileData, tempOEMConfiguration.configuration); |
| |
| if ((count > 0) || (data.swcChecksum != swcContext.checksum())) |
| { |
| data.configuration = tempOEMConfiguration.configuration; |
| data.linkChecksum = tempOEMConfiguration.cfgbuf.link_checksum_ts(); |
| data.swcChecksum = swcContext.checksum(); |
| |
| // create a symbol table |
| SymbolTable symbolTable = new SymbolTable(tempOEMConfiguration.configuration, data.perCompileData); |
| |
| data.sources = new ArrayList<Source>(); |
| data.units = compile(compilers, swcContext, symbolTable, mappings, licenseMap, data.sources); |
| |
| boolean forcedToStop = CompilerAPI.forcedToStop(); |
| if (data.units == null || forcedToStop) |
| { |
| data.sources = null; |
| } |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending active compile for " + getOutput(), true); |
| } |
| |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| |
| return (data.units != null && !forcedToStop) ? OK : FAIL; |
| } |
| else |
| { |
| if (benchmark != null) |
| { |
| benchmark.stopTime(Benchmark.PRECOMPILE, false); |
| benchmark.startTime(Benchmark.POSTCOMPILE); |
| } |
| |
| int retVal = SKIP; |
| if (data != null) |
| { |
| CompilerAPI.displayWarnings(data.units); |
| if ((data.linkChecksum != tempOEMConfiguration.cfgbuf.link_checksum_ts()) || relink) |
| { |
| retVal = LINK; |
| } |
| } |
| else |
| { |
| retVal = LINK; |
| } |
| |
| data.linkChecksum = tempOEMConfiguration.cfgbuf.link_checksum_ts(); |
| data.swcChecksum = swcContext.checksum(); |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending active compile for " + getOutput(), true); |
| } |
| |
| if (CompilerAPI.forcedToStop()) retVal = FAIL; |
| if (retVal != LINK) |
| { |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| } |
| |
| return retVal; |
| } |
| } |
| finally |
| { |
| // clean thread locals |
| OEMUtil.clean(); |
| } |
| } |
| |
| /** |
| * @param fullRecompile if true a full recompile is needed, do not attempted to use cache file. |
| * |
| * @return {@link Builder#OK} if this method call resulted in compilation of some/all parts of the application; |
| * {@link Builder#LINK} if this method call did not compile anything in the application but advise the caller to link again; |
| * {@link Builder#SKIP} if this method call did not compile anything in the application; |
| * {@link Builder#FAIL} if this method call encountered errors during compilation. |
| */ |
| private int recompile(boolean fullRecompile, Map licenseMap, OEMConfiguration localOEMConfiguration) |
| { |
| data = new ApplicationData(); |
| data.configuration = localOEMConfiguration.configuration; |
| data.cacheName = cacheName; |
| |
| CompilerAPI.setupHeadless(localOEMConfiguration.configuration); |
| |
| CompilerConfiguration compilerConfig = localOEMConfiguration.configuration.getCompilerConfiguration(); |
| NameMappings mappings = CompilerAPI.getNameMappings(localOEMConfiguration.configuration); |
| data.fontManager = compilerConfig.getFontsConfiguration().getTopLevelManager(); |
| |
| if (output != null) |
| { |
| OEMUtil.setGeneratedDirectory(compilerConfig, output); |
| } |
| |
| Transcoder[] transcoders = WebTierAPI.getTranscoders(localOEMConfiguration.configuration); |
| SubCompiler[] compilers = WebTierAPI.getCompilers(compilerConfig, mappings, transcoders); |
| |
| // NOT in compile |
| if (!setupSourceContainers(localOEMConfiguration)) |
| { |
| clean(true /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| return FAIL; |
| } |
| |
| // Setup SWC cache |
| if (libraryCache != null) |
| { |
| ContextStatics contextStatics = libraryCache.getContextStatics(); |
| |
| if (contextStatics != null) |
| { |
| // Clear out ASC's userDefined, so definitions from a |
| // previous compilation don't spill over into this one. |
| contextStatics.userDefined.clear(); |
| data.swcCache = libraryCache.getSwcCache(); |
| data.perCompileData = contextStatics; |
| } |
| } |
| |
| if (data.swcCache == null) |
| { |
| data.swcCache = new SwcCache(); |
| } |
| |
| // load SWCs |
| CompilerSwcContext swcContext = new CompilerSwcContext(true); |
| try |
| { |
| swcContext.load( compilerConfig.getLibraryPath(), |
| flex2.compiler.common.Configuration.getAllExcludedLibraries(compilerConfig, localOEMConfiguration.configuration), |
| compilerConfig.getThemeFiles(), |
| compilerConfig.getIncludeLibraries(), |
| mappings, |
| I18nUtils.getTranslationFormat(compilerConfig), |
| data.swcCache ); |
| } |
| catch (SwcException ex) |
| { |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| return FAIL; |
| } |
| |
| // save the generated swcCache if the class has a libraryCache. |
| if (libraryCache != null) |
| { |
| libraryCache.setSwcCache(data.swcCache); |
| } |
| |
| data.includes = new HashSet<String>(swcContext.getIncludes()); |
| data.excludes = new HashSet<String>(swcContext.getExterns()); |
| localOEMConfiguration.configuration.addExterns( swcContext.getExterns() ); |
| localOEMConfiguration.configuration.addIncludes( swcContext.getIncludes() ); |
| localOEMConfiguration.configuration.getCompilerConfiguration().addThemeCssFiles( swcContext.getThemeStyleSheets() ); |
| |
| data.cmdChecksum = localOEMConfiguration.cfgbuf.checksum_ts(); // OEMUtil.calculateChecksum(data, swcContext, c); |
| data.linkChecksum = localOEMConfiguration.cfgbuf.link_checksum_ts(); |
| data.swcChecksum = swcContext.checksum(); |
| int[] checksums = new int[] { 0, data.cmdChecksum, data.linkChecksum, data.swcChecksum }; |
| boolean relink = false; |
| |
| // C: must do loadCompilationUnits() after checksum calculation... |
| if (!fullRecompile) |
| { |
| if (!loadCompilationUnits(localOEMConfiguration, swcContext, checksums)) |
| { |
| clean(true /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| return FAIL; |
| } |
| |
| data.checksum = checksums[0]; |
| if (data.units != null && |
| data.units.size() > 0 && |
| OEMUtil.isRecompilationNeeded(data, swcContext, localOEMConfiguration)) |
| { |
| if (!setupSourceContainers(localOEMConfiguration)) |
| { |
| clean(true /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| return FAIL; |
| } |
| } |
| |
| if (applicationCache != null) |
| { |
| ContextStatics contextStatics = applicationCache.getContextStatics(); |
| |
| if (contextStatics != null) |
| { |
| // Clear out ASC's userDefined, so definitions |
| // from a previous compilation don't spill over |
| // into this one. |
| contextStatics.userDefined.clear(); |
| data.perCompileData = contextStatics; |
| |
| if (applicationCache.isConsistent(localOEMConfiguration.configuration)) |
| { |
| relink = (loadCachedSources(data.resources.sources()) || |
| loadCachedSources(data.sourceList.sources()) || |
| loadCachedSources(data.sourcePath.sources())); |
| } |
| else |
| { |
| applicationCache.clear(); |
| } |
| } |
| } |
| } |
| |
| // validate CompilationUnits... |
| int count = CompilerAPI.validateCompilationUnits(data.fileSpec, data.sourceList, |
| data.sourcePath, data.bundlePath, |
| data.resources, swcContext, |
| data.perCompileData, |
| localOEMConfiguration.configuration); |
| |
| SymbolTable symbolTable; |
| |
| if (data.perCompileData != null) |
| { |
| symbolTable = new SymbolTable(localOEMConfiguration.configuration, data.perCompileData); |
| } |
| else |
| { |
| symbolTable = new SymbolTable(localOEMConfiguration.configuration); |
| data.perCompileData = symbolTable.perCompileData; |
| } |
| |
| if (applicationCache != null) |
| { |
| applicationCache.setConfiguration(localOEMConfiguration.configuration); |
| applicationCache.setContextStatics(data.perCompileData); |
| } |
| |
| if (libraryCache != null) |
| { |
| libraryCache.setContextStatics(data.perCompileData); |
| } |
| |
| data.sources = new ArrayList<Source>(); |
| data.units = compile(compilers, swcContext, symbolTable, mappings, licenseMap, data.sources); |
| |
| // need to update the checksum here since doing a compile could add some |
| // some signature checksums and change it. |
| data.checksum = OEMUtil.calculateChecksum(data, swcContext, localOEMConfiguration); |
| |
| int result = OK; |
| |
| if (data.units == null || CompilerAPI.forcedToStop()) |
| { |
| result = FAIL; |
| } |
| else if ((count == 0) && relink) |
| { |
| result = LINK; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @param swcContext |
| * @param symbolTable |
| * @param licenseMap |
| * @param sources |
| * @param OEMConfig |
| * @param isRecompile - true if called as part of a recompile, false if incremental compile. |
| * |
| * @return a list of CompilationUnit |
| */ |
| private List<CompilationUnit> compile(SubCompiler[] compilers, CompilerSwcContext swcContext, |
| SymbolTable symbolTable, NameMappings nameMappings, |
| Map licenseMap, List<Source> sources) |
| { |
| List<CompilationUnit> units = null; |
| |
| try |
| { |
| if (benchmark != null) |
| { |
| for (int i = 0; i < compilers.length; i++) |
| { |
| compilers[i].initBenchmarks(); |
| } |
| } |
| |
| ApplicationCompilerConfiguration config = (ApplicationCompilerConfiguration) data.configuration; |
| VirtualFile projector = config.getProjector(); |
| |
| if (benchmark != null) |
| { |
| benchmark.stopTime(Benchmark.PRECOMPILE, false); |
| } |
| |
| if (projector != null && projector.getName().endsWith("avmplus.exe")) |
| { |
| units = CompilerAPI.compile(data.fileSpec, data.sourceList, null, data.sourcePath, data.resources, data.bundlePath, |
| swcContext, symbolTable, nameMappings, data.configuration, compilers, |
| null, licenseMap, sources); |
| } |
| else |
| { |
| units = CompilerAPI.compile(data.fileSpec, data.sourceList, null, data.sourcePath, data.resources, data.bundlePath, |
| swcContext, symbolTable, nameMappings, data.configuration, compilers, |
| new PreLink(), licenseMap, sources); |
| } |
| |
| if (applicationCache != null) |
| { |
| data.resources.refresh(); |
| applicationCache.addSources(data.resources.sources()); |
| applicationCache.addSources(data.sourceList.sources()); |
| applicationCache.addSources(data.sourcePath.sources()); |
| } |
| |
| if (benchmark != null) |
| { |
| benchmark.startTime(Benchmark.POSTCOMPILE); |
| } |
| |
| if ((benchmark != null) && (ThreadLocalToolkit.getLogger() != null)) |
| { |
| if (compilerBenchmarks == null) |
| compilerBenchmarks = new HashMap<String, PerformanceData[]>(); |
| |
| compilerBenchmarks.clear(); |
| |
| flex2.compiler.Logger logger = ThreadLocalToolkit.getLogger(); |
| for (int i = 0; i < compilers.length; i++) |
| { |
| SubCompiler compiler = compilers[i]; |
| PerformanceData[] times = compiler.getBenchmarks(); |
| |
| if (times != null) |
| { |
| compiler.logBenchmarks(logger); |
| String compilerName = compiler.getName(); |
| |
| assert(!compilerBenchmarks.containsKey(compilerName)); |
| compilerBenchmarks.put(compilerName, times); |
| } |
| |
| // Now check for any embedded compilers and get their phase times. |
| // "synthesize" compiler name by appending _ebm to main compiler name |
| times = compiler.getEmbeddedBenchmarks(); |
| if (times != null) |
| { |
| compiler.logBenchmarks(logger); |
| String compilerName = compiler.getName(); |
| compilerName += "_emb"; |
| |
| assert(!compilerBenchmarks.containsKey(compilerName)); |
| compilerBenchmarks.put(compilerName, times); |
| } |
| } |
| } |
| } |
| catch (CompilerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| finally |
| { |
| data.sourcePath.clearCache(); |
| data.bundlePath.clearCache(); |
| data.resources.refresh(); |
| |
| OEMUtil.saveSwcFileChecksums(swcContext, data, data.configuration); |
| OEMUtil.saveSignatureChecksums(units, data, data.configuration); |
| |
| // Make sure the swcContext is closed so we don't leave any dangling file handles |
| swcContext.close(); |
| |
| } |
| |
| return units; |
| } |
| |
| /** |
| * Links the application. This method writes the output to the output stream specified by |
| * the client. You should use a buffered output stream for best performance. |
| * |
| * <p> |
| * This method is protected. In most circumstances, the client only needs to call the |
| * <code>build()</code> method. Subclasses can call this method so that it links and outputs |
| * the application without recompiling. |
| * |
| * @param out The <code>OutputStream</code>. |
| * @return The size of the application, in bytes. |
| * @throws IOException Thrown when an I/O error occurs during linking. |
| */ |
| protected long link(OutputStream out) throws IOException |
| { |
| if (data == null || data.units == null) |
| { |
| return 0; |
| } |
| |
| boolean hasChanged = (oemConfiguration == null) ? false : oemConfiguration.hasChanged(); |
| flex2.compiler.common.Configuration config = null; |
| |
| if (hasChanged) |
| { |
| OEMConfiguration tempOEMConfiguration; |
| tempOEMConfiguration = OEMUtil.getLinkerConfiguration(oemConfiguration.getLinkerOptions(), |
| oemConfiguration.keepLinkReport(), |
| oemConfiguration.keepSizeReport(), |
| OEMUtil.getLogger(logger, messages), |
| mimeMappings, resolver, |
| data.configuration, |
| oemConfiguration.newLinkerOptionsAfterCompile, |
| data.includes, data.excludes); |
| if (tempOEMConfiguration == null) |
| { |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| false /* cleanConfig */, |
| false /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| return 0; |
| } |
| |
| config = tempOEMConfiguration.configuration; |
| } |
| else |
| { |
| config = data.configuration; |
| } |
| |
| long size = 0; |
| |
| try |
| { |
| OEMUtil.init(OEMUtil.getLogger(logger, messages), mimeMappings, meter, resolver, cc); |
| |
| ApplicationCompilerConfiguration appConfig = (ApplicationCompilerConfiguration) data.configuration; |
| VirtualFile projector = appConfig.getProjector(); |
| PostLink postLink = null; |
| |
| if (config.optimize() && !config.debug()) |
| { |
| postLink = new PostLink(config); |
| } |
| |
| // link |
| if (projector != null && projector.getName().endsWith("avmplus.exe")) |
| { |
| ConsoleApplication temp = data.app; |
| data.app = LinkerAPI.linkConsole(data.units, postLink, config); |
| size = encodeConsoleProjector(projector, out); |
| if (hasChanged && temp != null) |
| { |
| data.app = temp; |
| } |
| } |
| else |
| { |
| SimpleMovie temp = data.movie; |
| data.movie = (FlexMovie) LinkerAPI.link(data.units, postLink, config); |
| size = (projector == null) ? encode(out) : encodeProjector(projector, out); |
| if (hasChanged && temp != null) |
| { |
| data.movie = temp; |
| } |
| } |
| } |
| catch (LinkerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| catch (Throwable t) |
| { |
| if (Trace.error) |
| { |
| t.printStackTrace(); |
| } |
| |
| ThreadLocalToolkit.logError(t.getLocalizedMessage()); |
| } |
| finally |
| { |
| // clean thread locals |
| OEMUtil.clean(); |
| } |
| |
| return size; |
| } |
| |
| /** |
| * |
| * @param out |
| * @return Number of bytes written to 'out' |
| * @throws IOException |
| */ |
| private long encode(OutputStream out) throws IOException |
| { |
| if (data == null || data.units == null || data.movie == null) |
| { |
| return 0; |
| } |
| |
| // if (ThreadLocalToolkit.getBenchmark() != null && |
| // ThreadLocalToolkit.getLocalizationManager() == null) |
| // { |
| // OEMUtil.init(OEMUtil.getLogger(logger, messages), mimeMappings, meter, resolver, cc); |
| // } |
| |
| //TODO PERFORMANCE: A lot of unnecessary recopying and buffering here |
| // output SWF |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| CompilerAPI.encode(data.configuration, data.movie, baos); |
| long size = baos.size(); |
| |
| baos.writeTo(out); |
| out.flush(); |
| |
| return size; |
| } |
| |
| /** |
| * |
| * @param projector |
| * @param out |
| * @return |
| * @throws IOException |
| */ |
| private long encodeProjector(VirtualFile projector, OutputStream out) throws IOException |
| { |
| if (data == null || data.units == null || data.movie == null) |
| { |
| return 0; |
| } |
| |
| // output EXE |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| CompilerAPI.encode(data.configuration, data.movie, baos); |
| return Mxmlc.createProjector(data.configuration, projector, baos, out); |
| } |
| |
| /** |
| * |
| * @param projector |
| * @param out |
| * @return |
| * @throws IOException |
| */ |
| private long encodeConsoleProjector(VirtualFile projector, OutputStream out) throws IOException |
| { |
| if (data == null || data.units == null || data.app == null) |
| { |
| return 0; |
| } |
| |
| // output EXE |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| CompilerAPI.encode(data.app, baos); |
| return Mxmlc.createProjector(data.configuration, projector, baos, out); |
| } |
| |
| /** |
| * |
| * @param cleanData |
| * @param cleanCache |
| * @param cleanOutput |
| * @param cleanConfig |
| * @param cleanMessages |
| * @param cleanThreadLocals |
| */ |
| private void clean(boolean cleanData, boolean cleanCache, boolean cleanOutput, |
| boolean cleanConfig, boolean cleanMessages, boolean cleanThreadLocals) |
| { |
| if (cleanThreadLocals) |
| { |
| OEMUtil.clean(); |
| } |
| |
| if (oemConfiguration != null && cleanConfig) |
| { |
| oemConfiguration.reset(); |
| } |
| |
| if (cleanData) |
| { |
| data = null; |
| configurationReport = null; |
| } |
| |
| if (cleanCache) |
| { |
| if (cacheName != null) |
| { |
| File dead = FileUtil.openFile(cacheName); |
| if (dead != null && dead.exists()) |
| { |
| dead.delete(); |
| } |
| cacheName = null; |
| } |
| } |
| |
| if (cleanOutput) |
| { |
| if (output != null && output.exists()) |
| { |
| output.delete(); |
| } |
| } |
| |
| if (cleanMessages) |
| { |
| messages.clear(); |
| } |
| } |
| |
| /** |
| * |
| * @param localOEMConfiguration |
| * @return |
| */ |
| private String[] constructCommandLine(OEMConfiguration localOEMConfiguration) |
| { |
| String[] options = (localOEMConfiguration != null) ? localOEMConfiguration.getCompilerOptions() : new String[0]; |
| String[] args = new String[options.length + files.size() + 1]; |
| System.arraycopy(options, 0, args, 0, options.length); |
| args[options.length] = "--" + Mxmlc.FILE_SPECS; |
| for (int i = 0, size = files.size(); i < size; i++) |
| { |
| args[options.length + 1 + i] = files.get(i).getName(); |
| } |
| |
| return args; |
| } |
| |
| /** |
| * Returns the cache of sources in the source list and source |
| * path. After building this Application object, the cache may be |
| * used to compile another Application object with common sources. |
| * |
| * @return The active cache. May be null. |
| * |
| * @since 4.5 |
| */ |
| public ApplicationCache getApplicationCache() |
| { |
| return applicationCache; |
| } |
| |
| /** |
| * Sets the cache for sources in the source list and source path. |
| * After compiling an Application object, the cache may be reused |
| * to build another Application object with common sources. |
| * |
| * @param applicationCache A reference to the application cache. |
| * |
| * @since 4.5 |
| */ |
| public void setApplicationCache(ApplicationCache applicationCache) |
| { |
| this.applicationCache = applicationCache; |
| } |
| |
| // TODO: deprecate getSwcCache() and setSwcCache(), then add |
| // getLibraryCache() and setLibraryCache(). |
| /** |
| * Get the cache of swcs in the library path. After building this Application |
| * object the cache may be saved and used to compile another Application object |
| * that uses the same library path. |
| * |
| * @return The active cache. May be null. |
| * |
| * @since 3.0 |
| */ |
| public LibraryCache getSwcCache() |
| { |
| return libraryCache; |
| } |
| |
| /** |
| * Set the cache for swcs in the library path. After compiling an |
| * Application object the cache may be reused to build another Application |
| * object that uses the same library path. |
| * |
| * @param libraryCache A reference to an allocated swc cache. |
| * |
| * @since 3.0 |
| */ |
| public void setSwcCache(LibraryCache libraryCache) |
| { |
| this.libraryCache = libraryCache; |
| } |
| } |