예제 #1
0
  /**
   * This method attempts to find a matching dependency quickly, by bypassing full resolution of the
   * classpath path group for a plugin. It assumes the following: 1. The dependendency is directly
   * defined by the plugin artifact (this should always be true when a plugin implements an abstract
   * method of another) 2. The plugin artifact defines no overrides that effect the dependency (this
   * should be true as the plugin should just define the version it wants directly). If the
   * performance of resolvePathGroup is improved this method could be replaced by the version below.
   */
  private RepoArtifactId fastFindMatchingDependency(Target target, RepoArtifactId id) {
    // Find the matching id that belongs to the classpath
    PathGroup pathGroup = target.getPathGroup("classpath");
    RepoArtifactId match = null;
    String matchingPath = null;
    for (Iterator i = target.getPlugin().getArtifact().getDependencies().iterator();
        i.hasNext(); ) {
      RepoDependency dependency = (RepoDependency) i.next();
      if (dependency.getId().matches(id)) {
        for (Iterator j = dependency.getPathSpecs().iterator(); j.hasNext(); ) {
          RepoPathSpec pathSpec = (RepoPathSpec) j.next();
          if (pathGroup.getPaths().contains("plugin." + pathSpec.getTo())) {
            match = dependency.getId();
            matchingPath = pathSpec.getTo();
            break;
          }
        }
      }
    }

    Assert.isTrue(
        match != null,
        target.getPlugin().getArtifact().getId().toShortString()
            + " does not declare a dependency that matches "
            + id);

    // Apply any project overrides
    for (Iterator i = overrides.iterator(); i.hasNext(); ) {
      ws.quokka.core.model.Override override = (ws.quokka.core.model.Override) i.next();
      if (override.getWithVersion() != null && override.matches(match)) {
        Set paths = override.matchingPluginPaths(target.getPlugin().getArtifact().getId());
        if (paths.contains(matchingPath) || ((paths.size() == 1) && paths.contains("*"))) {
          log.verbose("Overriding " + match.toShortString() + " to " + override.getWithVersion());
          if (log.isDebugEnabled()) {
            log.debug(
                "Applied "
                    + override
                    + (override.getLocator() == null ? "" : " from " + override.getLocator()));
          }
          return new RepoArtifactId(
              id.getGroup(), id.getName(), id.getType(), override.getWithVersion());
        }
      }
    }

    return match;

    // Slow code
    //        List artifacts = resolvePathGroup(target, "classpath");
    //        for (Iterator i = artifacts.iterator(); i.hasNext();) {
    //            RepoArtifact artifact = (RepoArtifact) i.next();
    //            if (artifact.getId().matches(id)) {
    //                return artifact.getId();
    //            }
    //        }
  }
예제 #2
0
  private void addDependentTargets(Map resolved, Target target) {
    for (Iterator i = target.getDependencies().iterator(); i.hasNext(); ) {
      String dependency = (String) i.next();

      for (Iterator j = target.getPlugin().getTargets().iterator(); j.hasNext(); ) {
        Target siblingTarget = (Target) j.next();

        if (siblingTarget.getName().equals(dependency)) {
          addTarget(resolved, siblingTarget);
        }
      }
    }
  }
예제 #3
0
  public Plugin getPlugin(RepoArtifactId id) {
    for (Iterator i = resolvedTargets.values().iterator(); i.hasNext(); ) {
      List pluginTargets = (List) i.next();

      for (Iterator j = pluginTargets.iterator(); j.hasNext(); ) {
        Target target = (Target) j.next();

        if (target.getPlugin().getArtifact().getId().equals(id)) {
          return target.getPlugin();
        }
      }
    }

    return null;
  }
예제 #4
0
  private String[] parseImplements(Target target) {
    // TODO: parse during plugin parsing ... add them properly to target
    String[] implementsPlugin = Strings.trim(Strings.split(target.getImplementsPlugin(), ":"));

    if ((implementsPlugin == null) || (implementsPlugin.length != 3)) {
      throw new BuildException(
          "'implements' attribute of 'target' element is not in 'group:name:target' format. plugin="
              + target.getPlugin().getArtifact().getId()
              + ", target="
              + target.getName()
              + ", value="
              + target.getImplementsPlugin());
    }

    return implementsPlugin;
  }
