/* ******************************************************************* * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). * All rights reserved. * This program and the accompanying materials are made available * under the terms of the Eclipse Public License v1.0 * which accompanies this distribution and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * PARC initial implementation * ******************************************************************/ package org.aspectj.ajdt.internal.core.builder; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import org.aspectj.ajdt.internal.compiler.AjCompilerAdapter; import org.aspectj.ajdt.internal.compiler.AjPipeliningCompilerAdapter; import org.aspectj.ajdt.internal.compiler.IBinarySourceProvider; import org.aspectj.ajdt.internal.compiler.ICompilerAdapter; import org.aspectj.ajdt.internal.compiler.ICompilerAdapterFactory; import org.aspectj.ajdt.internal.compiler.IIntermediateResultsRequestor; import org.aspectj.ajdt.internal.compiler.IOutputClassFileNameProvider; import org.aspectj.ajdt.internal.compiler.InterimCompilationResult; import org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment; import org.aspectj.ajdt.internal.compiler.lookup.AnonymousClassPublisher; import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; import org.aspectj.ajdt.internal.compiler.problem.AjProblemReporter; import org.aspectj.asm.AsmManager; import org.aspectj.asm.IHierarchy; import org.aspectj.asm.IProgramElement; import org.aspectj.asm.internal.ProgramElement; import org.aspectj.bridge.AbortException; import org.aspectj.bridge.CountingMessageHandler; import org.aspectj.bridge.ILifecycleAware; import org.aspectj.bridge.IMessage; import org.aspectj.bridge.IMessageHandler; import org.aspectj.bridge.IProgressListener; import org.aspectj.bridge.Message; import org.aspectj.bridge.MessageUtil; import org.aspectj.bridge.SourceLocation; import org.aspectj.bridge.Version; import org.aspectj.bridge.context.CompilationAndWeavingContext; import org.aspectj.bridge.context.ContextFormatter; import org.aspectj.bridge.context.ContextToken; import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation; import org.aspectj.org.eclipse.jdt.core.compiler.IProblem; import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile; import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult; import org.aspectj.org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.aspectj.org.eclipse.jdt.internal.compiler.ICompilerRequestor; import org.aspectj.org.eclipse.jdt.internal.compiler.IProblemFactory; import org.aspectj.org.eclipse.jdt.internal.compiler.batch.ClasspathDirectory; import org.aspectj.org.eclipse.jdt.internal.compiler.batch.CompilationUnit; import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem; import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment; import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser; import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation; import org.aspectj.org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; import org.aspectj.tools.ajc.Main; import org.aspectj.util.FileUtil; import org.aspectj.weaver.Dump; import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.World; import org.aspectj.weaver.bcel.BcelWeaver; import org.aspectj.weaver.bcel.BcelWorld; import org.aspectj.weaver.bcel.UnwovenClassFile; import org.eclipse.core.runtime.OperationCanceledException; public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourceProvider,ICompilerAdapterFactory { private static final String CROSSREFS_FILE_NAME = "build.lst"; private static final String CANT_WRITE_RESULT = "unable to write compilation result"; private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; public static boolean COPY_INPATH_DIR_RESOURCES = false; // AJDT doesn't want this check, so Main enables it. private static boolean DO_RUNTIME_VERSION_CHECK = false; // If runtime version check fails, warn or fail? (unset?) static final boolean FAIL_IF_RUNTIME_NOT_FOUND = false; private static final FileFilter binarySourceFilter = new FileFilter() { public boolean accept(File f) { return f.getName().endsWith(".class"); }}; /** * This builder is static so that it can be subclassed and reset. However, note * that there is only one builder present, so if two extendsion reset it, only * the latter will get used. */ public static AsmHierarchyBuilder asmHierarchyBuilder = new AsmHierarchyBuilder(); static { CompilationAndWeavingContext.setMultiThreaded(false); CompilationAndWeavingContext.registerFormatter( CompilationAndWeavingContext.BATCH_BUILD, new AjBuildContexFormatter()); CompilationAndWeavingContext.registerFormatter( CompilationAndWeavingContext.INCREMENTAL_BUILD, new AjBuildContexFormatter()); } private IProgressListener progressListener = null; private boolean environmentSupportsIncrementalCompilation = false; private int compiledCount; private int sourceFileCount; private JarOutputStream zos; private boolean batchCompile = true; private INameEnvironment environment; private Map /* String -> List*/ binarySourcesForTheNextCompile = new HashMap(); // FIXME asc should this really be in here? private IHierarchy structureModel; public AjBuildConfig buildConfig; private boolean ignoreOutxml; private boolean wasFullBuild = true; // true if last build was a full build rather than an incremental build AjState state = new AjState(this); /** * Enable check for runtime version, used only by Ant/command-line Main. * @param main Main unused except to limit to non-null clients. */ public static void enableRuntimeVersionCheck(Main caller) { DO_RUNTIME_VERSION_CHECK = null != caller; } public BcelWeaver getWeaver() { return state.getWeaver();} public BcelWorld getBcelWorld() { return state.getBcelWorld();} public CountingMessageHandler handler; public AjBuildManager(IMessageHandler holder) { super(); this.handler = CountingMessageHandler.makeCountingMessageHandler(holder); } public void environmentSupportsIncrementalCompilation(boolean itDoes) { this.environmentSupportsIncrementalCompilation = itDoes; } /** @return true if we should generate a model as a side-effect */ public boolean doGenerateModel() { return buildConfig.isGenerateModelMode(); } public boolean batchBuild( AjBuildConfig buildConfig, IMessageHandler baseHandler) throws IOException, AbortException { return doBuild(buildConfig, baseHandler, true); } public boolean incrementalBuild( AjBuildConfig buildConfig, IMessageHandler baseHandler) throws IOException, AbortException { return doBuild(buildConfig, baseHandler, false); } /** @throws AbortException if check for runtime fails */ protected boolean doBuild( AjBuildConfig buildConfig, IMessageHandler baseHandler, boolean batch) throws IOException, AbortException { boolean ret = true; batchCompile = batch; wasFullBuild = batch; if (baseHandler instanceof ILifecycleAware) { ((ILifecycleAware)baseHandler).buildStarting(!batch); } CompilationAndWeavingContext.reset(); int phase = batch ? CompilationAndWeavingContext.BATCH_BUILD : CompilationAndWeavingContext.INCREMENTAL_BUILD; ContextToken ct = CompilationAndWeavingContext.enteringPhase(phase ,buildConfig); try { if (batch) { this.state = new AjState(this); } this.state.setCouldBeSubsequentIncrementalBuild(this.environmentSupportsIncrementalCompilation); boolean canIncremental = state.prepareForNextBuild(buildConfig); if (!canIncremental && !batch) { // retry as batch? CompilationAndWeavingContext.leavingPhase(ct); if (state.listenerDefined()) state.getListener().recordDecision("Falling back to batch compilation"); return doBuild(buildConfig, baseHandler, true); } this.handler = CountingMessageHandler.makeCountingMessageHandler(baseHandler); if (DO_RUNTIME_VERSION_CHECK) { String check = checkRtJar(buildConfig); if (check != null) { if (FAIL_IF_RUNTIME_NOT_FOUND) { MessageUtil.error(handler, check); CompilationAndWeavingContext.leavingPhase(ct); return false; } else { MessageUtil.warn(handler, check); } } } // if (batch) { setBuildConfig(buildConfig); //} if (batch || !AsmManager.attemptIncrementalModelRepairs) { // if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) { setupModel(buildConfig); // } } if (batch) { initBcelWorld(handler); } if (handler.hasErrors()) { CompilationAndWeavingContext.leavingPhase(ct); return false; } if (buildConfig.getOutputJar() != null) { if (!openOutputStream(buildConfig.getOutputJar())) { CompilationAndWeavingContext.leavingPhase(ct); return false; } } if (batch) { // System.err.println("XXXX batch: " + buildConfig.getFiles()); if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) { getWorld().setModel(AsmManager.getDefault().getHierarchy()); // in incremental build, only get updated model? } binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true); performCompilation(buildConfig.getFiles()); state.clearBinarySourceFiles(); // we don't want these hanging around... if (handler.hasErrors()) { CompilationAndWeavingContext.leavingPhase(ct); if (AsmManager.isReporting()) AsmManager.getDefault().reportModelInfo("After a failed batch build"); return false; } if (AsmManager.isReporting()) AsmManager.getDefault().reportModelInfo("After a batch build"); } else { // done already? // if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) { // bcelWorld.setModel(StructureModelManager.INSTANCE.getStructureModel()); // } // System.err.println("XXXX start inc "); binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true); List files = state.getFilesToCompile(true); if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) if (AsmManager.attemptIncrementalModelRepairs) AsmManager.getDefault().processDelta(files,state.getAddedFiles(),state.getDeletedFiles()); boolean hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty()); for (int i = 0; (i < 5) && hereWeGoAgain; i++) { if (state.listenerDefined()) state.getListener().recordInformation("Starting incremental compilation loop "+(i+1)+" of possibly 5"); // System.err.println("XXXX inc: " + files); performCompilation(files); if (handler.hasErrors() || (progressListener!=null && progressListener.isCancelledRequested())) { CompilationAndWeavingContext.leavingPhase(ct); return false; } if (state.requiresFullBatchBuild()) { if (state.listenerDefined()) state.getListener().recordInformation(" Dropping back to full build"); return batchBuild(buildConfig, baseHandler); } binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(false); files = state.getFilesToCompile(false); hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty()); // TODO Andy - Needs some thought here... // I think here we might want to pass empty addedFiles/deletedFiles as they were // dealt with on the first call to processDelta - we are going through this loop // again because in compiling something we found something else we needed to // rebuild. But what case causes this? if (hereWeGoAgain) { if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) if (AsmManager.attemptIncrementalModelRepairs) AsmManager.getDefault().processDelta(files,state.getAddedFiles(),state.getDeletedFiles()); } } if (!files.isEmpty()) { CompilationAndWeavingContext.leavingPhase(ct); return batchBuild(buildConfig, baseHandler); } else { if (AsmManager.isReporting()) AsmManager.getDefault().reportModelInfo("After an incremental build"); } } // XXX not in Mik's incremental if (buildConfig.isEmacsSymMode()) { new org.aspectj.ajdt.internal.core.builder.EmacsStructureModelManager().externalizeModel(); } // for bug 113554: support ajsym file generation for command line builds if (buildConfig.isGenerateCrossRefsMode()) { File configFileProxy = new File(buildConfig.getOutputDir(),CROSSREFS_FILE_NAME); AsmManager.getDefault().writeStructureModel(configFileProxy.getAbsolutePath()); } // have to tell state we succeeded or next is not incremental state.successfulCompile(buildConfig,batch); copyResourcesToDestination(); if (buildConfig.getOutxmlName() != null) { writeOutxmlFile(); } /*boolean weaved = *///weaveAndGenerateClassFiles(); // if not weaved, then no-op build, no model changes // but always returns true // XXX weaved not in Mik's incremental if (buildConfig.isGenerateModelMode()) { AsmManager.getDefault().fireModelUpdated(); } CompilationAndWeavingContext.leavingPhase(ct); } finally { if (baseHandler instanceof ILifecycleAware) { ((ILifecycleAware)baseHandler).buildFinished(!batch); } if (zos != null) { closeOutputStream(buildConfig.getOutputJar()); } ret = !handler.hasErrors(); if (getBcelWorld()!=null) getBcelWorld().tidyUp(); if (getWeaver()!=null) getWeaver().tidyUp(); // bug 59895, don't release reference to handler as may be needed by a nested call //handler = null; } return ret; } private String stringifyList(List l) { if (l==null) return ""; StringBuffer sb = new StringBuffer(); sb.append("{"); for (Iterator iter = l.iterator(); iter.hasNext();) { Object el = (Object) iter.next(); sb.append(el); if (iter.hasNext()) sb.append(","); } sb.append("}"); return sb.toString(); } private boolean openOutputStream(File outJar) { try { OutputStream os = FileUtil.makeOutputStream(buildConfig.getOutputJar()); zos = new JarOutputStream(os,getWeaver().getManifest(true)); } catch (IOException ex) { IMessage message = new Message("Unable to open outjar " + outJar.getPath() + "(" + ex.getMessage() + ")", new SourceLocation(outJar,0), true); handler.handleMessage(message); return false; } return true; } private void closeOutputStream(File outJar) { try { if (zos != null) zos.close(); zos = null; /* Ensure we don't write an incomplete JAR bug-71339 */ if (handler.hasErrors()) { outJar.delete(); } } catch (IOException ex) { IMessage message = new Message("Unable to write outjar " + outJar.getPath() + "(" + ex.getMessage() + ")", new SourceLocation(outJar,0), true); handler.handleMessage(message); } } private void copyResourcesToDestination() throws IOException { // resources that we need to copy are contained in the injars and inpath only for (Iterator i = buildConfig.getInJars().iterator(); i.hasNext(); ) { File inJar = (File)i.next(); copyResourcesFromJarFile(inJar); } for (Iterator i = buildConfig.getInpath().iterator(); i.hasNext(); ) { File inPathElement = (File)i.next(); if (inPathElement.isDirectory()) { copyResourcesFromDirectory(inPathElement); } else { copyResourcesFromJarFile(inPathElement); } } if (buildConfig.getSourcePathResources() != null) { for (Iterator i = buildConfig.getSourcePathResources().keySet().iterator(); i.hasNext(); ) { String resource = (String)i.next(); File from = (File)buildConfig.getSourcePathResources().get(resource); copyResourcesFromFile(from,resource,from); } } writeManifest(); } private void copyResourcesFromJarFile(File jarFile) throws IOException { JarInputStream inStream = null; try { inStream = new JarInputStream(new FileInputStream(jarFile)); while (true) { ZipEntry entry = inStream.getNextEntry(); if (entry == null) break; String filename = entry.getName(); // System.out.println("? copyResourcesFromJarFile() filename='" + filename +"'"); if (!entry.isDirectory() && acceptResource(filename)) { byte[] bytes = FileUtil.readAsByteArray(inStream); writeResource(filename,bytes,jarFile); } inStream.closeEntry(); } } finally { if (inStream != null) inStream.close(); } } private void copyResourcesFromDirectory(File dir) throws IOException { if (!COPY_INPATH_DIR_RESOURCES) return; // Get a list of all files (i.e. everything that isnt a directory) File[] files = FileUtil.listFiles(dir,new FileFilter() { public boolean accept(File f) { boolean accept = !(f.isDirectory() || f.getName().endsWith(".class")) ; return accept; } }); // For each file, add it either as a real .class file or as a resource for (int i = 0; i < files.length; i++) { // ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath() // or we are in trouble... String filename = files[i].getAbsolutePath().substring( dir.getAbsolutePath().length()+1); copyResourcesFromFile(files[i],filename,dir); } } private void copyResourcesFromFile(File f,String filename,File src) throws IOException { if (!acceptResource(filename)) return; FileInputStream fis = null; try { fis = new FileInputStream(f); byte[] bytes = FileUtil.readAsByteArray(fis); // String relativePath = files[i].getPath(); writeResource(filename,bytes,src); } finally { if (fis != null) fis.close(); } } private void writeResource(String filename, byte[] content, File srcLocation) throws IOException { if (state.hasResource(filename)) { IMessage msg = new Message("duplicate resource: '" + filename + "'", IMessage.WARNING, null, new SourceLocation(srcLocation,0)); handler.handleMessage(msg); return; } if (filename.equals(buildConfig.getOutxmlName())) { ignoreOutxml = true; IMessage msg = new Message("-outxml/-outxmlfile option ignored because resource already exists: '" + filename + "'", IMessage.WARNING, null, new SourceLocation(srcLocation,0)); handler.handleMessage(msg); } if (zos != null) { ZipEntry newEntry = new ZipEntry(filename); //??? get compression scheme right zos.putNextEntry(newEntry); zos.write(content); zos.closeEntry(); } else { File destDir = buildConfig.getOutputDir(); if (buildConfig.getCompilationResultDestinationManager() != null) { destDir = buildConfig.getCompilationResultDestinationManager().getOutputLocationForResource(srcLocation); } try { OutputStream fos = FileUtil.makeOutputStream(new File(destDir,filename)); fos.write(content); fos.close(); } catch (FileNotFoundException fnfe) { IMessage msg = new Message("unable to copy resource to output folder: '" + filename + "' - reason: "+fnfe.getMessage(), IMessage.ERROR, null, new SourceLocation(srcLocation,0)); handler.handleMessage(msg); } } state.recordResource(filename); } /* * If we are writing to an output directory copy the manifest but only * if we already have one */ private void writeManifest () throws IOException { Manifest manifest = getWeaver().getManifest(false); if (manifest != null && zos == null) { File outputDir = buildConfig.getOutputDir(); if (buildConfig.getCompilationResultDestinationManager() != null) { // Manifests are only written if we have a jar on the inpath. Therefore, // we write the manifest to the defaultOutputLocation because this is // where we sent the classes that were on the inpath outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation(); } if (outputDir == null) return; OutputStream fos = FileUtil.makeOutputStream(new File(outputDir,MANIFEST_NAME)); manifest.write(fos); fos.close(); } } private boolean acceptResource(String resourceName) { if ( (resourceName.startsWith("CVS/")) || (resourceName.indexOf("/CVS/") != -1) || (resourceName.endsWith("/CVS")) || (resourceName.endsWith(".class")) || (resourceName.startsWith(".svn/")) || (resourceName.indexOf("/.svn/")!=-1) || (resourceName.endsWith("/.svn")) || (resourceName.toUpperCase().equals(MANIFEST_NAME)) ) { return false; } else { return true; } } private void writeOutxmlFile () throws IOException { if (ignoreOutxml) return; String filename = buildConfig.getOutxmlName(); // System.err.println("? AjBuildManager.writeOutxmlFile() outxml=" + filename); Map outputDirsAndAspects = findOutputDirsForAspects(); Set outputDirs = outputDirsAndAspects.entrySet(); for (Iterator iterator = outputDirs.iterator(); iterator.hasNext();) { Map.Entry entry = (Map.Entry) iterator.next(); File outputDir = (File) entry.getKey(); List aspects = (List) entry.getValue(); ByteArrayOutputStream baos = getOutxmlContents(aspects); if (zos != null) { ZipEntry newEntry = new ZipEntry(filename); zos.putNextEntry(newEntry); zos.write(baos.toByteArray()); zos.closeEntry(); } else { OutputStream fos = FileUtil.makeOutputStream(new File(outputDir, filename)); fos.write(baos.toByteArray()); fos.close(); } } } private ByteArrayOutputStream getOutxmlContents(List aspectNames) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); ps.println(""); ps.println(""); if (aspectNames != null) { for (Iterator i = aspectNames.iterator(); i.hasNext();) { String name = (String) i.next(); ps.println(""); } } ps.println(""); ps.println(""); ps.println(); ps.close(); return baos; } /** * Returns a map where the keys are File objects corresponding to * all the output directories and the values are a list of aspects * which are sent to that ouptut directory */ private Map /* File --> List (String) */findOutputDirsForAspects() { Map outputDirsToAspects = new HashMap(); Map aspectNamesToFileNames = state.getAspectNamesToFileNameMap(); if (buildConfig.getCompilationResultDestinationManager() == null || buildConfig.getCompilationResultDestinationManager().getAllOutputLocations().size() == 1) { // we only have one output directory...which simplifies things File outputDir = buildConfig.getOutputDir(); if (buildConfig.getCompilationResultDestinationManager() != null) { outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation(); } List aspectNames = new ArrayList(); if (aspectNamesToFileNames != null) { Set keys = aspectNamesToFileNames.keySet(); for (Iterator iterator = keys.iterator(); iterator.hasNext();) { String name = (String) iterator.next(); aspectNames.add(name); } } outputDirsToAspects.put(outputDir, aspectNames); } else { List outputDirs = buildConfig.getCompilationResultDestinationManager().getAllOutputLocations(); for (Iterator iterator = outputDirs.iterator(); iterator.hasNext();) { File outputDir = (File) iterator.next(); outputDirsToAspects.put(outputDir,new ArrayList()); } Set entrySet = aspectNamesToFileNames.entrySet(); for (Iterator iterator = entrySet.iterator(); iterator.hasNext();) { Map.Entry entry = (Map.Entry) iterator.next(); String aspectName = (String) entry.getKey(); char[] fileName = (char[]) entry.getValue(); File outputDir = buildConfig.getCompilationResultDestinationManager() .getOutputLocationForClass(new File(new String(fileName))); if(!outputDirsToAspects.containsKey(outputDir)) { outputDirsToAspects.put(outputDir,new ArrayList()); } ((List)outputDirsToAspects.get(outputDir)).add(aspectName); } } return outputDirsToAspects; } // public static void dumprels() { // IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap(); // int ctr = 1; // Set entries = irm.getEntries(); // for (Iterator iter = entries.iterator(); iter.hasNext();) { // String hid = (String) iter.next(); // List rels = irm.get(hid); // for (Iterator iterator = rels.iterator(); iterator.hasNext();) { // IRelationship ir = (IRelationship) iterator.next(); // List targets = ir.getTargets(); // for (Iterator iterator2 = targets.iterator(); // iterator2.hasNext(); // ) { // String thid = (String) iterator2.next(); // System.err.println("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid); // } // } // } // } /** * Responsible for managing the ASM model between builds. Contains the policy for * maintaining the persistance of elements in the model. * * This code is driven before each 'fresh' (batch) build to create * a new model. */ private void setupModel(AjBuildConfig config) { AsmManager.setCreatingModel(config.isEmacsSymMode() || config.isGenerateModelMode()); if (!AsmManager.isCreatingModel()) return; AsmManager.getDefault().createNewASM(); // AsmManager.getDefault().getRelationshipMap().clear(); IHierarchy model = AsmManager.getDefault().getHierarchy(); String rootLabel = ""; IProgramElement.Kind kind = IProgramElement.Kind.FILE_JAVA; if (buildConfig.getConfigFile() != null) { rootLabel = buildConfig.getConfigFile().getName(); model.setConfigFile(buildConfig.getConfigFile().getAbsolutePath()); kind = IProgramElement.Kind.FILE_LST; } model.setRoot(new ProgramElement(rootLabel, kind, new ArrayList())); model.setFileMap(new HashMap()); setStructureModel(model); state.setStructureModel(model); state.setRelationshipMap(AsmManager.getDefault().getRelationshipMap()); } // // private void dumplist(List l) { // System.err.println("---- "+l.size()); // for (int i =0 ;i")) { // store.add(ipe); // return; // } // } // for (Iterator i = ipe.getChildren().iterator();i.hasNext();) { // accumulateFileNodes((IProgramElement)i.next(),store); // } // } /** init only on initial batch compile? no file-specific options */ private void initBcelWorld(IMessageHandler handler) throws IOException { List cp = buildConfig.getFullClasspath(); // pr145693 //buildConfig.getBootclasspath(); //cp.addAll(buildConfig.getClasspath()); BcelWorld bcelWorld = new BcelWorld(cp, handler, null); bcelWorld.setBehaveInJava5Way(buildConfig.getBehaveInJava5Way()); bcelWorld.setAddSerialVerUID(buildConfig.isAddSerialVerUID()); bcelWorld.performExtraConfiguration(buildConfig.getXconfigurationInfo()); bcelWorld.setTargetAspectjRuntimeLevel(buildConfig.getTargetAspectjRuntimeLevel()); bcelWorld.setOptionalJoinpoints(buildConfig.getXJoinpoints()); bcelWorld.setXnoInline(buildConfig.isXnoInline()); bcelWorld.setXlazyTjp(buildConfig.isXlazyTjp()); bcelWorld.setXHasMemberSupportEnabled(buildConfig.isXHasMemberEnabled()); bcelWorld.setPinpointMode(buildConfig.isXdevPinpoint()); bcelWorld.setErrorAndWarningThreshold(buildConfig.getOptions().errorThreshold,buildConfig.getOptions().warningThreshold); BcelWeaver bcelWeaver = new BcelWeaver(bcelWorld); state.setWorld(bcelWorld); state.setWeaver(bcelWeaver); state.clearBinarySourceFiles(); if (buildConfig.getLintMode().equals(AjBuildConfig.AJLINT_DEFAULT)) { bcelWorld.getLint().loadDefaultProperties(); } else { bcelWorld.getLint().setAll(buildConfig.getLintMode()); } if (buildConfig.getLintSpecFile() != null) { bcelWorld.getLint().setFromProperties(buildConfig.getLintSpecFile()); } for (Iterator i = buildConfig.getAspectpath().iterator(); i.hasNext();) { File f = (File) i.next(); if (!f.exists()) { IMessage message = new Message("invalid aspectpath entry: "+f.getName(),null,true); handler.handleMessage(message); } else { bcelWeaver.addLibraryJarFile(f); } } // String lintMode = buildConfig.getLintMode(); File outputDir = buildConfig.getOutputDir(); if (outputDir == null && buildConfig.getCompilationResultDestinationManager() != null) { // send all output from injars and inpath to the default output location // (will also later send the manifest there too) outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation(); } // ??? incremental issues for (Iterator i = buildConfig.getInJars().iterator(); i.hasNext();) { File inJar = (File) i.next(); List unwovenClasses = bcelWeaver.addJarFile(inJar, outputDir, false); state.recordBinarySource(inJar.getPath(), unwovenClasses); } for (Iterator i = buildConfig.getInpath().iterator(); i.hasNext(); ) { File inPathElement = (File)i.next(); if (!inPathElement.isDirectory()) { // its a jar file on the inpath // the weaver method can actually handle dirs, but we don't call it, see next block List unwovenClasses = bcelWeaver.addJarFile(inPathElement,outputDir,true); state.recordBinarySource(inPathElement.getPath(),unwovenClasses); } else { // add each class file in an in-dir individually, this gives us the best error reporting // (they are like 'source' files then), and enables a cleaner incremental treatment of // class file changes in indirs. File[] binSrcs = FileUtil.listFiles(inPathElement, binarySourceFilter); for (int j = 0; j < binSrcs.length; j++) { UnwovenClassFile ucf = bcelWeaver.addClassFile(binSrcs[j], inPathElement, outputDir); List ucfl = new ArrayList(); ucfl.add(ucf); state.recordBinarySource(binSrcs[j].getPath(),ucfl); } } } bcelWeaver.setReweavableMode(buildConfig.isXNotReweavable()); //check for org.aspectj.runtime.JoinPoint ResolvedType joinPoint = bcelWorld.resolve("org.aspectj.lang.JoinPoint"); if (joinPoint.isMissing()) { IMessage message = new Message("classpath error: unable to find org.aspectj.lang.JoinPoint (check that aspectjrt.jar is in your classpath)", null, true); handler.handleMessage(message); } } public World getWorld() { return getBcelWorld(); } void addAspectClassFilesToWeaver(List addedClassFiles) throws IOException { for (Iterator i = addedClassFiles.iterator(); i.hasNext(); ) { UnwovenClassFile classFile = (UnwovenClassFile) i.next(); getWeaver().addClassFile(classFile); } } // public boolean weaveAndGenerateClassFiles() throws IOException { // handler.handleMessage(MessageUtil.info("weaving")); // if (progressListener != null) progressListener.setText("weaving aspects"); // bcelWeaver.setProgressListener(progressListener, 0.5, 0.5/state.addedClassFiles.size()); // //!!! doesn't provide intermediate progress during weaving // // XXX add all aspects even during incremental builds? // addAspectClassFilesToWeaver(state.addedClassFiles); // if (buildConfig.isNoWeave()) { // if (buildConfig.getOutputJar() != null) { // bcelWeaver.dumpUnwoven(buildConfig.getOutputJar()); // } else { // bcelWeaver.dumpUnwoven(); // bcelWeaver.dumpResourcesToOutPath(); // } // } else { // if (buildConfig.getOutputJar() != null) { // bcelWeaver.weave(buildConfig.getOutputJar()); // } else { // bcelWeaver.weave(); // bcelWeaver.dumpResourcesToOutPath(); // } // } // if (progressListener != null) progressListener.setProgress(1.0); // return true; // //return messageAdapter.getErrorCount() == 0; //!javaBuilder.notifier.anyErrors(); // } public FileSystem getLibraryAccess(String[] classpaths, String[] filenames) { String defaultEncoding = buildConfig.getOptions().defaultEncoding; if ("".equals(defaultEncoding)) //$NON-NLS-1$ defaultEncoding = null; //$NON-NLS-1$ // Bug 46671: We need an array as long as the number of elements in the classpath - *even though* not every // element of the classpath is likely to be a directory. If we ensure every element of the array is set to // only look for BINARY, then we make sure that for any classpath element that is a directory, we won't build // a classpathDirectory object that will attempt to look for source when it can't find binary. int[] classpathModes = new int[classpaths.length]; for (int i =0 ;i