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(), ","));
    }
  }
  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();
      }
    }
  }