incubator-aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mnutt...@apache.org
Subject svn commit: r989601 [2/3] - in /incubator/aries/trunk/application/application-modeller: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/aries/ src/main/java/org/apache/aries/application/ src/main/j...
Date Thu, 26 Aug 2010 11:04:42 GMT
Added: incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/internal/PackageRequirementMerger.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/internal/PackageRequirementMerger.java?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/internal/PackageRequirementMerger.java (added)
+++ incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/internal/PackageRequirementMerger.java Thu Aug 26 11:04:41 2010
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.application.modelling.internal;
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.aries.application.modelling.ImportedPackage;
+import org.apache.aries.application.modelling.utils.ModellingUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class to merge collections of package requirements, such that multiple requirements
+ * for the same package are consolidated to a single requirement with a version constraint
+ * that is the intersection of the original version requirements.
+ */
+public final class PackageRequirementMerger
+{
+  private final Logger logger = LoggerFactory.getLogger(PackageRequirementMerger.class);
+  /** The merged requirements, or null if the merge failed. */
+  private final Collection<ImportedPackage> mergedRequirements;
+  /** Names of packages for which requirements were incompatible. */
+  private final Set<String> invalidRequirements = new HashSet<String>();
+  
+  /**
+   * Constructor.
+   * @param requirements the package requirements to be merged.
+   * @throws NullPointerException if the parameter is {@code null}.
+   */
+  public PackageRequirementMerger(Collection<ImportedPackage> requirements)
+  {
+    logger.debug(LOG_ENTRY, "PackageRequirementMerger", requirements);
+    
+    if (requirements == null)
+    {
+      NullPointerException npe = new NullPointerException();
+      logger.debug(LOG_EXIT, "PackageRequirementMerger", npe);
+      throw npe;
+    }
+
+    // Do the merge.
+    Map<String, ImportedPackage> reqMap = new HashMap<String, ImportedPackage>();
+    for (ImportedPackage req : requirements)
+    {
+      String pkgName = req.getPackageName();
+      ImportedPackage existingReq = reqMap.get(pkgName);
+      if (existingReq == null)
+      {
+        reqMap.put(pkgName, req);
+        continue;
+      }
+      
+      ImportedPackage intersectReq = ModellingUtils.intersectPackage(req, existingReq);
+      if (intersectReq != null)
+      {
+        reqMap.put(pkgName, intersectReq);
+        continue;
+      }
+
+      invalidRequirements.add(pkgName);
+    }
+    
+    mergedRequirements = (invalidRequirements.isEmpty() ? reqMap.values() : null);
+    logger.debug(LOG_EXIT,"PackageRequirementMerger");
+    }
+
+  /**
+   * Check if the requirements could be successfully merged.
+   * @return true if the merge was successful; false if the requirements were not compatible.
+   */
+  public boolean isMergeSuccessful()
+  {
+    logger.debug(LOG_ENTRY, "isMergeSuccessful");
+    boolean result = mergedRequirements != null;
+    logger.debug(LOG_EXIT, "isMergeSuccessful", result);
+    return result;
+  }
+  
+  /**
+   * Get the merged package requirements. The result will mirror the input collection,
+   * except that multiple requirements for the same package will be replaced by a single
+   * requirement that is the intersection of all the input requirements.
+   * <p>
+   * The {@code isMergeSuccessful} method should be checked for success prior to calling this method.
+   * @param inputRequirements
+   * @return A collection of package requirements, or {@code null} if the input contained incompatible requirements.
+   * @throws IllegalStateException if the merge was not successful.
+   */
+  public Collection<ImportedPackage> getMergedRequirements()
+  {
+    logger.debug(LOG_ENTRY, "getMergedRequirements");
+    if (mergedRequirements == null)
+    {
+      IllegalStateException ise = new IllegalStateException();
+      logger.debug(LOG_EXIT, "getMergedRequirements", ise);
+      throw ise;
+    }
+    logger.debug(LOG_EXIT, "getMergedRequirements", mergedRequirements);
+    return Collections.unmodifiableCollection(mergedRequirements);
+  }
+  
+  /**
+   * Get the names of packages that caused the merge to fail due to their constraints
+   * being mutually exclusive.
+   * @return an unmodifiable set of package names.
+   */
+  public Set<String> getInvalidRequirements()
+  {
+    logger.debug(LOG_ENTRY, "getInvalidRequirements");
+    logger.debug(LOG_EXIT, "getInvalidRequirements", invalidRequirements);
+    return Collections.unmodifiableSet(invalidRequirements);
+  }
+
+}