예제 #5
0
  private void resolvePath(
      List ids,
      List paths,
      boolean mergeWithCore,
      boolean overrideCore,
      Target target,
      boolean flatten) {
    String projectPrefix = "project.";
    String pluginPrefix = "plugin.";
    String propertyPrefix = "property.";

    for (Iterator i = ids.iterator(); i.hasNext(); ) {
      String id = (String) i.next();

      if (id.startsWith(projectPrefix)) {
        String projectPathId = id.substring(projectPrefix.length());
        Assert.isTrue(
            resolvedPaths.get(projectPathId) != null,
            "Project path '" + projectPathId + "' is not defined");
        paths.add(getReslovedProjectPath(projectPathId, mergeWithCore, overrideCore, flatten));
      } else if (id.startsWith(pluginPrefix)) {
        String pluginPathId = id.substring(pluginPrefix.length());
        paths.add(
            getResolvedPluginPath(
                target.getPlugin(), pluginPathId, mergeWithCore, overrideCore, flatten));
      } else if (id.startsWith(propertyPrefix)) {
        String property = id.substring(propertyPrefix.length());
        property = Strings.replace(property, "prefix", target.getPrefix());

        String value = project.getProperties().getProperty(property);

        if (value != null) {
          resolvePath(
              Strings.commaSepList(value), paths, mergeWithCore, overrideCore, target, flatten);
        }
      } else if (id.equals("plugin")) {
        ResolvedPath path = new ResolvedPath();
        path.setId("Plugin:");
        path.add(target.getPlugin().getArtifact());
        paths.add(path);
      } else {
        throw new BuildException(
            "A path group must contain a comma separated list of: plugin | plugin.<pluginpath> | project.<projectpath> | property.<reference to a property containing additional paths>: id="
                + id);
      }
    }
  }
예제 #6
0
 public List resolvePathGroup(Target target, String pathGroupId) {
   // This code path now gets hit frequently when resolving plugin interdependencies, so cache
   String key =
       "pathGroup#"
           + target.getPlugin().toShortString()
           + "#"
           + target.getName()
           + "#"
           + pathGroupId;
   List path = (List) pathCache.get(key);
   if (path == null) {
     path = _resolvePathGroup(target, pathGroupId);
     pathCache.put(key, path);
   } else {
     log.debug("Cache hit for: " + key);
   }
   return path;
 }
예제 #7
0
  public List _resolvePathGroup(Target target, String pathGroupId) {
    Plugin plugin = target.getPlugin();
    PathGroup pathGroup = target.getPathGroup(pathGroupId);

    if (pathGroup == null) {
      if (plugin.getDeclaringPlugin() != null) {
        String declaringTargetName =
            plugin.getDeclaringPlugin().getNameSpace() + ":" + parseImplements(target)[2];
        pathGroup =
            plugin.getDeclaringPlugin().getTarget(declaringTargetName).getPathGroup(pathGroupId);

        // TODO: Check the path group only refers to project paths?
      }

      Assert.isTrue(
          pathGroup != null,
          "Target '"
              + target.getName()
              + "' has requested path group '"
              + pathGroupId
              + "' that does not exist");
    }

    if (log.isDebugEnabled()) {
      log.debug(
          "Resolving path: target="
              + target.getName()
              + ", pathGroup="
              + pathGroupId
              + ", pathGroupElements="
              + pathGroup.getPaths());
    }

    List paths = new ArrayList();

    // Note: merging with core is turned off here so that the proper path tree is maintained
    // However, core overrides are still applied by separating that into a different flag
    resolvePath(
        pathGroup.getPaths(),
        paths,
        false,
        pathGroup.getMergeWithCore().booleanValue(),
        target,
        false);

    if (log.isDebugEnabled()) {
      log.debug("Resolved the following paths for path group '" + pathGroup + "'");
      for (Iterator i = paths.iterator(); i.hasNext(); ) {
        ResolvedPath path = (ResolvedPath) i.next();
        log.debug(pathResolver.formatPath(path, false));
      }
    }

    ResolvedPath path = pathResolver.merge(paths);

    if (pathGroup.getMergeWithCore().booleanValue()) {
      path = mergeWithCore(path);
    }

    //        System.out.println(pathResolver.formatPath(path, false));
    StringBuffer sb = new StringBuffer();

    for (Iterator i = path.getArtifacts().iterator(); i.hasNext(); ) {
      RepoArtifact artifact = (RepoArtifact) i.next();
      sb.append(artifact.getId().toShortString()).append(";");
    }

    if (log.isDebugEnabled()) {
      log.debug(
          "Resolved path: target="
              + target.getName()
              + ", pathGroup="
              + pathGroupId
              + ", path="
              + sb.toString());
    }

    return path.getArtifacts();
  }
