private Features toFeatures(
     Collection<Bundle> addedBundles,
     Collection<Dependency> addedDependencys,
     ObjectFactory objectFactory) {
   Features features = objectFactory.createFeaturesRoot();
   Feature feature = objectFactory.createFeature();
   feature.getBundle().addAll(addedBundles);
   feature.getFeature().addAll(addedDependencys);
   features.getFeature().add(feature);
   return features;
 }
  private void checkChanges(Features newFeatures, ObjectFactory objectFactory)
      throws Exception, IOException, JAXBException, XMLStreamException {
    if (checkDependencyChange) {
      // combine all the dependencies to one feature and strip out versions
      Features features = objectFactory.createFeaturesRoot();
      features.setName(newFeatures.getName());
      Feature feature = objectFactory.createFeature();
      features.getFeature().add(feature);
      for (Feature f : newFeatures.getFeature()) {
        for (Bundle b : f.getBundle()) {
          Bundle bundle = objectFactory.createBundle();
          bundle.setLocation(b.getLocation());
          feature.getBundle().add(bundle);
        }
        for (Dependency d : f.getFeature()) {
          Dependency dependency = objectFactory.createDependency();
          dependency.setName(d.getName());
          feature.getFeature().add(dependency);
        }
      }

      Collections.sort(
          feature.getBundle(),
          new Comparator<Bundle>() {

            public int compare(Bundle bundle, Bundle bundle1) {
              return bundle.getLocation().compareTo(bundle1.getLocation());
            }
          });
      Collections.sort(
          feature.getFeature(),
          new Comparator<Dependency>() {
            public int compare(Dependency dependency, Dependency dependency1) {
              return dependency.getName().compareTo(dependency1.getName());
            }
          });

      if (dependencyCache.exists()) {
        // filter dependencies file
        filter(dependencyCache, filteredDependencyCache);
        // read dependency types, convert to dependencies, compare.
        Features oldfeatures = readFeaturesFile(filteredDependencyCache);
        Feature oldFeature = oldfeatures.getFeature().get(0);

        List<Bundle> addedBundles = new ArrayList<Bundle>(feature.getBundle());
        List<Bundle> removedBundles = new ArrayList<Bundle>();
        for (Bundle test : oldFeature.getBundle()) {
          boolean t1 = addedBundles.contains(test);
          int s1 = addedBundles.size();
          boolean t2 = addedBundles.remove(test);
          int s2 = addedBundles.size();
          if (t1 != t2) {
            getLog().warn("dependencies.contains: " + t1 + ", dependencies.remove(test): " + t2);
          }
          if (t1 == (s1 == s2)) {
            getLog()
                .warn(
                    "dependencies.contains: "
                        + t1
                        + ", size before: "
                        + s1
                        + ", size after: "
                        + s2);
          }
          if (!t2) {
            removedBundles.add(test);
          }
        }

        List<Dependency> addedDependencys = new ArrayList<Dependency>(feature.getFeature());
        List<Dependency> removedDependencys = new ArrayList<Dependency>();
        for (Dependency test : oldFeature.getFeature()) {
          boolean t1 = addedDependencys.contains(test);
          int s1 = addedDependencys.size();
          boolean t2 = addedDependencys.remove(test);
          int s2 = addedDependencys.size();
          if (t1 != t2) {
            getLog().warn("dependencies.contains: " + t1 + ", dependencies.remove(test): " + t2);
          }
          if (t1 == (s1 == s2)) {
            getLog()
                .warn(
                    "dependencies.contains: "
                        + t1
                        + ", size before: "
                        + s1
                        + ", size after: "
                        + s2);
          }
          if (!t2) {
            removedDependencys.add(test);
          }
        }
        if (!addedBundles.isEmpty()
            || !removedBundles.isEmpty()
            || !addedDependencys.isEmpty()
            || !removedDependencys.isEmpty()) {
          saveDependencyChanges(
              addedBundles, removedBundles, addedDependencys, removedDependencys, objectFactory);
          if (overwriteChangedDependencies) {
            writeDependencies(features, dependencyCache);
          }
        } else {
          getLog().info(saveTreeListing());
        }

      } else {
        writeDependencies(features, dependencyCache);
      }
    }
  }
  /*
   * Write all project dependencies as feature
   */
  private void writeFeatures(PrintStream out)
      throws ArtifactResolutionException, ArtifactNotFoundException, IOException, JAXBException,
          SAXException, ParserConfigurationException, XMLStreamException, MojoExecutionException {
    getLog().info("Generating feature descriptor file " + outputFile.getAbsolutePath());
    // read in an existing feature.xml
    ObjectFactory objectFactory = new ObjectFactory();
    Features features;
    if (inputFile.exists()) {
      filter(inputFile, filteredInputFile);
      features = readFeaturesFile(filteredInputFile);
    } else {
      features = objectFactory.createFeaturesRoot();
    }
    if (features.getName() == null) {
      features.setName(project.getArtifactId());
    }

    Feature feature = null;
    for (Feature test : features.getFeature()) {
      if (test.getName().equals(project.getArtifactId())) {
        feature = test;
      }
    }
    if (feature == null) {
      feature = objectFactory.createFeature();
      feature.setName(project.getArtifactId());
    }
    if (!feature.hasVersion()) {
      feature.setVersion(project.getArtifact().getBaseVersion());
    }
    if (feature.getDescription() == null) {
      feature.setDescription(project.getName());
    }
    if (resolver != null) {
      feature.setResolver(resolver);
    }
    if (installMode != null) {
      feature.setInstall(installMode);
    }
    if (project.getDescription() != null && feature.getDetails() == null) {
      feature.setDetails(project.getDescription());
    }
    if (includeProjectArtifact) {
      Bundle bundle = objectFactory.createBundle();
      bundle.setLocation(this.dependencyHelper.artifactToMvn(project.getArtifact()));
      if (startLevel != null) {
        bundle.setStartLevel(startLevel);
      }
      feature.getBundle().add(bundle);
    }
    for (Map.Entry<?, String> entry : localDependencies.entrySet()) {
      Object artifact = entry.getKey();

      if (excludedArtifactIds.contains(this.dependencyHelper.getArtifactId(artifact))) {
        continue;
      }

      if (this.dependencyHelper.isArtifactAFeature(artifact)) {
        if (aggregateFeatures
            && FEATURE_CLASSIFIER.equals(this.dependencyHelper.getClassifier(artifact))) {
          File featuresFile = this.dependencyHelper.resolve(artifact, getLog());
          if (featuresFile == null || !featuresFile.exists()) {
            throw new MojoExecutionException(
                "Cannot locate file for feature: " + artifact + " at " + featuresFile);
          }
          Features includedFeatures = readFeaturesFile(featuresFile);
          // TODO check for duplicates?
          features.getFeature().addAll(includedFeatures.getFeature());
        }
      } else if (addBundlesToPrimaryFeature) {
        String bundleName = this.dependencyHelper.artifactToMvn(artifact);
        File bundleFile = this.dependencyHelper.resolve(artifact, getLog());
        Manifest manifest = getManifest(bundleFile);

        if (manifest == null || !ManifestUtils.isBundle(getManifest(bundleFile))) {
          bundleName = "wrap:" + bundleName;
        }

        Bundle bundle = null;
        for (Bundle b : feature.getBundle()) {
          if (bundleName.equals(b.getLocation())) {
            bundle = b;
            break;
          }
        }
        if (bundle == null) {
          bundle = objectFactory.createBundle();
          bundle.setLocation(bundleName);
          if (!"provided".equals(entry.getValue()) || !ignoreScopeProvided) {
            feature.getBundle().add(bundle);
          }
        }
        if ("runtime".equals(entry.getValue())) {
          bundle.setDependency(true);
        }
        if (startLevel != null && bundle.getStartLevel() == 0) {
          bundle.setStartLevel(startLevel);
        }
      }
    }

    if ((!feature.getBundle().isEmpty() || !feature.getFeature().isEmpty())
        && !features.getFeature().contains(feature)) {
      features.getFeature().add(feature);
    }

    JaxbUtil.marshal(features, out);
    try {
      checkChanges(features, objectFactory);
    } catch (Exception e) {
      throw new MojoExecutionException("Features contents have changed", e);
    }
    getLog().info("...done!");
  }