Added: incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/DeployedBundles.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/DeployedBundles.java?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/DeployedBundles.java (added)
+++ incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/DeployedBundles.java Thu Aug 26 11:04:41 2010
@@ -0,0 +1,459 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.application.modelling.utils;
+
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.aries.application.management.ResolverException;
+import org.apache.aries.application.modelling.DeploymentMFElement;
+import org.apache.aries.application.modelling.ExportedBundle;
+import org.apache.aries.application.modelling.ExportedPackage;
+import org.apache.aries.application.modelling.ExportedService;
+import org.apache.aries.application.modelling.ImportedBundle;
+import org.apache.aries.application.modelling.ImportedPackage;
+import org.apache.aries.application.modelling.ImportedService;
+import org.apache.aries.application.modelling.ModelledResource;
+import org.apache.aries.application.modelling.impl.ImportedPackageImpl;
+import org.apache.aries.application.modelling.internal.MessageUtil;
+import org.apache.aries.application.modelling.internal.PackageRequirementMerger;
+import org.apache.aries.application.utils.AppConstants;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * Class to generate DEPLOYMENT.MF manifest entries for resolved bundles based on
+ * corresponding APPLICATION.MF entries.
+ */
+public final class DeployedBundles
+{
+  private final Logger logger = LoggerFactory.getLogger(DeployedBundles.class);
+  private final String assetName;
+
+  /** Content from APPLICATION.MF */
+  private final Set<ImportedBundle> appContent = new HashSet<ImportedBundle>();
+  /** Use Bundle from APPLICATION.MF */
+  private final Set<ImportedBundle> appUseBundle = new HashSet<ImportedBundle>();
+  /** Content for deployment.mf deployed-content. */
+  private final Set<ModelledResource> deployedContent = new HashSet<ModelledResource>();
+  /** Content for deployment.mf use-bundle. */
+  private final Set<ModelledResource> deployedUseBundle = new HashSet<ModelledResource>();
+  /** Content for deployment.mf provision-bundle. */
+  private final Set<ModelledResource> deployedProvisionBundle = new HashSet<ModelledResource>();
+  /** Content for deployment.mf DeployedImport-Service. */
+  private final Collection<ImportedService> deployedImportService = new HashSet<ImportedService>(); 
+  private final Collection<ModelledResource> fakeDeployedBundles = new HashSet<ModelledResource>();
+  
+  /**
+   * Constructor for cases when we have one or more '
+   * @param assetName         the name of the asset being deployed.
+   * @param appContentNames   the bundle names specified in Deployed-Content.
+   * @param appUseBundleNames the bundle names specified in Deployed-Use-Bundle.
+   * @param fakeServiceProvidingBundles  bundles that we're pretending are part of the deployed content. Can be null. 
+   *                                     These bundles are proxies for bundles provided (for example by SCA) that export
+   *                                     services matching Application-ImportService. 
+   */
+  public DeployedBundles(String assetName, Collection<ImportedBundle> appContentNames, 
+      Collection<ImportedBundle> appUseBundleNames, Collection<ModelledResource> fakeServiceProvidingBundles)
+  {
+    logger.debug(LOG_ENTRY, "DeployedBundles", new Object[]{appContentNames, appUseBundleNames, fakeServiceProvidingBundles});
+    
+    this.assetName = assetName;
+
+    appContent.addAll(appContentNames);
+    appUseBundle.addAll(appUseBundleNames);
+    if (fakeServiceProvidingBundles != null) { 
+      fakeDeployedBundles.addAll(fakeServiceProvidingBundles);
+    }
+    logger.debug(LOG_EXIT, "DeployedBundles");
+  }
+  
+  /**
+   * Add provisioned version information for a specific bundle name. This will be added to the
+   * appropriate manifest header for the specified bundle.
+   * @param resolvedBundle the bundle that has been provisioned.
+   * @param resolvedVersion the specific version provisioned.
+   */
+  public void addBundle(ModelledResource modelledBundle)
+  {
+    logger.debug(LOG_ENTRY, "addBundle", new Object[]{modelledBundle});
+    // Identify the deployment.mf entries the bundle should be added to by matching
+    // both the bundle name and resolved version against the name and version range
+    // defined in application.mf.
+    
+    ExportedBundle resolvedBundle = modelledBundle.getExportedBundle();
+    
+    if (isBundleMatch(appContent, resolvedBundle))
+    {
+      logger.debug("Added to " + AppConstants.DEPLOYMENT_CONTENT + ": " + resolvedBundle);
+     
+      deployedContent.add(modelledBundle);
+      
+      // Add any service dependencies to the list
+      deployedImportService.addAll(modelledBundle.getImportedServices());
+    }
+    else if (isBundleMatch(appUseBundle, resolvedBundle))
+    {
+      logger.debug("Added to " + AppConstants.DEPLOYMENT_USE_BUNDLE + ": " + resolvedBundle);
+      deployedUseBundle.add(modelledBundle);
+    } else
+    {
+      logger.debug("Added to " + AppConstants.DEPLOYMENT_PROVISION_BUNDLE + ": " + resolvedBundle);
+      deployedProvisionBundle.add(modelledBundle);
+    }
+   logger.debug(LOG_EXIT, "addBundle");    
+  }
+
+  /**
+   * Check if a match is found between the supplied map of application bundle name/version information,
+   * and the supplied bundle name and version.
+   * @param imports Imported bundles
+   * @param potentialMatch the exported bundle or composite we're interested in
+   * @return true if a match is found; otherwise false.
+   */
+  private boolean isBundleMatch(Set<ImportedBundle> imports, ExportedBundle potentialMatch)
+  {
+    boolean result = false;
+    
+    for (ImportedBundle ib : imports)
+    {
+      if (ib.isSatisfied(potentialMatch))
+      {
+        result = true;
+        break;
+      }
+    }
+  
+    return result;
+  }
+  
+  /**
+   * Get the value corresponding to the Deployed-Content header in the deployment.mf.
+   * @return a manifest entry, or an empty string if there is no content.
+   */
+  public String getContent()
+  {
+    return createManifestString(deployedContent);
+  }
+  
+  /**
+   * Get the value corresponding to the Deployed-Use-Bundle header in the deployment.mf.
+   * @return a manifest entry, or an empty string if there is no content.
+   */
+  public String getUseBundle()
+  {
+    return createManifestString(deployedUseBundle);
+  }
+  
+  /**
+   * Get the value corresponding to the Provision-Bundle header in the deployment.mf.
+   * @return a manifest entry, or an empty string if there is no content.
+   */
+  public String getProvisionBundle()
+  {
+    return createManifestString(deployedProvisionBundle);
+  }
+  
+  /**
+   * Get the value corresponding to the Import-Package header in the deployment.mf. 
+   * @return a manifest entry, or an empty string if there is no content.
+   * @throws ResolverException if the requirements could not be resolved.
+   */
+  public String getImportPackage()
+    throws ResolverException
+  {
+    logger.debug(LOG_ENTRY, "getImportPackage");
+    Collection<ImportedPackage> externalReqs = new ArrayList<ImportedPackage>(getExternalPackageRequirements());
+
+    //Validate that we don't have attributes that will break until RFC138 is used
+    validateOtherImports(externalReqs);
+    
+    // Find the matching capabilities from bundles in use bundle, and prune
+    // matched requirements out of the external requirements collection.
+    Map<ImportedPackage,ExportedPackage> useBundlePkgs = new HashMap<ImportedPackage,ExportedPackage>();
+    for (Iterator<ImportedPackage> iter = externalReqs.iterator(); iter.hasNext(); )
+    {
+      ImportedPackage req = iter.next();
+      ExportedPackage match = getPackageMatch(req, deployedUseBundle);
+      if (match != null)
+      {
+        useBundlePkgs.put(req, match);
+        iter.remove();
+      }
+    }
+    
+    
+    StringBuilder useBundleImports = new StringBuilder();
+    for(Map.Entry<ImportedPackage, ExportedPackage> entry : useBundlePkgs.entrySet()) {
+      useBundleImports.append(entry.getValue().toDeploymentString());
+      ImportedPackage key = entry.getKey();
+      if(key.isOptional())
+        useBundleImports.append(";" + Constants.RESOLUTION_DIRECTIVE +":=" + Constants.RESOLUTION_OPTIONAL);
+      useBundleImports.append(",");
+    }
+    
+    String result = useBundleImports.toString() + createManifestString(externalReqs);
+    
+    if(result.endsWith(","))
+      result = result.substring(0, result.length() - 1);
+    logger.debug(LOG_EXIT, "getImportPackage", result);
+    return result;
+  }
+  
+  /**
+   * Get the Deployed-ImportService header. 
+   * this.deployedImportService contains all the service import filters for every 
+   * blueprint component within the application. We will only write an entry
+   * to Deployed-ImportService if
+   *   a) the reference isMultiple(), or
+   *   b) the service was not available internally when the app was first deployed
+   *   
+   */
+  public String getDeployedImportService() { 
+    logger.debug(LOG_ENTRY,"getDeployedImportService");
+    Collection<ImportedService> deployedBundleServiceImports = new ArrayList<ImportedService>();
+    Collection<ExportedService> servicesExportedWithinIsolatedContent = new ArrayList<ExportedService>();
+    for (ModelledResource mRes : getDeployedContent()) { 
+      servicesExportedWithinIsolatedContent.addAll(mRes.getExportedServices());
+    }
+    for (ModelledResource mRes : fakeDeployedBundles) { 
+      servicesExportedWithinIsolatedContent.addAll(mRes.getExportedServices());
+    }
+    for (ImportedService impService : deployedImportService) { 
+      if (impService.isMultiple()) { 
+        deployedBundleServiceImports.add(impService);
+      } else { 
+        boolean serviceProvidedWithinIsolatedContent = false;
+        Iterator<ExportedService> it = servicesExportedWithinIsolatedContent.iterator();
+        while (!serviceProvidedWithinIsolatedContent && it.hasNext()) { 
+          ExportedService svc = it.next(); 
+          serviceProvidedWithinIsolatedContent |= impService.isSatisfied(svc);
+        }
+        if (!serviceProvidedWithinIsolatedContent) { 
+          deployedBundleServiceImports.add(impService);
+        }
+      }
+    }
+    
+    String result = createManifestString(deployedBundleServiceImports);
+    logger.debug(LOG_EXIT,"getDeployedImportService", result);
+    
+    return result;
+  }
+  /**
+   * Get all the requirements of bundles in deployed content that are not satisfied
+   * by other bundles in deployed content.
+   * @return a collection of package requirements.
+   * @throws ResolverException if the requirements could not be resolved.
+   */
+  private Collection<ImportedPackage> getExternalPackageRequirements()
+    throws ResolverException
+  {
+    logger.debug(LOG_ENTRY,"getExternalPackageRequirements");
+    
+    // Get all the internal requirements.
+    Collection<ImportedPackage> requirements = new ArrayList<ImportedPackage>();
+    for (ModelledResource bundle : deployedContent)
+    {
+      requirements.addAll(bundle.getImportedPackages());
+    }
+    
+    // Filter out requirements satisfied by internal capabilities.
+    Collection<ImportedPackage> result = new ArrayList<ImportedPackage>();
+    for (ImportedPackage req : requirements)
+    {
+      ExportedPackage match = getPackageMatch(req, deployedContent);
+      //If we didn't find a match then it must come from outside
+      if (match == null)
+      {
+        result.add(req);
+      }
+    }
+    
+    PackageRequirementMerger merger = new PackageRequirementMerger(result);
+    if (!merger.isMergeSuccessful())
+    {
+      List<String> pkgNames = new ArrayList<String>(merger.getInvalidRequirements());
+      
+      StringBuilder buff = new StringBuilder();
+      for (String pkgName : merger.getInvalidRequirements())
+      {
+        buff.append(pkgName).append(", ");
+      }
+
+      int buffLen = buff.length();
+      String pkgString = (buffLen > 0 ? buff.substring(0, buffLen - 2) : "");
+
+      ResolverException re = new ResolverException(MessageUtil.getMessage(
+          "INCOMPATIBLE_PACKAGE_VERSION_REQUIREMENTS", new Object[] { assetName, pkgString }));
+      re.setUnsatisfiedRequirements(pkgNames);
+      logger.debug(LOG_EXIT,"getExternalPackageRequirements", re);
+      
+      throw re;
+    }
+    
+    result = merger.getMergedRequirements();
+    logger.debug(LOG_EXIT,"getExternalPackageRequirements", result);
+    
+    return result;
+  }
+  
+  /**
+   * Create entries for the Import-Package header corresponding to the supplied
+   * packages, referring to bundles not in Use-Bundle.
+   * @param requirements packages for which entries should be created.
+   * @return manifest header entries.
+   * @throws ResolverException if the imports are invalid.
+   */
+  private void validateOtherImports(Collection<ImportedPackage> requirements)
+    throws ResolverException
+  {
+    logger.debug(LOG_ENTRY, "validateOtherImports", requirements);
+    for (ImportedPackage req : requirements)
+    {
+      String pkgName = req.getPackageName();
+
+      for (String name : req.getAttributes().keySet())
+      {
+        if (Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE.equals(name)
+            || Constants.BUNDLE_VERSION_ATTRIBUTE.equals(name))
+        {
+          ResolverException re = new ResolverException(MessageUtil.getMessage(
+              "INVALID_PACKAGE_REQUIREMENT_ATTRIBUTES", new Object[] { assetName, name, pkgName }));
+          re.setUnsatisfiedRequirements(Arrays.asList(pkgName));
+          logger.debug(LOG_EXIT, "validateOtherImports", re);
+          throw re;
+        }
+      }
+    }
+    logger.debug(LOG_EXIT, "validateOtherImports");
+  }
+
+  /**
+   * Get a package match between the specified requirement and a capability of the supplied
+   * bundles. The resulting match object might not refer to any matching capability.
+   * @param requirement the {@link ImportedPackageImpl} to be matched.
+   * @param bundles the bundles to be searched for matching capabilities.
+   * @return an ExportedPackageImpl or null if no match is found.
+   */
+  private ExportedPackage getPackageMatch(ImportedPackage requirement, Collection<ModelledResource> bundles)
+  {
+    logger.debug(LOG_ENTRY, "getPackageMatch", new Object[]{requirement, bundles});
+    ExportedPackage result = null;
+    
+    outer: for (ModelledResource bundle : bundles)
+    {
+      for (ExportedPackage pkg : bundle.getExportedPackages())
+      {
+        if(requirement.isSatisfied(pkg)) {
+          result = pkg;
+          break outer;
+        }
+      }
+    }
+    logger.debug(LOG_EXIT, "getPackageMatch", new Object[]{result});
+    return result;
+  }
+  
+  private String createManifestString(Collection<? extends DeploymentMFElement> values)
+  {
+    logger.debug(LOG_ENTRY, "createManifestString", new Object[]{values});
+    StringBuilder builder = new StringBuilder();
+    for (DeploymentMFElement value : values)
+    {
+      builder.append(value.toDeploymentString()).append(",");
+    }
+    
+    int length = builder.length();
+    String result = (length > 0 ? builder.substring(0, length - 1) : "");
+    logger.debug(LOG_EXIT, "createManifestString", new Object[]{result});
+    return result;
+  }
+  
+
+  public String toString()
+  {
+    return AppConstants.DEPLOYMENT_CONTENT + '=' + deployedContent + ' ' +
+        AppConstants.DEPLOYMENT_USE_BUNDLE + '=' + deployedUseBundle + ' ' +
+        AppConstants.DEPLOYMENT_PROVISION_BUNDLE + '=' + deployedProvisionBundle;/* + ' ' /*+
+        AppConstants.WAS_FEATURE_REQUIRED + "=" + requiredFeatures;*/
+  }
+  
+  /**
+   * Get the set of bundles that are going to be deployed into an isolated framework
+   * @return a set of bundle metadata
+   */
+  public Collection<ModelledResource> getDeployedContent()
+  {
+    logger.debug(LOG_ENTRY, "getDeployedContent");
+    logger.debug(LOG_EXIT,"getDeployedContent", deployedContent);
+    return Collections.unmodifiableCollection(deployedContent);
+  }
+  
+  /**
+   * Get the set of bundles that map to Provision-Bundle: these plus 
+   * getRequiredUseBundle combined give the bundles that will be provisioned
+   * into the shared bundle space
+   * 'getProvisionBundle' returns the manifest header string, so this method 
+   * needs to be called something else. 
+   *
+   */
+  public Collection<ModelledResource> getDeployedProvisionBundle () 
+  { 
+    logger.debug(LOG_ENTRY,"getDeployedProvisionBundle");
+    logger.debug(LOG_EXIT, "getDeployedProvisionBundle", deployedContent);
+    return Collections.unmodifiableCollection(deployedProvisionBundle);
+  }
+  
+  /**
+   * Get the subset of bundles specified in use-bundle that are actually required to
+   * satisfy direct requirements of deployed content.
+   * @return a set of bundle metadata.
+   * @throws ResolverException if the requirements could not be resolved.
+   */
+  public Collection<ModelledResource> getRequiredUseBundle()
+    throws ResolverException
+  {
+    logger.debug(LOG_ENTRY, "getRequiredUseBundle");
+    Collection<ImportedPackage> externalReqs = getExternalPackageRequirements();
+    Collection<ModelledResource> usedUseBundles = new HashSet<ModelledResource>();
+    for (ImportedPackage req : externalReqs)
+    {
+      // Find a match from the supplied bundle capabilities.
+      ExportedPackage match = getPackageMatch(req, deployedUseBundle);
+      if (match != null)
+      {
+          usedUseBundles.add(match.getBundle());
+      }
+    }
+    logger.debug(LOG_EXIT, "getRequiredUseBundle", usedUseBundles);
+    return usedUseBundles;
+  }
+}