예제 #8
0
  /**
   * Returns a set of properties for the project. The precedence is: quokka.properties
   * quokka.properties of inherited projects plugin.properties No expansion or ordering of
   * properties is done
   */
  public AnnotatedProperties getProperties() {
    AnnotatedProperties resolvedProperties = new AnnotatedProperties();

    // Add the global defaults
    resolvedProperties.put("quokka.project.targetDir", "${basedir}/target");
    resolvedProperties.put("quokka.project.sourceDir", "${basedir}/src");
    resolvedProperties.put("quokka.project.resourcesDir", "${basedir}/resources");

    // Add artifact related properties
    if (project.getArtifacts().size() > 0) {
      // Add properties common to all (group & version)
      RepoArtifactId artifactId =
          ((Artifact) getProject().getArtifacts().iterator().next()).getId();
      resolvedProperties.put("quokka.project.artifact.group", artifactId.getGroup());
      resolvedProperties.put("quokka.project.artifact.version", artifactId.getVersion().toString());

      // Build up a list of names by type
      Map namesByType = new HashMap();

      for (Iterator i = project.getArtifacts().iterator(); i.hasNext(); ) {
        Artifact artifact = (Artifact) i.next();
        artifactId = artifact.getId();

        List names = (List) namesByType.get(artifactId.getType());

        if (names == null) {
          names = new ArrayList();
          namesByType.put(artifactId.getType(), names);
        }

        names.add(artifactId.getName());
      }

      // Output the names
      for (Iterator i = namesByType.entrySet().iterator(); i.hasNext(); ) {
        Map.Entry entry = (Map.Entry) i.next();
        List names = (List) entry.getValue();
        resolvedProperties.put(
            "quokka.project.artifact.name[" + entry.getKey() + "]",
            Strings.join(names.iterator(), ","));
      }
    }

    // Put the plugin properties in first. Order is not important as plugin properties should be
    // unique to their plugin
    for (Iterator i = resolvedTargets.values().iterator(); i.hasNext(); ) {
      Target target = (Target) i.next();
      AnnotatedProperties targetProperties = target.getDefaultProperties();
      resolvedProperties.putAll(
          applyProfiles(targetProperties, project.getActiveProfiles().getElements()));
    }

    // Put in any properties defined in dependency sets (processed in reverse to ensure high levels
    // override low levels)
    resolveProperties(resolvedProperties, project.getDependencySet());

    resolvedProperties.putAll(
        applyProfiles(project.getProperties(), project.getActiveProfiles().getElements()));

    // Put the project paths as properties
    for (Iterator i = resolvedPaths.entrySet().iterator(); i.hasNext(); ) {
      Map.Entry entry = (Map.Entry) i.next();
      resolvedProperties.put(
          "quokka.project.path." + entry.getKey(),
          toAntPath(getProjectPath((String) entry.getKey(), false, true)).toString());
    }

    return resolvedProperties;
  }
예제 #9
0
 private void registerTypes(Target target) {
   // TODO: prevent registration of duplicates?
   for (Iterator i = target.getPlugin().getTypes().iterator(); i.hasNext(); ) {
     repository.getFactory().registerType((RepoType) i.next());
   }
 }
예제 #10
0
 private void registerProjectPaths(Target target) {
   for (Iterator i = target.getProjectPaths().iterator(); i.hasNext(); ) {
     addPath((Path) i.next());
   }
 }
