Logo Search packages:      
Sourcecode: aspectj version File versions

AjdeCoreBuildManager.java

/********************************************************************
 * Copyright (c) 2007 Contributors. 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://eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: IBM Corporation - initial API and implementation 
 *                       Helen Hawkins   - initial version (bug 148190)
 *******************************************************************/
package org.aspectj.ajde.core.internal;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.aspectj.ajde.core.AjCompiler;
import org.aspectj.ajde.core.ICompilerConfiguration;
import org.aspectj.ajde.core.IOutputLocationManager;
import org.aspectj.ajdt.ajc.AjdtCommand;
import org.aspectj.ajdt.ajc.BuildArgParser;
import org.aspectj.ajdt.ajc.ConfigParser;
import org.aspectj.ajdt.internal.core.builder.AjBuildConfig;
import org.aspectj.ajdt.internal.core.builder.AjBuildManager;
import org.aspectj.ajdt.internal.core.builder.AjState;
import org.aspectj.ajdt.internal.core.builder.IncrementalStateManager;
import org.aspectj.asm.AsmManager;
import org.aspectj.bridge.AbortException;
import org.aspectj.bridge.CountingMessageHandler;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.bridge.context.CompilationAndWeavingContext;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.aspectj.util.LangUtil;

/**
 * Build Manager which drives the build for a given AjCompiler. Tools call build on the AjCompiler which drives this.
 */