Added: incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingConstants.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingConstants.java?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingConstants.java (added)
+++ incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingConstants.java Thu Aug 26 11:04:41 2010
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.application.modelling.utils;
+
+import org.osgi.framework.Constants;
+
+public class ModellingConstants
+{
+  public static final String OBR_SYMBOLIC_NAME = "symbolicname";
+  public static final String OBR_PRESENTATION_NAME = "presentationname";
+  public static final String OBR_MANIFEST_VERSION = "manifestversion";
+  public static final String OBR_BUNDLE = "bundle";
+  public static final String OBR_PACKAGE = "package";
+  public static final String OBR_SERVICE = "service";
+  public static final String OBR_COMPOSITE_BUNDLE = "composite-bundle";
+  public static final String OPTIONAL_KEY = Constants.RESOLUTION_DIRECTIVE + ":";
+}

Added: incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingManager.java?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingManager.java (added)
+++ incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingManager.java Thu Aug 26 11:04:41 2010
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.application.modelling.utils;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.jar.Attributes;
+
+import org.apache.aries.application.management.BundleInfo;
+import org.apache.aries.application.management.InvalidAttributeException;
+import org.apache.aries.application.modelling.ExportedBundle;
+import org.apache.aries.application.modelling.ExportedPackage;
+import org.apache.aries.application.modelling.ExportedService;
+import org.apache.aries.application.modelling.ImportedBundle;
+import org.apache.aries.application.modelling.ImportedPackage;
+import org.apache.aries.application.modelling.ImportedService;
+import org.apache.aries.application.modelling.ModelledResource;
+import org.apache.aries.application.modelling.ParsedServiceElements;
+import org.apache.aries.application.modelling.impl.ExportedBundleImpl;
+import org.apache.aries.application.modelling.impl.ExportedPackageImpl;
+import org.apache.aries.application.modelling.impl.ExportedServiceImpl;
+import org.apache.aries.application.modelling.impl.ImportedBundleImpl;
+import org.apache.aries.application.modelling.impl.ImportedPackageImpl;
+import org.apache.aries.application.modelling.impl.ImportedServiceImpl;
+import org.apache.aries.application.modelling.impl.ModelledResourceImpl;
+import org.apache.aries.application.modelling.impl.ParsedServiceElementsImpl;
+
+public class ModellingManager
+{
+
+  public  static ExportedBundle getExportedBundle(Map<String, String> attributes, ImportedBundle fragHost) {
+
+    return new ExportedBundleImpl(attributes, fragHost);
+  }
+  public  static ExportedPackage getExportedPackage(ModelledResource mr, String pkg, Map<String, Object> attributes)  {
+
+    return new ExportedPackageImpl(mr, pkg, attributes);
+  }
+  public static  ExportedService getExportedService(String name, int ranking, Collection<String> ifaces, 
+      Map<String, Object> serviceProperties ) {
+    return new ExportedServiceImpl (name, ranking, ifaces, serviceProperties );
+  }
+  @SuppressWarnings("deprecation")
+  public static ExportedService getExportedService(String ifaceName, Map<String, String> attrs) {
+    return new ExportedServiceImpl (ifaceName, attrs );
+  }
+  
+  public static ImportedBundle getImportedBundle(String filterString, Map<String, String> attributes) throws InvalidAttributeException {
+    return new ImportedBundleImpl(filterString, attributes);
+  }
+  
+  public static ImportedBundle getImportedBundle(String bundleName, String versionRange) throws InvalidAttributeException {
+    return new ImportedBundleImpl(bundleName, versionRange);
+  }
+  
+  public static ImportedPackage getImportedPackage(String pkg, Map<String, String> attributes) throws InvalidAttributeException{
+    return new ImportedPackageImpl(pkg, attributes);
+  }
+  
+  public static ImportedService getImportedService(boolean optional, String iface, String componentName, 
+      String blueprintFilter, String id, boolean isMultiple) throws InvalidAttributeException{
+    return new ImportedServiceImpl(optional, iface, componentName, blueprintFilter, id, isMultiple);
+  }
+  @SuppressWarnings("deprecation")
+  public static ImportedService getImportedService(String ifaceName, Map<String, String> attributes) throws InvalidAttributeException{
+    return new ImportedServiceImpl(ifaceName, attributes);
+  }
+  
+  public static ModelledResource getModelledResource(String fileURI, BundleInfo bundleInfo, 
+      Collection<ImportedService> importedServices, 
+      Collection<ExportedService> exportedServices) throws InvalidAttributeException {
+    return new ModelledResourceImpl(fileURI, bundleInfo, importedServices, exportedServices);
+    
+  }
+  
+  public static ModelledResource getModelledResource(String fileURI, Attributes bundleAttributes, 
+      Collection<ImportedService> importedServices, 
+      Collection<ExportedService> exportedServices) throws InvalidAttributeException {
+    return new ModelledResourceImpl(fileURI, bundleAttributes, importedServices, exportedServices);
+    
+  }
+  
+  public static ParsedServiceElements getParsedServiceElements ( Collection<ExportedService> services, 
+      Collection<ImportedService> references) {
+    return new ParsedServiceElementsImpl(services, references);
+  }
+}