예제 #11
0
  private void addTarget(Map resolved, Target target) {
    //        System.out.println("Adding " + target.getName() + " from " + parents);
    if (target.getPrefix() != null) {
      target.setDefaultProperties(expandPrefix(target.getPrefix(), target.getDefaultProperties()));
    }

    Target existing = (Target) resolved.get(target.getName());

    if (existing != null) {
      RepoArtifactId targetId = target.getPlugin().getArtifact().getId();
      RepoArtifactId existingId = existing.getPlugin().getArtifact().getId();
      Assert.isTrue(
          targetId.equals(existingId),
          target.getLocator(),
          "Multiple targets are defined with the name '"
              + target.getName()
              + "'. Declared in "
              + targetId
              + " and "
              + existingId);

      return;
    }

    resolved.put(target.getName(), target);
    registerTypes(target);
    registerProjectPaths(target);
    buildResources.putAll(target.getPlugin().getBuildResources());

    // PluginDependency declares the target
    addDependentTargets(resolved, target);

    if (target.getImplementsPlugin() != null) {
      // PluginDependency implements the target declared in another plugin
      String[] implementsPlugin = parseImplements(target);
      RepoArtifactId declaringPluginId =
          fastFindMatchingDependency(
              target,
              new RepoArtifactId(
                  implementsPlugin[0], implementsPlugin[1], "plugin", (Version) null));

      Plugin declaringPlugin = getPluginInstance(declaringPluginId);
      String declaringTargetName = declaringPlugin.getNameSpace() + ":" + implementsPlugin[2];

      // Get the declaring plugin and find the matching target
      Target declaringTarget = (Target) resolved.get(declaringTargetName);

      if (declaringTarget == null) {
        declaringTarget = declaringPlugin.getTarget(declaringTargetName);
        Assert.isTrue(
            declaringTarget != null,
            target.getLocator(),
            "'"
                + declaringTargetName
                + "' is not defined in '"
                + declaringPluginId.toShortString()
                + "'");
        addTarget(resolved, declaringTarget);
      }

      Assert.isTrue(
          declaringTarget.isAbstract(),
          target.getLocator(),
          "Target is attempting to implement a non-abstract target: target="
              + target.getName()
              + ", implements="
              + declaringTarget.getName());
      target.getPlugin().setDeclaringPlugin(declaringTarget.getPlugin());

      if (!declaringTarget.isImplemented()) {
        declaringTarget.setImplemented(true);
        declaringTarget.clearDependencies();
      }

      declaringTarget.addDependency(target.getName());

      // Add the declaring targets dependencies to ensure the implementation is executed before them
      for (Iterator i = declaringTarget.getOriginalDependencies().iterator(); i.hasNext(); ) {
        String dependency = (String) i.next();
        target.addDependency(dependency);
      }
    }
  }
예제 #12
0
  private void resolveTargets(Map resolved, PluginDependency pluginDependency) {
    List dependencyTargets = new ArrayList(pluginDependency.getTargets());
    Plugin plugin = getPluginInstance(pluginDependency.getId());
    plugin.setDependency(pluginDependency);

    for (Iterator i = plugin.getTargets().iterator(); i.hasNext(); ) {
      Target target = (Target) i.next();

      // If the target is based on a template internally, merge with the template
      if (target.getTemplateName() != null) {
        String template = target.getTemplateName();
        template =
            (template.indexOf(":") != -1)
                ? template
                : (target.getPlugin().getNameSpace() + ":" + template);
        target.merge(plugin.getTarget(template));
      }

      // Process explicit target definitions
      boolean added = false;

      for (Iterator j = dependencyTargets.iterator(); j.hasNext(); ) {
        PluginDependencyTarget dependencyTarget = (PluginDependencyTarget) j.next();
        Target targetInstance = null;

        if (dependencyTarget.getTemplate() == null) {
          // Enabling a target
          String name = dependencyTarget.getName();
          name =
              (name.indexOf(":") != -1) ? name : (target.getPlugin().getNameSpace() + ":" + name);

          if (target.getName().equals(name)) {
            Assert.isTrue(
                !target.isTemplate(),
                dependencyTarget.getLocator(),
                "The named target '" + name + "' is a template");

            String prefix = dependencyTarget.getPrefix();
            Assert.isTrue(
                (prefix == null) || prefix.equals(target.getPrefix()),
                dependencyTarget.getLocator(),
                "The prefix '"
                    + prefix
                    + "' should match the target prefix '"
                    + target.getPrefix()
                    + "' if specified");

            if (dependencyTarget.getAlias() != null) {
              target.setAlias(dependencyTarget.getAlias());
            }

            targetInstance = target;
          }
        } else {
          // Instantiation of a template
          String template = dependencyTarget.getTemplate();
          template =
              (template.indexOf(":") != -1)
                  ? template
                  : (target.getPlugin().getNameSpace() + ":" + template);

          if (target.getName().equals(template)) {
            Assert.isTrue(
                target.isTemplate(),
                dependencyTarget.getLocator(),
                "The named target '" + template + "' is not a template");
            targetInstance = (Target) target.clone();
            targetInstance.setPrefix(dependencyTarget.getPrefix());
            targetInstance.setTemplateName(target.getName());
            targetInstance.setName(dependencyTarget.getName());
          }
        }

        if (targetInstance != null) {
          added = true;

          for (Iterator k = dependencyTarget.getDependencies().iterator(); k.hasNext(); ) {
            String dependency = (String) k.next();
            targetInstance.addDependency(dependency);
          }

          // Record the plugin dependency target that introduced the target
          // This will be used later for dependency-of processing
          targetInstance.setPluginDependencyTarget(dependencyTarget);

          addTarget(resolved, targetInstance);
          j.remove();
        }
      }

      // Use defaults
      if (!added && pluginDependency.isUseDefaults() && target.isEnabledByDefault()) {
        addTarget(resolved, target);
      }
    }

    if (dependencyTargets.size() != 0) {
      List names = new ArrayList();

      for (Iterator i = dependencyTargets.iterator(); i.hasNext(); ) {
        PluginDependencyTarget target = (PluginDependencyTarget) i.next();
        names.add(target.getName());
      }

      Assert.isTrue(
          false,
          pluginDependency.getLocator(),
          "The following targets are not defined in plugin '"
              + plugin.getArtifact().getId().toShortString()
              + "': "
              + Strings.join(names.iterator(), ","));
    }
  }