00046 public class AjdeCoreBuildManager {

      private final AjCompiler compiler;
      private AjdeCoreBuildNotifierAdapter buildEventNotifier = null;
      private final AjBuildManager ajBuildManager;
      private final IMessageHandler msgHandlerAdapter;

      public AjdeCoreBuildManager(AjCompiler compiler) {
            this.compiler = compiler;
            this.msgHandlerAdapter = new AjdeCoreMessageHandlerAdapter(compiler.getMessageHandler());
            this.ajBuildManager = new AjBuildManager(msgHandlerAdapter);
            this.ajBuildManager.environmentSupportsIncrementalCompilation(true);

            // this static information needs to be set to ensure
            // incremental compilation works correctly
            IncrementalStateManager.recordIncrementalStates = true;
            IncrementalStateManager.debugIncrementalStates = false;
            AsmManager.attemptIncrementalModelRepairs = true;
      }

      // public AsmManager getStructureModel() {
      // return ajBuildManager.
      // }

      /**
       * Execute a full or incremental build
       * 
       * @param fullBuild true if requesting a full build, false if requesting to try an incremental build
       */
00075       public void performBuild(boolean fullBuild) {

            // If an incremental build is requested, check that we can
            if (!fullBuild) {
                  AjState existingState = IncrementalStateManager.retrieveStateFor(compiler.getId());
                  if (existingState == null || existingState.getBuildConfig() == null
                              || ajBuildManager.getState().getBuildConfig() == null) {
                        // No existing state so we must do a full build
                        fullBuild = true;
                  } else {
                        AsmManager.setLastActiveStructureModel(existingState.getStructureModel());
                        // AsmManager.getDefault().setRelationshipMap(existingState.getRelationshipMap());
                        // AsmManager.getDefault().setHierarchy(existingState.getStructureModel());
                  }
            }
            try {
                  reportProgressBegin();

                  // record the options passed to the compiler if INFO turned on
                  if (!msgHandlerAdapter.isIgnoring(IMessage.INFO)) {
                        handleMessage(new Message(getFormattedOptionsString(), IMessage.INFO, null, null));
                  }

                  CompilationAndWeavingContext.reset();

                  if (fullBuild) { // FULL BUILD
                        AjBuildConfig buildConfig = generateAjBuildConfig();
                        if (buildConfig == null) {
                              return;
                        }
                        ajBuildManager.batchBuild(buildConfig, msgHandlerAdapter);
                  } else { // INCREMENTAL BUILD
                        // Only rebuild the config object if the configuration has changed
                        AjBuildConfig buildConfig = null;
                        ICompilerConfiguration compilerConfig = compiler.getCompilerConfiguration();
                        int changes = compilerConfig.getConfigurationChanges();
                        if (changes != ICompilerConfiguration.NO_CHANGES) {

                              // What configuration changes can we cope with? And besides just repairing the config object
                              // what does it mean for any existing state that we have?

                              buildConfig = generateAjBuildConfig();
                              if (buildConfig == null) {
                                    return;
                              }
                        } else {
                              buildConfig = ajBuildManager.getState().getBuildConfig();
                              buildConfig.setChanged(changes); // pass it through for the state to use it when making decisions
                              buildConfig.setModifiedFiles(compilerConfig.getProjectSourceFilesChanged());
                              buildConfig.setClasspathElementsWithModifiedContents(compilerConfig.getClasspathElementsWithModifiedContents());
                              compilerConfig.configurationRead();
                        }
                        ajBuildManager.incrementalBuild(buildConfig, msgHandlerAdapter);
                  }
                  IncrementalStateManager.recordSuccessfulBuild(compiler.getId(), ajBuildManager.getState());

            } catch (ConfigParser.ParseException pe) {
                  handleMessage(new Message("Config file entry invalid, file: " + pe.getFile().getPath() + ", line number: "
                              + pe.getLine(), IMessage.WARNING, null, null));
            } catch (AbortException e) {
                  final IMessage message = e.getIMessage();
                  if (message == null) {
                        handleMessage(new Message(LangUtil.unqualifiedClassName(e) + " thrown: " + e.getMessage(), IMessage.ERROR, e, null));
                  } else {
                        handleMessage(new Message(message.getMessage() + "\n" + CompilationAndWeavingContext.getCurrentContext(),
                                    IMessage.ERROR, e, null));
                  }
            } catch (Throwable t) {
                  handleMessage(new Message("Compile error: " + LangUtil.unqualifiedClassName(t) + " thrown: " + "" + t.getMessage(),
                              IMessage.ABORT, t, null));
            } finally {
                  compiler.getBuildProgressMonitor().finish(ajBuildManager.wasFullBuild());
            }
      }

      /**
       * Starts the various notifiers which are interested in the build progress
       */
00153       private void reportProgressBegin() {
            compiler.getBuildProgressMonitor().begin();
            buildEventNotifier = new AjdeCoreBuildNotifierAdapter(compiler.getBuildProgressMonitor());
            ajBuildManager.setProgressListener(buildEventNotifier);
      }

      private String getFormattedOptionsString() {
            ICompilerConfiguration compilerConfig = compiler.getCompilerConfiguration();
            return "Building with settings: " + "\n-> output paths: "
                        + formatCollection(compilerConfig.getOutputLocationManager().getAllOutputLocations()) + "\n-> classpath: "
                        + compilerConfig.getClasspath() + "\n-> -inpath " + formatCollection(compilerConfig.getInpath()) + "\n-> -outjar "
                        + formatOptionalString(compilerConfig.getOutJar()) + "\n-> -aspectpath "
                        + formatCollection(compilerConfig.getAspectPath()) + "\n-> -sourcePathResources "
                        + formatMap(compilerConfig.getSourcePathResources()) + "\n-> non-standard options: "
                        + compilerConfig.getNonStandardOptions() + "\n-> javaoptions:" + formatMap(compilerConfig.getJavaOptionsMap());
      }

      private String formatCollection(Collection options) {
            if (options == null)
                  return "<default>";
            if (options.isEmpty())
                  return "none";

            StringBuffer formattedOptions = new StringBuffer();
            Iterator it = options.iterator();
            while (it.hasNext()) {
                  String o = it.next().toString();
                  if (formattedOptions.length() > 0)
                        formattedOptions.append(", ");
                  formattedOptions.append(o);
            }
            return formattedOptions.toString();
      }

      private String formatMap(Map options) {
            if (options == null)
                  return "<default>";
            if (options.isEmpty())
                  return "none";

            return options.toString();
      }

      private String formatOptionalString(String s) {
            if (s == null) {
                  return "";
            } else {
                  return s;
            }
      }

      /**
       * Generate a new AjBuildConfig from the compiler configuration associated with this AjdeCoreBuildManager or from a
       * configuration file.
       * 
       * @return null if invalid configuration, corresponding AjBuildConfig otherwise
       */
00210       public AjBuildConfig generateAjBuildConfig() {
            File configFile = new File(compiler.getId());
            ICompilerConfiguration compilerConfig = compiler.getCompilerConfiguration();
            CountingMessageHandler handler = CountingMessageHandler.makeCountingMessageHandler(msgHandlerAdapter);

            String[] args = null;
            // Retrieve the set of files from either an arg file (@filename) or the compiler configuration
            if (configFile.exists() && configFile.isFile()) {
                  args = new String[] { "@" + configFile.getAbsolutePath() };
            } else {
                  List l = compilerConfig.getProjectSourceFiles();
                  if (l == null) {
                        return null;
                  }
                  List xmlfiles = compilerConfig.getProjectXmlConfigFiles();
                  if (xmlfiles != null && !xmlfiles.isEmpty()) {
                        args = new String[l.size() + xmlfiles.size()];
                        // TODO speedup
                        int p = 0;
                        for (int i = 0; i < l.size(); i++) {
                              args[p++] = (String) l.get(i);
                        }
                        for (int i = 0; i < xmlfiles.size(); i++) {
                              args[p++] = (String) xmlfiles.get(i);
                        }
                  } else {
                        args = (String[]) l.toArray(new String[l.size()]);
                  }
            }

            BuildArgParser parser = new BuildArgParser(handler);

            AjBuildConfig config = new AjBuildConfig();

            parser.populateBuildConfig(config, args, false, configFile);

            // Process the CLASSPATH
            String propcp = compilerConfig.getClasspath();
            if (propcp != null && propcp.length() != 0) {
                  StringTokenizer st = new StringTokenizer(propcp, File.pathSeparator);
                  List configClasspath = config.getClasspath();
                  ArrayList toAdd = new ArrayList();
                  while (st.hasMoreTokens()) {
                        String entry = st.nextToken();
                        if (!configClasspath.contains(entry)) {
                              toAdd.add(entry);
                        }
                  }
                  if (0 < toAdd.size()) {
                        ArrayList both = new ArrayList(configClasspath.size() + toAdd.size());
                        both.addAll(configClasspath);
                        both.addAll(toAdd);
                        config.setClasspath(both);
                  }
            }

            // Process the OUTJAR
            if (config.getOutputJar() == null) {
                  String outJar = compilerConfig.getOutJar();
                  if (outJar != null && outJar.length() != 0) {
                        config.setOutputJar(new File(outJar));
                  }
            }

            // Process the OUTPUT LOCATION MANAGER
            IOutputLocationManager outputLocationManager = compilerConfig.getOutputLocationManager();
            if (config.getCompilationResultDestinationManager() == null && outputLocationManager != null) {
                  config.setCompilationResultDestinationManager(new OutputLocationAdapter(outputLocationManager));
            }

            // Process the INPATH
            mergeInto(config.getInpath(), compilerConfig.getInpath());
            // bug 168840 - calling 'setInPath(..)' creates BinarySourceFiles which
            // are used to see if there have been changes in classes on the inpath
            if (config.getInpath() != null) {
                  config.setInPath(config.getInpath());
            }

            // Process the SOURCE PATH RESOURCES
            config.setSourcePathResources(compilerConfig.getSourcePathResources());

            // Process the ASPECTPATH
            mergeInto(config.getAspectpath(), compilerConfig.getAspectPath());

            // Process the JAVA OPTIONS MAP
            Map jom = compilerConfig.getJavaOptionsMap();
            if (jom != null) {
                  String version = (String) jom.get(CompilerOptions.OPTION_Compliance);
                  if (version != null && (version.equals(CompilerOptions.VERSION_1_5) || version.equals(CompilerOptions.VERSION_1_6))) {
                        config.setBehaveInJava5Way(true);
                  }
                  config.getOptions().set(jom);
            }

            // Process the NON-STANDARD COMPILER OPTIONS
            configureNonStandardOptions(config);

            compilerConfig.configurationRead();

            ISourceLocation location = null;
            if (config.getConfigFile() != null) {
                  location = new SourceLocation(config.getConfigFile(), 0);
            }

            String message = parser.getOtherMessages(true);
            if (null != message) {
                  IMessage m = new Message(message, IMessage.ERROR, null, location);
                  handler.handleMessage(m);
            }

            // always force model generation in AJDE
            config.setGenerateModelMode(true);
            // always be in incremental mode in AJDE
            config.setIncrementalMode(true);
            // always force proceedOnError in AJDE
            config.setProceedOnError(true);
            return config;
      }

      private void mergeInto(Collection target, Collection source) {
            if ((null == target) || (null == source)) {
                  return;
            }
            for (Iterator iter = source.iterator(); iter.hasNext();) {
                  Object next = iter.next();
                  if (!target.contains(next)) {
                        target.add(next);
                  }
            }
      }

      /**
       * Helper method for configure build options. This reads all command-line options specified in the non-standard options text
       * entry and sets any corresponding unset values in config.
       */
00345       private void configureNonStandardOptions(AjBuildConfig config) {

            String nonStdOptions = compiler.getCompilerConfiguration().getNonStandardOptions();
            if (LangUtil.isEmpty(nonStdOptions)) {
                  return;
            }

            // Break a string into a string array of non-standard options.
            // Allows for one option to include a ' '. i.e. assuming it has been quoted, it
            // won't accidentally get treated as a pair of options (can be needed for xlint props file option)
            List tokens = new ArrayList();
            int ind = nonStdOptions.indexOf('\"');
            int ind2 = nonStdOptions.indexOf('\"', ind + 1);
            if ((ind > -1) && (ind2 > -1)) { // dont tokenize within double quotes
                  String pre = nonStdOptions.substring(0, ind);
                  String quoted = nonStdOptions.substring(ind + 1, ind2);
                  String post = nonStdOptions.substring(ind2 + 1, nonStdOptions.length());
                  tokens.addAll(tokenizeString(pre));
                  tokens.add(quoted);
                  tokens.addAll(tokenizeString(post));
            } else {
                  tokens.addAll(tokenizeString(nonStdOptions));
            }
            String[] args = (String[]) tokens.toArray(new String[] {});

            // set the non-standard options in an alternate build config
            // (we don't want to lose the settings we already have)
            CountingMessageHandler counter = CountingMessageHandler.makeCountingMessageHandler(msgHandlerAdapter);
            AjBuildConfig altConfig = AjdtCommand.genBuildConfig(args, counter);
            if (counter.hasErrors()) {
                  return;
            }
            // copy globals where local is not set
            config.installGlobals(altConfig);
      }

      /** Local helper method for splitting option strings */
00382       private List tokenizeString(String str) {
            List tokens = new ArrayList();
            StringTokenizer tok = new StringTokenizer(str);
            while (tok.hasMoreTokens()) {
                  tokens.add(tok.nextToken());
            }
            return tokens;
      }

      /**
       * Helper method to ask the messagehandler to handle the given message
       */
00394       private void handleMessage(Message msg) {
            compiler.getMessageHandler().handleMessage(msg);
      }

      public void setCustomMungerFactory(Object o) {
            ajBuildManager.setCustomMungerFactory(o);
      }

      public Object getCustomMungerFactory() {
            return ajBuildManager.getCustomMungerFactory();
      }

      public void cleanupEnvironment() {
            ajBuildManager.cleanupEnvironment();
      }

      public AsmManager getStructureModel() {
            return ajBuildManager.getStructureModel();
      }
}

Generated by  Doxygen 1.6.0   Back to index