Added: incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingUtils.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingUtils.java?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingUtils.java (added)
+++ incubator/aries/trunk/application/application-modeller/src/main/java/org/apache/aries/application/modelling/utils/ModellingUtils.java Thu Aug 26 11:04:41 2010
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.application.modelling.utils;
+
+import static org.apache.aries.application.modelling.utils.ModellingConstants.OPTIONAL_KEY;
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+import static org.osgi.framework.Constants.BUNDLE_VERSION_ATTRIBUTE;
+import static org.osgi.framework.Constants.VERSION_ATTRIBUTE;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.application.VersionRange;
+import org.apache.aries.application.management.InvalidAttributeException;
+import org.apache.aries.application.modelling.ImportedBundle;
+import org.apache.aries.application.modelling.ImportedPackage;
+import org.apache.aries.application.modelling.Provider;
+import org.apache.aries.application.modelling.impl.ImportedBundleImpl;
+import org.apache.aries.application.modelling.impl.ImportedPackageImpl;
+import org.apache.aries.application.modelling.internal.MessageUtil;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor.NameValueMap;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class ModellingUtils
+{
+  private static final  Logger logger = LoggerFactory.getLogger(ModellingUtils.class);
+  /**
+   * Check that all mandatory attributes from a Provider are specified by the consumer's attributes
+   * @param consumerAttributes
+   * @param p
+   * @return true if all mandatory attributes are present, or no attributes are mandatory
+   */
+  public static boolean areMandatoryAttributesPresent(Map<String,String> consumerAttributes, Provider p) {
+    logger.debug(LOG_ENTRY, "areMandatoryAttributesPresent", new Object[]{consumerAttributes, p});
+    boolean allPresent = true;
+    String mandatory = (String) p.getAttributes().get(Constants.MANDATORY_DIRECTIVE + ":");
+    
+    if(mandatory != null && !mandatory.equals("")) {
+      List<String> attributeNames = ManifestHeaderProcessor.split(mandatory, ",");
+      
+      for(String name : attributeNames) {
+        allPresent = consumerAttributes.containsKey(name);
+        if(!allPresent)
+          break;
+      }
+    }
+    logger.debug(LOG_EXIT, "areMandatoryAttributesPresent", allPresent);
+    return allPresent;
+  }
+  
+  
+  
+  public static ImportedBundle buildFragmentHost(String fragmentHostHeader) throws InvalidAttributeException {
+    logger.debug(LOG_ENTRY, "buildFragmentHost", new Object[]{fragmentHostHeader});
+    if(fragmentHostHeader == null) { 
+      
+      return null;
+    }
+    Map<String, NameValueMap<String, String>> parsedFragHost = ManifestHeaderProcessor.parseImportString(fragmentHostHeader);
+    if(parsedFragHost.size() != 1)
+      throw new InvalidAttributeException(MessageUtil.getMessage("APPUTILS0001W",
+          new Object[] {fragmentHostHeader}, 
+          "An internal error occurred. A bundle fragment manifest must define exactly one Fragment-Host entry. The following entry was found" + fragmentHostHeader + "."));
+    
+    String hostName = parsedFragHost.keySet().iterator().next();
+    Map<String, String> attribs = parsedFragHost.get(hostName);
+    
+    String bundleVersion = attribs.remove(BUNDLE_VERSION_ATTRIBUTE);
+    if (bundleVersion != null && attribs.get(VERSION_ATTRIBUTE) == null) { 
+      attribs.put (VERSION_ATTRIBUTE, bundleVersion);
+    }
+    attribs.put(ModellingConstants.OBR_SYMBOLIC_NAME, hostName);  
+    
+    String filter = ManifestHeaderProcessor.generateFilter(attribs);
+    
+    ImportedBundle result = new ImportedBundleImpl(filter, attribs);
+    logger.debug(LOG_EXIT, "buildFragmentHost", result);
+    return result;
+  }
+  
+  /**
+   * Create a new ImnportedPackage that is the intersection of the two supplied imports.
+   * @param p1
+   * @param p2
+   * @return ImportedPackageImpl representing the intersection, or null. All attributes must match exactly.
+   */
+  public static ImportedPackage intersectPackage (ImportedPackage p1, ImportedPackage p2) { 
+    
+    logger.debug(LOG_ENTRY, "intersectPackage", new Object[]{p1, p2});
+    ImportedPackage result = null;
+    if (p1.getPackageName().equals(p2.getPackageName()))
+    {
+      Map<String,String> att1 = new HashMap<String, String>(p1.getAttributes());
+      Map<String,String> att2 = new HashMap<String, String>(p2.getAttributes());
+      
+      // Get the versions, we remove them so that the remaining attributes can be matched.
+      String rangeStr1 = att1.remove(Constants.VERSION_ATTRIBUTE);
+      String rangeStr2 = att2.remove(Constants.VERSION_ATTRIBUTE);
+
+      //Also remove the optional directive as we don't care about that either
+      att1.remove(OPTIONAL_KEY);
+      att2.remove(OPTIONAL_KEY);
+      
+      //If identical take either, otherwise null!
+      Map<String, String> mergedAttribs = (att1.equals(att2) ? att1 : null);
+      if (mergedAttribs == null)
+      {
+        // Cannot intersect requirements if attributes are not identical.
+        result = null;
+      }
+      else
+      {
+        boolean isIntersectSuccessful = true;
+        
+        if (rangeStr1 != null && rangeStr2 != null)
+        {
+          // Both requirements have a version constraint so check for an intersection between them.
+          VersionRange range1 = ManifestHeaderProcessor.parseVersionRange(rangeStr1);
+          VersionRange range2 = ManifestHeaderProcessor.parseVersionRange(rangeStr2);
+          VersionRange intersectRange = range1.intersect(range2);
+          
+          if (intersectRange == null)
+          {
+            // No intersection possible.
+            isIntersectSuccessful = false;
+          }
+          else
+          {
+            // Use the intersected version range.
+            mergedAttribs.put(Constants.VERSION_ATTRIBUTE, intersectRange.toString());
+          }
+        }
+        else if (rangeStr1 != null)
+        {
+          mergedAttribs.put(Constants.VERSION_ATTRIBUTE, rangeStr1);
+        }
+        else if (rangeStr2 != null)
+        {
+          mergedAttribs.put(Constants.VERSION_ATTRIBUTE, rangeStr2);
+        }
+        
+        //If both optional, we are optional, otherwise use the default
+        if(p1.isOptional() && p2.isOptional()) 
+        {
+          mergedAttribs.put(OPTIONAL_KEY, Constants.RESOLUTION_OPTIONAL);
+        } 
+        
+        try { 
+          result = (isIntersectSuccessful ? new ImportedPackageImpl(p1.getPackageName(), mergedAttribs) : null);
+        } catch (InvalidAttributeException iax) { 
+          logger.error(iax.getMessage());
+        }
+      }
+    } 
+    logger.debug(LOG_EXIT, "intersectPackage", result);
+    return result;
+  }
+  
+  
+}