예제 #13
0
  public Runnable createTargetInstance(Target target, Properties localProperties, Logger logger) {
    //        System.out.println("DefaultProjectModel.createTargetInstance");
    AntClassLoader loader = null;
    DefaultResources resources;

    try {
      org.apache.tools.ant.types.Path classPath = toAntPath(resolvePathGroup(target, "classpath"));

      // Allow additional classes to added to the plugin classpath. This is primarily designed to
      // allow the additional of instrumented testing classes and libraries for code coverage of
      // integration
      // tests with Cobertura
      String key = "quokka.classpath." + target.getPlugin().getArtifact().getId().getGroup();

      if (log.isDebugEnabled()) {
        log.debug("Searching for additional classpath with key: " + key);
      }

      String additionalPath = System.getProperty(key);

      if ((additionalPath != null) && !additionalPath.trim().equals("")) {
        org.apache.tools.ant.types.Path existing = classPath;
        classPath = new org.apache.tools.ant.types.Path(antProject, additionalPath);
        log.verbose("Prefixing classpath with: " + classPath);
        classPath.append(existing); // Make sure additions override existing
      }

      if ("true".equals(antProject.getProperty("quokka.project.debugclassloaders"))) {
        loader =
            new QuokkaLoader(target, antProject.getClass().getClassLoader(), antProject, classPath);
      } else {
        loader = antProject.createClassLoader(classPath);
      }

      loader.setParent(antProject.getCoreLoader());
      loader.setParentFirst(true);
      loader.setIsolated(false);
      loader.setThreadContextLoader();

      // Initialise this plugin
      Plugin plugin = target.getPlugin();
      loader.forceLoadClass(plugin.getClassName());

      Class pluginClass = Class.forName(plugin.getClassName(), true, loader);
      ws.quokka.core.plugin_spi.Plugin actualPlugin =
          (ws.quokka.core.plugin_spi.Plugin) pluginClass.newInstance();

      if (actualPlugin instanceof MetadataAware) {
        ((MetadataAware) actualPlugin).setMetadata(getMetadata());
      }

      if (actualPlugin instanceof ResourcesAware) {
        resources = new DefaultResources(this, target, antProject, logger);
        ((ResourcesAware) actualPlugin).setResources(resources);
      }

      if (actualPlugin instanceof RepositoryAware) {
        ((RepositoryAware) actualPlugin).setRepository(getRepository());
      }

      if (actualPlugin instanceof RepositoryFactoryAware) {
        ((RepositoryFactoryAware) actualPlugin)
            .setRepositoryFactory(
                (RepositoryFactory) antProject.getReference(ProjectHelper.REPOSITORY_FACTORY));
      }

      if (actualPlugin instanceof ResolverAware) {
        ((ResolverAware) actualPlugin).setResolver(pathResolver);
      }

      if (actualPlugin instanceof ModelFactoryAware) {
        ((ModelFactoryAware) actualPlugin).setModelFactory(getModelFactory());
      }

      actualPlugin.initialise();

      return actualPlugin.getTarget(
          (target.getTemplateName() != null) ? target.getTemplateName() : target.getName());
    } catch (Exception e) {
      throw new BuildException(e);
    } finally {
      if (loader != null) {
        loader.resetThreadContextLoader();
        loader.cleanup();
      }
    }
  }