Added: incubator/aries/trunk/application/application-modeller/src/main/resources/org/apache/aries/application/modelling/messages/APPModellingMessages.properties
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/main/resources/org/apache/aries/application/modelling/messages/APPModellingMessages.properties?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/main/resources/org/apache/aries/application/modelling/messages/APPModellingMessages.properties (added)
+++ incubator/aries/trunk/application/application-modeller/src/main/resources/org/apache/aries/application/modelling/messages/APPModellingMessages.properties Thu Aug 26 11:04:41 2010
@@ -0,0 +1,54 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+MORE_THAN_ONE_FRAG_HOST=APPMODELLING0001W: An internal error occurred. A bundle fragment manifest must define exactly one Fragment-Host entry. The following entry was found {0}.
+TOO_MANY_SYM_NAMES=APPMODELLING0002W: An internal error occurred. A bundle manifest must contain exactly one Bundle-SymbolicName entry. The following entry was found {0}.
+INCORRECT_MANDATORY_HEADERS=APPMODELLING0003W: An internal error occurred. A bundle with symbolic name {0} and manifest version {1} was unable to be processed.
+TOO_MANY_CB_SYM_NAMES=APPMODELLING0004W: An internal error occurred. A composite bundle manifest must contain exactly one Bundle-SymbolicName entry. The following entry was found {0}.
+INCORRECT_CB_MANDATORY_HEADERS=APPMODELLING0005W: An internal error occurred. A composite bundle with symbolic name {0} and manifest version {1} was unable to be processed.
+TOO_MANY_FRAG_HOSTS=APPMODELLING0006W: An internal error occurred. A bundle fragment manifest must define exactly one Fragment-Host entry. The following entry was found {0}.
+INCOMPATIBLE_PACKAGE_VERSION_REQUIREMENTS=APPMODELLING0007W: The asset {0} cannot be resolved. It has incompatible version requirements on the following packages: {1}.
+INVALID_PACKAGE_REQUIREMENT_ATTRIBUTES=APPMODELLING0008W: The asset {0} cannot be resolved. The attribute {1} on an import for package {2} cannot be satisfied at deployment.
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+MORE_THAN_ONE_FRAG_HOST=APPMODELLING0001W: An internal error occurred. A bundle fragment manifest must define exactly one Fragment-Host entry. The following entry was found {0}.
+TOO_MANY_SYM_NAMES=APPMODELLING0002W: An internal error occurred. A bundle manifest must contain exactly one Bundle-SymbolicName entry. The following entry was found {0}.
+INCORRECT_MANDATORY_HEADERS=APPMODELLING0003W: An internal error occurred. A bundle with symbolic name {0} and manifest version {1} was unable to be processed.
+TOO_MANY_CB_SYM_NAMES=APPMODELLING0004W: An internal error occurred. A composite bundle manifest must contain exactly one Bundle-SymbolicName entry. The following entry was found {0}.
+INCORRECT_CB_MANDATORY_HEADERS=APPMODELLING0005W: An internal error occurred. A composite bundle with symbolic name {0} and manifest version {1} was unable to be processed.
+TOO_MANY_FRAG_HOSTS=APPMODELLING0006W: An internal error occurred. A bundle fragment manifest must define exactly one Fragment-Host entry. The following entry was found {0}.
+INCOMPATIBLE_PACKAGE_VERSION_REQUIREMENTS=APPMODELLING0007W: The asset {0} cannot be resolved. It has incompatible version requirements on the following packages: {1}.
+INVALID_PACKAGE_REQUIREMENT_ATTRIBUTES=APPMODELLING0008W: The asset {0} cannot be resolved. The attribute {1} on an import for package {2} cannot be satisfied at deployment.

Added: incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/AbstractBundleResourceTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/AbstractBundleResourceTest.java?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/AbstractBundleResourceTest.java (added)
+++ incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/AbstractBundleResourceTest.java Thu Aug 26 11:04:41 2010
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.application.modelling.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.apache.aries.application.management.ResolverException;
+import org.apache.aries.application.modelling.ExportedPackage;
+import org.apache.aries.application.modelling.ExportedService;
+import org.apache.aries.application.modelling.ImportedBundle;
+import org.apache.aries.application.modelling.ImportedPackage;
+import org.apache.aries.application.modelling.ImportedService;
+import org.apache.aries.application.modelling.ModelledResource;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+
+/* This is an abstract class and should not be instantiated, so we have an ignore
+ * annotation to the class.
+ */
+@Ignore
+public abstract class AbstractBundleResourceTest
+{
+  protected ModelledResource bundleResource;
+
+  @Before
+  public void setUp() throws Exception
+  {
+    bundleResource = instantiateBundleResource();
+  }
+
+  /**
+   * @return
+   * @throws ResolverException 
+   * @throws FileNotFoundException 
+   * @throws IOException 
+   * @throws Exception 
+   */
+  protected abstract ModelledResource instantiateBundleResource() throws Exception;
+
+  @Test
+  public void testBundleResource() throws Exception
+  {
+    assertEquals("The bundle symbolic name is wrong.", "test.bundle1", bundleResource.getSymbolicName());
+    assertEquals("The bundle version is wrong.", "2.0.0.build-121", bundleResource.getVersion().toString());
+    assertEquals("The bundle presentation name is wrong.", "Test Bundle", bundleResource.getExportedBundle()
+        .getAttributes().get(ModellingConstants.OBR_PRESENTATION_NAME));
+    
+
+    
+    int count = 0;
+  
+    for (ImportedPackage ip : bundleResource.getImportedPackages()) {
+      
+      if (ip.getPackageName().equals("org.osgi.framework")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=org.osgi.framework)(version>=1.3.0))", 
+            ip.getAttributeFilter());
+  
+      } else if (ip.getPackageName().equals("aries.ws.kernel.file")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ws.kernel.file)(version>=0.0.0))", ip.getAttributeFilter());
+  
+      } else if (ip.getPackageName().equals("aries.wsspi.application.aries")) {
+        count++;
+        assertEquals("The filter is wrong.",
+            "(&(package=aries.wsspi.application.aries)(version>=0.0.0)(company=yang)(mandatory:<*company))", ip
+                .getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.ws.ffdc")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ws.ffdc)(version>=0.0.0))", ip.getAttributeFilter());
+        assertTrue ("Optional import not correctly represented", ip.isOptional());
+      } else if (ip.getPackageName().equals("aries.ws.app.framework.plugin")) {
+        count++;
+        assertEquals(
+            "The filter is wrong.",
+            "(&(package=aries.ws.app.framework.plugin)(version>=1.0.0)(version<=2.0.0)(!(version=2.0.0)))",
+            ip.getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.ejs.ras")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ejs.ras)(version>=0.0.0))", ip.getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.ws.event")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ws.event)(version>=1.0.0))", ip
+            .getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.wsspi.app.container.aries")) {
+        count++;
+        assertEquals(
+            "The filter is wrong.",
+            "(&(package=aries.wsspi.app.container.aries)(version>=0.0.0)(bundle-symbolic-name=B)(bundle-version>=1.2.0)(bundle-version<=2.2.0)(!(bundle-version=2.2.0)))",
+            ip.getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.ws.eba.bla")) {
+  
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ws.eba.bla)(version>=0.0.0))", ip.getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.ws.eba.launcher")) {
+  
+        count++;
+        assertEquals("The filter is wrong.",
+            "(&(package=aries.ws.eba.launcher)(version>=1.0.0)(version<=2.0.0))", ip.getAttributeFilter());
+        assertTrue ("Dynamic-ImportPackage should be optional", ip.isOptional());
+  
+      } else if (ip.getPackageName().equals("aries.ws.eba.bundle4")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ws.eba.bundle4)(version>=3.0.0))",
+            ip.getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.ws.eba.bundle5")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ws.eba.bundle5)(version>=3.0.0))",
+            ip.getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.ws.eba.bundle6")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ws.eba.bundle6)(version>=0.0.0))", ip.getAttributeFilter());
+      } else if (ip.getPackageName().equals("aries.ws.eba.bundle7")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(package=aries.ws.eba.bundle7)(version>=0.0.0))", ip.getAttributeFilter());
+      } 
+    }
+      
+    for (ImportedBundle ib : bundleResource.getRequiredBundles()) {
+    
+      if (ib.getSymbolicName().equals("com.acme.facade")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(symbolicname=com.acme.facade)(version>=3.0.0))",
+            ib.getAttributeFilter());
+      } else if (ib.getSymbolicName().equals("com.acme.bar")) {
+        count++;
+        assertEquals("The filter is wrong.", "(symbolicname=com.acme.bar)", ib.getAttributeFilter());
+      } else if (ib.getSymbolicName().equals("aries.ws.eba.framework")) {
+        count++;
+        assertEquals("The filter is wrong.",
+            "(&(symbolicname=aries.ws.eba.framework)(version>=3.0.0)(version<=4.0.0))", ib
+                .getAttributeFilter());
+      } else if (ib.getSymbolicName().equals("com.de.ba")) {
+        count++;
+        assertEquals("The filter is wrong.", "(symbolicname=com.de.ba)", ib.getAttributeFilter());
+      } else if (ib.getSymbolicName().equals("com.ab.de")) {
+        count++;
+        assertEquals("The filter is wrong.", "(symbolicname=com.ab.de)", ib.getAttributeFilter());
+      }
+    }
+    
+    for(ImportedService svc : bundleResource.getImportedServices()) {
+      if (svc.getInterface().equals("aries.ws.eba.import")) {
+        count++;
+        assertEquals("The filter is wrong.", "(&(service=service)(objectClass=aries.ws.eba.import)(mandatory:<*service))",
+          svc.getAttributeFilter());
+      } 
+    }
+    
+    assertEquals("Not all requirements are listed.", bundleResource.getImportedPackages().size() +
+        bundleResource.getImportedServices().size() + bundleResource.getRequiredBundles().size() , count);
+  
+    //verify the capability
+  
+    int verifiedExport = 0;
+    for (ExportedPackage cap : bundleResource.getExportedPackages()) {
+ 
+        if (cap.getPackageName().equals("aries.ws.eba.bundle1")) {
+  
+          verifiedExport++;
+          assertEquals("The export package is not expected.", "2.2.0", cap.getVersion());
+          assertEquals("The export package is not expected.", "test.bundle1", cap.getAttributes().get(
+              "bundle-symbolic-name"));
+          assertEquals("The export package is not expected.", "2.0.0.build-121", cap.getAttributes()
+              .get("bundle-version").toString());
+        } else if (cap.getPackageName().equals("aries.ws.eba.bundle2")) {
+          verifiedExport++;
+          assertEquals("The export package is not expected.", "3", cap.getVersion());
+        } else if (cap.getPackageName().equals("aries.ws.eba.bundle3")) {
+          verifiedExport++;
+          assertEquals("The export package is not expected.", "3", cap.getVersion());
+        }
+    }
+    assertEquals("The number of exports are not expected.", bundleResource.getExportedPackages().size()
+        , verifiedExport);
+    
+
+    // bundle resource
+    assertEquals("The bundle resource is wrong.", "Test Bundle", bundleResource.getExportedBundle().
+        getAttributes().get(ModellingConstants.OBR_PRESENTATION_NAME));
+    assertEquals("The bundle resource is wrong.", "2.0.0.build-121", bundleResource.getExportedBundle().
+        getVersion());
+    assertEquals("The bundle resource is wrong.", "test.bundle1", bundleResource.getExportedBundle().
+        getSymbolicName());
+    
+    
+    for (ExportedService svc : bundleResource.getExportedServices()) {
+      assertEquals("The export service is wrong", "aries.ws.eba.export", svc.getInterfaces().
+          iterator().next());
+    }
+  }
+}

Added: incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/BundleResourceTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/BundleResourceTest.java?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/BundleResourceTest.java (added)
+++ incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/BundleResourceTest.java Thu Aug 26 11:04:41 2010
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.application.modelling.utils;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.jar.Manifest;
+
+import org.apache.aries.application.management.InvalidAttributeException;
+import org.apache.aries.application.management.ResolverException;
+import org.apache.aries.application.modelling.ModelledResource;
+import org.apache.aries.application.modelling.ResourceType;
+import org.apache.aries.application.modelling.impl.ModelledResourceImpl;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+public class BundleResourceTest extends AbstractBundleResourceTest
+{
+  /**
+   * 
+   */
+  private static final String MANIFEST_MF = "MANIFEST.MF";
+  /**
+   * 
+   */
+  private static final String TEST_APP_MANIFEST_PATH = "../src/test/resources/bundles/test.bundle1.jar/META-INF";
+
+  /**
+   * @return
+   * @throws IOException
+   * @throws FileNotFoundException
+   * @throws ResolverException
+   * @throws InvalidAttributeException 
+   */
+  protected ModelledResource instantiateBundleResource() throws Exception
+  {
+    File file = new File(TEST_APP_MANIFEST_PATH, MANIFEST_MF);
+    Manifest man = new Manifest(new FileInputStream(file));
+
+    ModelledResource br = new ModelledResourceImpl(null, man.getMainAttributes(), null, null);
+    return br;
+  }
+
+  @Test
+  public void testBundleResourceIsBundle() throws Exception
+  {
+    assertEquals(ResourceType.BUNDLE, bundleResource.getType());
+  }
+  
+  @Test
+  public void testFragmentCapability()
+  {
+    assertEquals("The bundle resource is wrong.", Constants.FRAGMENT_ATTACHMENT_ALWAYS,
+        bundleResource.getExportedBundle().getAttributes().get(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE + ":"));
+  }
+}

Added: incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/DeployedBundlesTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/DeployedBundlesTest.java?rev=989601&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/DeployedBundlesTest.java (added)
+++ incubator/aries/trunk/application/application-modeller/src/test/java/org/apache/aries/application/modelling/utils/DeployedBundlesTest.java Thu Aug 26 11:04:41 2010
@@ -0,0 +1,582 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.application.modelling.utils;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.Attributes;
+
+import org.apache.aries.application.management.InvalidAttributeException;
+import org.apache.aries.application.management.ResolverException;
+import org.apache.aries.application.modelling.ExportedService;
+import org.apache.aries.application.modelling.ImportedBundle;
+import org.apache.aries.application.modelling.ImportedService;
+import org.apache.aries.application.modelling.ModelledResource;
+import org.apache.aries.application.modelling.impl.ExportedServiceImpl;
+import org.apache.aries.application.modelling.impl.ImportedBundleImpl;
+import org.apache.aries.application.modelling.impl.ImportedServiceImpl;
+import org.apache.aries.application.modelling.impl.ModelledResourceImpl;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor.NameValueMap;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor.NameValuePair;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+
+public final class DeployedBundlesTest
+{
+  
+  private DeployedBundles validDeployedBundles() throws Exception {
+
+    Collection<ImportedBundle> content = new ArrayList<ImportedBundle>();
+    Collection<ImportedBundle> uses = new ArrayList<ImportedBundle>();
+
+    content.add(new ImportedBundleImpl("bundle.a", "1.0.0"));
+    content.add(new ImportedBundleImpl("bundle.b", "1.0.0"));
+    
+    uses.add(new ImportedBundleImpl("bundle.c", "1.0.0"));
+    uses.add(new ImportedBundleImpl("bundle.d", "1.0.0"));
+    
+    return new DeployedBundles("test",content, uses, null);
+  }
+  
+  private void basicResolve(DeployedBundles db, boolean cPersistent) throws InvalidAttributeException {
+    db.addBundle(createModelledResource("bundle.a", "1.0.0", 
+        Arrays.asList("package.b", "package.c"), Arrays.asList("package.a;version=1.0.0")));
+    db.addBundle(createModelledResource("bundle.b", "1.0.0", 
+        Arrays.asList("package.d;version=1.0.0", "package.e;version=\"[1.0.0,2.0.0)\"", "package.g"),
+        Arrays.asList("package.b;version=1.0.0")));
+    
+    db.addBundle(createModelledResource("bundle.c", "1.0.0", 
+        (cPersistent) ? Arrays.asList("package.d;version=\"[1.0.0,2.0.0)\"", "javax.persistence;version=1.1.0") : 
+          Arrays.asList("package.d;version=\"[1.0.0,2.0.0)\""), Arrays.asList("package.c;version=1.0.0")));
+    db.addBundle(createModelledResource("bundle.d", "1.0.0", 
+        Arrays.asList("package.e;version=\"[1.0.0,1.0.0]\""), Arrays.asList("package.d;version=1.0.0")));
+
+  }
+  
+  private void packagesResolve(DeployedBundles db) throws InvalidAttributeException {
+    basicResolve(db, false);
+    
+    db.addBundle(createModelledResource("bundle.e", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.e;version=1.0.0")));
+  }
+  
+  public static ModelledResource createModelledResource(String bundleName, String bundleVersion, 
+      Collection<String> importedPackages, Collection<String> exportedPackages) throws InvalidAttributeException {
+    Attributes att = new Attributes();
+    att.put(new Attributes.Name(Constants.BUNDLE_SYMBOLICNAME), bundleName);
+    att.put(new Attributes.Name(Constants.BUNDLE_VERSION), bundleVersion);
+    att.put(new Attributes.Name(Constants.BUNDLE_MANIFESTVERSION), "2");
+    
+    StringBuilder builder = new StringBuilder();
+    for(String iPackage : importedPackages) {
+      builder.append(iPackage).append(",");
+    }
+    if(builder.length() > 0) {
+      builder.deleteCharAt(builder.length() - 1);
+      att.put(new Attributes.Name(Constants.IMPORT_PACKAGE), builder.toString());
+    }
+    
+    builder = new StringBuilder();
+    for(String ePackage : exportedPackages) {
+      builder.append(ePackage).append(",");
+    }
+    if(builder.length() > 0) {
+      builder.deleteCharAt(builder.length() - 1);
+      att.put(new Attributes.Name(Constants.EXPORT_PACKAGE), builder.toString());
+    }
+    return new ModelledResourceImpl(null, att, null, null);
+  }
+  
+  public static ModelledResource createModelledServiceBundle(String bundleName, String bundleVersion,
+      Collection<String> importService, Collection<String> exportService) throws InvalidAttributeException 
+  {
+    Attributes att = new Attributes();
+    att.put(new Attributes.Name(Constants.BUNDLE_SYMBOLICNAME), bundleName);
+    att.put(new Attributes.Name(Constants.BUNDLE_VERSION), bundleVersion);
+    att.put(new Attributes.Name(Constants.BUNDLE_MANIFESTVERSION), "2");
+    
+    List<ImportedService> importedServices = new ArrayList<ImportedService>();
+    for (String s : importService) {
+      importedServices.add(new ImportedServiceImpl(false, s, null, null, null, false));
+    }
+    
+    List<ExportedService> exportedServices = new ArrayList<ExportedService>();
+    for (String s : exportService) {
+      exportedServices.add(new ExportedServiceImpl(null, 0, Collections.singleton(s), Collections.<String,Object>emptyMap()));
+    }
+    
+    return new ModelledResourceImpl(null, att, importedServices, exportedServices);
+  }
+  
+  /**
+   * Check the actual results match the expected values, regardless of order of the parts.
+   * @param entry the actual manifest entry.
+   * @param expected the expected manifest entry.
+   * @return true if they match; false otherwise.
+   */
+  private static boolean isEqual(String actual, String expected)
+  {
+    Map<NameValuePair<String, NameValueMap<String, String>>, Integer> actualEntries = parseEntries(actual);
+    Map<NameValuePair<String, NameValueMap<String, String>>, Integer> expectedEntries = parseEntries(expected);
+    return actualEntries.equals(expectedEntries);
+  }
+
+  /**
+   * Parse manifest entries into a set of values and associated attributes, which can
+   * be directly compared for equality regardless of ordering.
+   * <p>
+   * Example manifest entry format: value1;attrName1=attrValue1;attrName2=attrValue2,value2;attrName1=attrValue1
+   * @param entries a manifest header entry.
+   * @return a set of parsed entries.
+   */
+  private static Map<NameValuePair<String, NameValueMap<String, String>>, Integer> parseEntries(String entries)
+  {
+    Map<NameValuePair<String, NameValueMap<String, String>>, Integer> result = new HashMap<NameValuePair<String, NameValueMap<String, String>>, Integer>();
+    for (NameValuePair<String, NameValueMap<String, String>> entry : ManifestHeaderProcessor.parseExportString(entries))
+    {
+      Integer count = result.get(entry);
+      if (count != null)
+      {
+        // This entry already exists to increment the count.
+        count++;
+      }
+      else
+      {
+        count = 1;
+      }
+      result.put(entry, count);
+    }
+    
+    return result;
+  }
+
+  @Test
+  public void testGetContent_Valid() throws Exception
+  {
+    // Get a valid set of deployment information.
+    DeployedBundles deployedBundles = validDeployedBundles();
+    packagesResolve(deployedBundles);
+    
+    // Check the deployed content entry is correct.
+    String contentEntry = deployedBundles.getContent();
+    String expectedResult = "bundle.a;deployed-version=1.0.0,bundle.b;deployed-version=1.0.0";
+    Assert.assertTrue("Content=" + contentEntry, isEqual(contentEntry, expectedResult));
+  }
+
+  @Test
+  public void testGetUseBundle_Valid() throws Exception
+  {
+    // Get a valid set of deployment information.
+    DeployedBundles deployedBundles = validDeployedBundles();
+    packagesResolve(deployedBundles);
+    
+    // Check the deployed use bundle entry is correct.
+    String useBundleEntry = deployedBundles.getUseBundle();
+    String expectedResult = "bundle.c;deployed-version=1.0.0,bundle.d;deployed-version=1.0.0";
+    Assert.assertTrue("UseBundle=" + useBundleEntry, isEqual(useBundleEntry, expectedResult));
+  }
+
+  @Test
+  public void testGetProvisionBundle_Valid() throws Exception
+  {
+    // Check the provision bundle entry is correct.
+    DeployedBundles deployedBundles = validDeployedBundles();
+    packagesResolve(deployedBundles);
+    String provisionBundleEntry = deployedBundles.getProvisionBundle();
+    String expectedResult = "bundle.e;deployed-version=1.0.0";
+    Assert.assertTrue("ProvisionBundle=" + provisionBundleEntry, isEqual(provisionBundleEntry, expectedResult));
+  }
+
+  @Test
+  public void testGetImportPackage_Valid() throws Exception
+  {
+    // Check the import package entry is correct.
+    String importPackageEntry = null;
+    try
+    {
+      DeployedBundles deployedBundles = validDeployedBundles();
+      packagesResolve(deployedBundles);
+      
+      importPackageEntry = deployedBundles.getImportPackage();
+    }
+    catch (ResolverException e)
+    {
+      e.printStackTrace();
+      Assert.fail(e.toString());
+    }
+    
+    String expectedResult = "package.c;version=\"1.0.0\";bundle-symbolic-name=\"bundle.c\";bundle-version=\"[1.0.0,1.0.0]\","
+      + "package.d;version=\"1.0.0\";bundle-symbolic-name=\"bundle.d\";bundle-version=\"[1.0.0,1.0.0]\"," 
+      + "package.e;version=\"[1.0.0,2.0.0)\","
+      + "package.g;version=\"0.0.0\"";
+    
+    
+    /*
+     * String expectedResult = "package.c;bundle-symbolic-name=bundle.c;bundle-version=\"[1.0.0,1.0.0]\""
+     
+        + ",package.d;version=\"1.0.0\";bundle-symbolic-name=bundle.d;bundle-version=\"[1.0.0,1.0.0]\""
+        + ",package.e;version=\"[1.0.0,2.0.0)\""
+        + ",package.g";
+     */
+    Assert.assertTrue("ImportPackage=" + importPackageEntry, isEqual(importPackageEntry, expectedResult));
+  }
+  
+  
+  
+
+  private enum ternary { CONTENT,USES,NONE }
+  
+  private DeployedBundles getSimpleDeployedBundles(ternary a, ternary b, ternary c) throws InvalidAttributeException
+  {
+    Collection<ImportedBundle> content = new ArrayList<ImportedBundle>();
+    Collection<ImportedBundle> uses = new ArrayList<ImportedBundle>();
+
+    if(a == ternary.CONTENT)
+      content.add(new ImportedBundleImpl("bundle.a", "1.0.0"));
+    else if (a == ternary.USES)
+      uses.add(new ImportedBundleImpl("bundle.a", "1.0.0"));
+    if (b == ternary.CONTENT)
+      content.add(new ImportedBundleImpl("bundle.b", "1.0.0"));
+    else if (b == ternary.USES)
+      uses.add(new ImportedBundleImpl("bundle.b", "1.0.0"));
+    if (c == ternary.CONTENT)
+      content.add(new ImportedBundleImpl("bundle.c", "1.0.0"));
+    else if (c == ternary.USES)
+      uses.add(new ImportedBundleImpl("bundle.c", "1.0.0"));
+    
+    return new DeployedBundles("test",content, uses, null);
+  }
+  
+  @Test
+  public void testGetImportPackage_ValidDuplicates() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.CONTENT, ternary.CONTENT);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.d;version=\"[1.0.0,3.0.0)\""), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+        Arrays.asList("package.d;version=\"2.0.0\""), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.c", "1.0.0",
+        Arrays.asList("package.d;version=\"1.0.0\""), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.d", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.d;version=2.0.1")));
+    
+    // Check that package D is not duplicated in Import-Package, and that the version range
+    // has been narrowed to the intersection of the original requirements.
+    String importPackageEntry = null;
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();
+    }
+    catch (ResolverException e)
+    {
+      e.printStackTrace();
+      Assert.fail(e.toString());
+    }
+    String expectedResult = "package.d;version=\"[2.0.0,3.0.0)\"";
+    Assert.assertTrue("ImportPackage=" + importPackageEntry, isEqual(importPackageEntry, expectedResult));
+  }
+
+  @Test
+  public void testGetImportPackage_ValidDuplicatesWithAttributes() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.CONTENT, ternary.NONE);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.c;version=1.0.0;was_internal=true"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+        Arrays.asList("package.c;version=2.0.0;was_internal=true"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.c", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.c;version=2.0.0;was_internal=true")));
+
+    // Check that package C is not duplicated in Import-Package, and that the version range
+    // has been narrowed to the intersection of the original requirements.
+    String importPackageEntry = null;
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();
+    }
+    catch (ResolverException e)
+    {
+      e.printStackTrace();
+      Assert.fail(e.toString());
+    }
+    String expectedResult = "package.c;was_internal=\"true\";version=\"2.0.0\"";
+    Assert.assertTrue("ImportPackage=" + importPackageEntry, isEqual(importPackageEntry, expectedResult));
+  }
+
+  @Test
+  public void testGetImportPackage_InvalidDuplicates() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.CONTENT, ternary.NONE);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.c;version=\"[1.0.0,2.0.0)\""), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+        Arrays.asList("package.c;version=2.0.0"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.c", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.c;version=2.0.0;was_internal=true")));
+    
+    // Check that the incompatible version requirements cannot be resolved.
+    String importPackageEntry = null;
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();
+      Assert.fail("Expected exception. ImportPackage=" + importPackageEntry);
+    }
+    catch (ResolverException e)
+    {
+      // We expect to reach this point if the test passes.
+    }
+  }
+
+  @Test
+  public void testGetImportPackage_InvalidDuplicatesWithAttributes() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.CONTENT, ternary.NONE);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.c;version=1.0.0;was_internal=true"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+        Arrays.asList("package.c;version=2.0.0"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.c", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.c;version=2.0.0;was_internal=true")));
+
+    // Check that the incompatible package requirement attributes cause an exception.
+    String importPackageEntry = null;
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();
+      Assert.fail("Expected exception. ImportPackage=" + importPackageEntry);
+    }
+    catch (ResolverException e)
+    {
+      // We expect to reach this point if the test passes.
+    }
+  }
+
+  
+  @Test
+  public void testGetImportPackage_bundleSymbolicNameOK() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.CONTENT, ternary.NONE);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.b;version=1.0.0;bundle-symbolic-name=bundle.b;bundle-version=\"[1.0.0,2.0.0)\""), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.b;version=2.0.0")));
+    
+    // Check that the bundle-symbolic-name attribute for a bundle within deployed-content is ok. 
+    String importPackageEntry = null; 
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();      
+    }
+    catch (ResolverException e)
+    {
+      e.printStackTrace();
+      Assert.fail(e.toString());
+    }
+    String expectedResult = "";  // All packages are satisfied internally 
+    Assert.assertTrue("ImportPackage=" + importPackageEntry, isEqual(importPackageEntry, expectedResult));
+
+  }
+  
+  @Test
+  public void testGetImportPackage_rfc138PreventsBundleSymbolicNameWorking() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.USES, ternary.NONE);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.b;version=1.0.0;bundle-symbolic-name=bundle.b"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.b;version=2.0.0")));
+
+    
+    // Check that the bundle-symbolic-name attribute for a bundle outside use-bundle causes an exception.
+    String importPackageEntry = null;
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();
+      Assert.fail("Expected exception. ImportPackage=" + importPackageEntry);
+    }
+    catch (ResolverException e)
+    {
+      // We expect to reach this point if the test passes.
+    }
+  }
+  
+  @Test
+  public void testGetImportPackage_rfc138PreventsBundleVersionWorking() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.NONE, ternary.NONE);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.b;version=1.0.0;bundle-version=1.0.0"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.b;version=2.0.0")));
+
+    
+    // Check that the bundle-symbolic-name attribute for a bundle outside use-bundle causes an exception.
+    String importPackageEntry = null;
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();
+      Assert.fail("Expected exception. ImportPackage=" + importPackageEntry);
+    }
+    catch (ResolverException e)
+    {
+      // We expect to reach this point if the test passes.
+    }
+  }
+  
+  @Test
+  public void testGetImportPackage_ValidResolutionAttribute() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.CONTENT, ternary.NONE);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.c;version=1.0.0;resolution:=optional"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+         Arrays.asList("package.c;version=1.0.0"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.c", "1.0.0",
+        new ArrayList<String>(), Arrays.asList("package.c;version=1.0.0")));
+    
+    // Check that the resulting resolution directive is not optional.
+    String importPackageEntry = null;
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();
+    }
+    catch (ResolverException e)
+    {
+      e.printStackTrace();
+      Assert.fail(e.toString());
+    }
+    String expectedResult = "package.c;version=1.0.0";
+    Assert.assertTrue("ImportPackage=" + importPackageEntry, isEqual(importPackageEntry, expectedResult));
+  }
+
+  @Test
+  public void testGetRequiredUseBundle_RedundantEntry() throws Exception
+  {
+    // Bundle A requires package B from bundle B with no version requirement.
+    // Bundle B requires package C from bundle C with no version requirement.
+    // Bundle C requires package B from bundle B with explicit version requirement.
+    
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.USES, ternary.USES);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.b"), new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+         Arrays.asList("package.c"), Arrays.asList("package.b;version=1.0.0")));
+    deployedBundles.addBundle(createModelledResource("bundle.c", "1.0.0",
+        Arrays.asList("package.b;version=1.0.0"), Arrays.asList("package.c;version=1.0.0")));
+      
+    // Check the redundant use-bundle entry is identified.
+    // Bundle C is not required by app content, although it is specified in use-bundle.
+    Collection<ModelledResource> requiredUseBundle = null;
+    try
+    {
+      requiredUseBundle = deployedBundles.getRequiredUseBundle();
+    }
+    catch (ResolverException e)
+    {
+      e.printStackTrace();
+      Assert.fail(e.toString());
+    }
+    Assert.assertTrue("RequiredUseBundle=" + requiredUseBundle, requiredUseBundle.size() == 1);
+  }
+
+  @Test
+  public void testGetRequiredUseBundle_Valid() throws Exception
+  {
+    // Get a valid set of deployment information.
+    DeployedBundles deployedBundles = validDeployedBundles();
+    packagesResolve(deployedBundles);
+    
+    // Check all the use-bundle entries are required.
+    Collection<ModelledResource> requiredUseBundle = null;
+    try
+    {
+      requiredUseBundle = deployedBundles.getRequiredUseBundle();
+    }
+    catch (ResolverException e)
+    {
+      e.printStackTrace();
+      Assert.fail(e.toString());
+    }
+    Assert.assertTrue("RequiredUseBundle=" + requiredUseBundle, requiredUseBundle.size() == 2);
+  }
+  
+  //Inside cannot bundle-symbolic-name an outside bundle until the new RFC 138!
+  @Test
+  public void testGetImportPackage_InvalidBundleVersion() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.USES, ternary.NONE);
+    
+    deployedBundles.addBundle(createModelledResource("bundle.a", "1.0.0",
+        Arrays.asList("package.b;version=\"[1.0.0,1.0.0]\";bundle-symbolic-name=bundle.b;bundle-version=\"[0.0.0,1.0.0)\"")
+        , new ArrayList<String>()));
+    deployedBundles.addBundle(createModelledResource("bundle.b", "1.0.0",
+         new ArrayList<String>(), Arrays.asList("package.b;version=1.0.0")));
+
+    // Check that the bundle version requirement generates an error because it doesn't match the a bundle in use-bundle.
+    String importPackageEntry = null;
+    try
+    {
+      importPackageEntry = deployedBundles.getImportPackage();
+      Assert.fail("Expected exception. ImportPackage=" + importPackageEntry);
+    }
+    catch (ResolverException e)
+    {
+      // We expect to reach this point if the test passes.
+    }
+  }
+  
+  
+  @Test
+  public void testImportedService() throws Exception
+  {
+    DeployedBundles deployedBundles = getSimpleDeployedBundles(ternary.CONTENT, ternary.NONE, ternary.NONE);
+
+    deployedBundles.addBundle(createModelledServiceBundle("bundle.a", "1.0.0", 
+        Collections.singleton("java.util.List"), Collections.<String>emptyList()));
+
+    deployedBundles.addBundle(createModelledServiceBundle("bundle.b", "1.0.0", 
+        Collections.singleton("java.util.Set"), Collections.singleton("java.util.List")));
+
+    deployedBundles.addBundle(createModelledServiceBundle("bundle.c", "1.0.0", 
+        Collections.<String>emptyList(), Collections.singleton("java.util.Set")));
+    
+    assertEquals("(objectClass=java.util.List)", deployedBundles.getDeployedImportService());
+  }
+
+}



Mime
View raw message