You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by zo...@apache.org on 2011/02/27 21:20:30 UTC

svn commit: r1075132 [9/18] - in /aries/tags/application-0.3: ./ application-api/ application-api/src/ application-api/src/main/ application-api/src/main/java/ application-api/src/main/java/org/ application-api/src/main/java/org/apache/ application-api...

Added: aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/DeployedBundlesImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/DeployedBundlesImpl.java?rev=1075132&view=auto
==============================================================================
--- aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/DeployedBundlesImpl.java (added)
+++ aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/DeployedBundlesImpl.java Sun Feb 27 20:20:13 2011
@@ -0,0 +1,477 @@
+/*
+ * 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.impl;
+
+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.DeployedBundles;
+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.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 DeployedBundlesImpl implements DeployedBundles
+{
+  private final Logger logger = LoggerFactory.getLogger(DeployedBundlesImpl.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 DeployedBundlesImpl(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.
+   */
+  @Override
+  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.
+   */
+  @Override
+  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.
+   */
+  @Override
+  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.
+   */
+  @Override
+  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.
+   */
+  @Override
+  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
+   *   
+   */
+  @Override
+  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;
+  }
+  
+
+  @Override
+  public String toString()
+  {
+    return AppConstants.DEPLOYMENT_CONTENT + '=' + deployedContent + ' ' +
+        AppConstants.DEPLOYMENT_USE_BUNDLE + '=' + deployedUseBundle + ' ' +
+        AppConstants.DEPLOYMENT_PROVISION_BUNDLE + '=' + deployedProvisionBundle;
+  }
+  
+  /**
+   * Get the set of bundles that are going to be deployed into an isolated framework
+   * @return a set of bundle metadata
+   */
+  @Override
+  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. 
+   *
+   */
+  @Override
+  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.
+   */
+  @Override
+  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;
+  }
+
+  /** This method will be overridden by a PostResolveTransformer returning an extended version of
+   * DeployedBundles 
+   */
+  @Override
+  public Map<String, String> getExtraHeaders() {
+    logger.debug (LOG_ENTRY, "getExtraHeaders");
+    Map<String, String> result = Collections.emptyMap();
+    logger.debug (LOG_EXIT, "getExtraHeaders", result);
+    return result;
+  }
+}

Added: aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedBundleImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedBundleImpl.java?rev=1075132&view=auto
==============================================================================
--- aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedBundleImpl.java (added)
+++ aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedBundleImpl.java Sun Feb 27 20:20:13 2011
@@ -0,0 +1,149 @@
+/*
+ * 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.impl;
+
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.Attributes;
+
+import org.apache.aries.application.InvalidAttributeException;
+import org.apache.aries.application.modelling.ImportedBundle;
+import org.apache.aries.application.modelling.ModellingConstants;
+import org.apache.aries.application.modelling.internal.MessageUtil;
+import org.apache.aries.application.modelling.utils.impl.ModellingHelperImpl;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor.NameValueMap;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An exported bundle: one that I have and make available.  
+ */
+public class ExportedBundleImpl extends AbstractExportedBundle
+{
+  private static final Logger logger = LoggerFactory.getLogger(ExportedBundleImpl.class);
+  private final Map<String, Object> _attributes;
+  private final ImportedBundle _fragHost;
+    
+  /**
+   * Construct an ExportedBundleImpl from a processed Manifest
+   * @param attrs
+   * @throws InvalidAttributeException
+   */
+  public ExportedBundleImpl (Attributes attrs) throws InvalidAttributeException { 
+    logger.debug(LOG_ENTRY, "ExportedBundleImpl", attrs);
+    String symbolicName = attrs.getValue(Constants.BUNDLE_SYMBOLICNAME);
+    
+    Map<String,NameValueMap<String, String>> map = ManifestHeaderProcessor.parseImportString(symbolicName);
+    
+    //This should have one entry, which is keyed on the symbolicName
+    
+    if(map.size() != 1) {
+      InvalidAttributeException iax = new InvalidAttributeException (MessageUtil.getMessage(
+          "TOO_MANY_SYM_NAMES", new Object[] {symbolicName}));
+      logger.debug(LOG_EXIT, "ExportedBundleImpl", iax);
+      throw iax;
+    }
+    
+    Map.Entry<String, NameValueMap<String, String>> entry =  map.entrySet().iterator().next();
+    
+    symbolicName = entry.getKey();
+    
+    Map<String, String> bundleAttrs = entry.getValue();
+    
+    String displayName = attrs.getValue(Constants.BUNDLE_NAME);
+    String version = attrs.getValue(Constants.BUNDLE_VERSION);
+    if (version == null) { 
+      version = Version.emptyVersion.toString();
+    }
+    String bmVersion = attrs.getValue(Constants.BUNDLE_MANIFESTVERSION);
+    if (symbolicName == null || bmVersion == null) { 
+      InvalidAttributeException iax = new InvalidAttributeException(MessageUtil.getMessage("INCORRECT_MANDATORY_HEADERS", 
+          new Object[] {symbolicName, bmVersion}));
+      logger.debug(LOG_EXIT, "ExportedBundleImpl", iax);
+      throw iax;
+    }
+
+    if(bundleAttrs != null)
+      _attributes = new HashMap<String, Object>(entry.getValue());
+    else
+      _attributes = new HashMap<String, Object>();
+
+    _attributes.put (Constants.BUNDLE_MANIFESTVERSION, bmVersion);
+    _attributes.put(ModellingConstants.OBR_SYMBOLIC_NAME, symbolicName);
+    _attributes.put (Constants.VERSION_ATTRIBUTE, version);
+    
+    if(displayName != null)
+      _attributes.put(ModellingConstants.OBR_PRESENTATION_NAME, displayName);
+    
+    String fragmentHost = attrs.getValue(Constants.FRAGMENT_HOST);
+    if (fragmentHost != null) { 
+      _fragHost = ModellingHelperImpl.buildFragmentHost_(fragmentHost);
+      _attributes.put(Constants.FRAGMENT_HOST, fragmentHost);
+    } else { 
+      _fragHost = null;
+    }
+    logger.debug(LOG_EXIT, "ExportedBundleImpl");
+  }
+  
+  /**
+   * Construct a bundle from attributes and a fragment host
+   * @param attributes attributes describing the bundle
+   * @param fragHost may be null if this bundle is not a fragment
+   */
+  public ExportedBundleImpl(Map<String, String> attributes, ImportedBundle fragHost) {
+    logger.debug(LOG_ENTRY, "ExportedBundleImpl", new Object[]{attributes, fragHost});
+    _attributes = new HashMap<String, Object>(attributes);
+    _fragHost = fragHost;
+    logger.debug(LOG_EXIT, "ExportedBundleImpl", new Object[]{attributes, fragHost});
+  }
+
+
+  public Map<String, Object> getAttributes() {
+    logger.debug(LOG_ENTRY, "getAttributes");
+    logger.debug(LOG_EXIT, "getAttributes", new Object[]{_attributes});
+    return Collections.unmodifiableMap(_attributes);
+  }
+  
+
+  public String toString() {
+    return  _attributes.toString();
+  }
+
+ 
+  public ImportedBundle getFragmentHost() {
+    logger.debug(LOG_ENTRY, "getFragmentHost");
+    logger.debug(LOG_EXIT, "getFragmentHost", new Object[]{_fragHost});
+    return _fragHost;
+  }
+
+
+  public boolean isFragment() {
+    logger.debug(LOG_ENTRY, "isFragment");
+    boolean result = _fragHost != null;
+    logger.debug(LOG_EXIT, "isFragment", new Object[]{result});
+    return result;
+  }
+}

Added: aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedPackageImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedPackageImpl.java?rev=1075132&view=auto
==============================================================================
--- aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedPackageImpl.java (added)
+++ aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedPackageImpl.java Sun Feb 27 20:20:13 2011
@@ -0,0 +1,157 @@
+/*
+ * 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.impl;
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+import static org.apache.aries.application.modelling.ResourceType.PACKAGE;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.aries.application.modelling.ExportedPackage;
+import org.apache.aries.application.modelling.ModelledResource;
+import org.apache.aries.application.modelling.ResourceType;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+
+
+public class ExportedPackageImpl implements ExportedPackage
+{
+  
+  @SuppressWarnings("deprecation")
+  private static final String PACKAGE_SPECIFICATION_VERSION = Constants.PACKAGE_SPECIFICATION_VERSION;
+  private final Map<String, Object> _attributes;
+  private final String _packageName;
+  private final String _version;
+  private final ModelledResource _bundle;
+  private final Logger logger = LoggerFactory.getLogger(ExportedPackageImpl.class);
+  /**
+   * 
+   * @param mr                 The {@link ModelledResource} exporting this package. Never null.  
+   * @param pkg                The fully qualified name of the package being exported
+   * @param attributes         The package attributes. If no version is present, will be defaulted to 0.0.0. 
+   *                           
+   */
+  public ExportedPackageImpl (ModelledResource mr, String pkg, Map<String, Object> attributes) {
+    logger.debug(LOG_ENTRY, "ExportedPackageImpl", new Object[]{mr, pkg, attributes});
+    _attributes = new HashMap<String, Object> (attributes);
+    _packageName = pkg;
+    _attributes.put (PACKAGE.toString(), _packageName);
+    String version = (String) attributes.get(Constants.VERSION_ATTRIBUTE);
+    if (version == null || "".equals(version)) { 
+      _version = Version.emptyVersion.toString();
+    } else { 
+      _version = version;
+    }
+    _attributes.put(Constants.VERSION_ATTRIBUTE, _version); 
+    _attributes.put (Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, mr.getSymbolicName());
+    _attributes.put (Constants.BUNDLE_VERSION_ATTRIBUTE, mr.getVersion());
+    _bundle = mr;
+    logger.debug(LOG_EXIT, "ExportedPackageImpl");
+  }
+
+
+  public Map<String, Object> getAttributes() {
+    logger.debug(LOG_ENTRY, "getAttributes");
+    logger.debug(LOG_EXIT, "getAttributes", _attributes);
+    return Collections.unmodifiableMap(_attributes);
+  }
+
+
+  public ResourceType getType() {
+    logger.debug(LOG_ENTRY, "getType");
+    logger.debug(LOG_EXIT, "getType", PACKAGE);
+    return PACKAGE;
+  }
+
+  /**
+   * Get the name of the exported package
+   * @return package name
+   */
+  public String getPackageName() { 
+    logger.debug(LOG_ENTRY, "getPackageName");
+    logger.debug(LOG_EXIT, "getPackageName", _packageName);
+    return _packageName;
+  }
+
+  /**
+   * This will never be null. 
+   * @return Version as String, or 0.0.0
+   */
+  public String getVersion() {
+    logger.debug(LOG_ENTRY, "getVersion");
+    logger.debug(LOG_EXIT, "getVersion", _version);
+    return _version;
+  }
+  
+  /**
+   * This method turns an {@link ExportedPackageImpl} into a string suitable for a 
+   * Use-Bundle style package import. We do NOT lock down package versions, only bundle versions. 
+   */
+  public String toDeploymentString() {
+    logger.debug(LOG_ENTRY, "toDeploymentString");
+    StringBuilder sb = new StringBuilder(_packageName);
+    for (Map.Entry<String, Object> entry : _attributes.entrySet()) {
+      String key = entry.getKey();
+      Object objectValue = entry.getValue(); 
+      // While attributes can be arrays, especially for services, they should never be arrays for packages
+      // If the values are not arrays, they are Strings
+      if (!objectValue.getClass().isArray()) {  
+        String value = String.valueOf(objectValue);
+        if (key != null && !key.equals(PACKAGE.toString()) 
+            && !key.equals(PACKAGE_SPECIFICATION_VERSION))
+        {
+          if (key.equals(Constants.BUNDLE_VERSION_ATTRIBUTE)) { 
+            value = "[" + value + "," + value + "]";
+          }
+          // No Export-Package directives are valid on Import-Package, so strip out all 
+          // directives. Never print out a null or empty key or value. 
+          if (key.equals("") || key.endsWith(":") || value==null || value.equals("")) {
+            
+            logger.debug("ExportedPackageImpl.toDeploymentString ignored " + key + "=" + value);
+          } else { 
+            sb.append (";").append (key).append("=\"").append(value).append('"');
+          }
+        } else { 
+          logger.debug("ExportedPackageImpl.toDeploymentString() ignoring attribute " + key + "->" + value);
+        }
+      }
+    }
+    String result = sb.toString();
+    logger.debug(LOG_EXIT, "toDeploymentString", result);
+    return result;
+  }
+
+  public ModelledResource getBundle() {
+    logger.debug(LOG_ENTRY, "getBundle");
+    logger.debug(LOG_EXIT, "getBundle", _bundle);
+    return _bundle;
+  }
+  
+  @Override
+  public String toString() {
+    return toDeploymentString();
+  }
+
+}

Added: aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedServiceImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedServiceImpl.java?rev=1075132&view=auto
==============================================================================
--- aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedServiceImpl.java (added)
+++ aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ExportedServiceImpl.java Sun Feb 27 20:20:13 2011
@@ -0,0 +1,281 @@
+/*
+ * 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.impl;
+
+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.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.aries.application.modelling.ExportedService;
+import org.apache.aries.application.modelling.ModellingConstants;
+import org.apache.aries.application.modelling.ResourceType;
+import org.apache.aries.application.modelling.WrappedServiceMetadata;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A service exported by a bundle. Provides an entry to DEPLOYMENT.MF
+ */
+public class ExportedServiceImpl implements ExportedService
+{
+  private final Logger logger = LoggerFactory.getLogger(ExportedServiceImpl.class);
+  private final Map<String, Object> _attributes;
+  private final Collection<String> _interfaces;
+  private final Map<String, Object> _serviceProperties;
+  private final String _name;
+  private final int _ranking;
+  private String _toString = null;
+
+  /**
+   * Constructor. 
+   * @param name              "" will be changed to null
+   * @param ranking           Service ranking
+   * @param ifaces            Interfaces offered by the service
+   * @param serviceProperties Service properties. 
+   *                          We expect that osgi.service.blueprint.compname has been set if possible
+   */
+  public ExportedServiceImpl (String name, int ranking, Collection<String> ifaces, 
+      Map<String, Object> serviceProperties ) 
+  { 
+     
+    logger.debug(LOG_ENTRY,"ExportedServiceImpl", new Object[]{name, ranking, ifaces});
+    _interfaces = new TreeSet<String>(ifaces);
+    if (!"".equals(name)) { 
+      _name = name;
+    } else { 
+      _name = null;
+    }
+    _ranking = ranking;
+    if (serviceProperties == null) { 
+      _serviceProperties = new HashMap<String, Object>();
+    } else { 
+      _serviceProperties = new HashMap<String, Object>(serviceProperties);
+    }
+    
+    // Construct _attributes
+    _attributes = new HashMap<String, Object>(_serviceProperties);
+    
+    // Turn interfaces into a comma separated String
+    StringBuilder sb = new StringBuilder();
+    for (String i : _interfaces) { 
+      sb.append(i + ",");
+    }
+    sb = sb.deleteCharAt(sb.length()-1);
+    _attributes.put(Constants.OBJECTCLASS, sb.toString());
+    _attributes.put (Constants.SERVICE_RANKING, String.valueOf(_ranking));
+    _attributes.put(ModellingConstants.OBR_SERVICE, ModellingConstants.OBR_SERVICE);
+    logger.debug(LOG_EXIT,"ExportedServiceImpl");
+  }
+  
+  /**
+   * This constructor is for building ExportedServices from Export-Service manifest headers, 
+   * which are deprecated in OSGi. 
+   * @param ifaceName
+   * @param attrs
+   */
+  @Deprecated 
+  public ExportedServiceImpl (String ifaceName, Map<String, String> attrs) { 
+    logger.debug(LOG_ENTRY,"ExportedServiceImpl", new Object[]{ ifaceName, attrs});
+    _interfaces = new TreeSet<String> (Arrays.asList(ifaceName));
+    _ranking = 0;
+    _attributes = new HashMap<String, Object> (attrs);
+    _attributes.put(Constants.OBJECTCLASS, ifaceName);
+    _attributes.put (Constants.SERVICE_RANKING, String.valueOf(_ranking));
+    _attributes.put(ModellingConstants.OBR_SERVICE, ModellingConstants.OBR_SERVICE);
+    _serviceProperties = new HashMap<String, Object>();
+    _name = null;
+    logger.debug(LOG_EXIT,"ExportedServiceImpl");
+   }
+  
+
+  public Map<String, Object> getAttributes() {    
+    logger.debug(LOG_ENTRY,"getAttributes");
+    logger.debug(LOG_EXIT, "getAttributes", _attributes);
+    return Collections.unmodifiableMap(_attributes);
+  }
+
+
+  public ResourceType getType() {
+    logger.debug(LOG_ENTRY,"getType");
+    logger.debug(LOG_EXIT, "getType", ResourceType.SERVICE);
+    return ResourceType.SERVICE;
+  }
+
+
+  public Collection<String> getInterfaces() {
+    logger.debug(LOG_ENTRY,"getInterfaces");
+    logger.debug(LOG_EXIT, "getInterfaces", _interfaces);
+    return Collections.unmodifiableCollection(_interfaces);
+  }
+
+
+  public String getName() {
+    logger.debug(LOG_ENTRY,"getName");
+    logger.debug(LOG_EXIT, "getName", _name);
+    return _name;
+  }
+
+
+  public int getRanking() {
+    logger.debug(LOG_ENTRY,"getRanking");
+    logger.debug(LOG_EXIT, "getRanking", _ranking);
+    return _ranking;
+  }
+
+
+  public Map<String, Object> getServiceProperties() {
+    logger.debug(LOG_ENTRY,"getServiceProperties");
+    logger.debug(LOG_EXIT, "getServiceProperties", _serviceProperties);
+    return Collections.unmodifiableMap(_serviceProperties);
+  }
+
+
+  public int compareTo(WrappedServiceMetadata o) {
+    logger.debug(LOG_ENTRY, "compareTo", o);
+    if (o == null) {
+      logger.debug(LOG_EXIT, "compareTo", -1);
+      return -1;      // shunt nulls to the end of any lists
+    }
+    int result = this.toString().compareTo(o.toString());
+    logger.debug(LOG_EXIT,"compareTo", result);
+    return result;
+  }
+
+  @Override
+  public boolean equals (Object o) { 
+    logger.debug(LOG_ENTRY, "equals", o);
+    // Doubles as a null check
+    if (!(o instanceof WrappedServiceMetadata)) { 
+      logger.debug(LOG_EXIT, "equals", false);
+      return false;
+    }
+
+    if (o==this) { 
+      logger.debug(LOG_EXIT, "equals", true);
+      return true;
+    }
+ 
+    boolean eq = this.toString().equals(o.toString());
+    logger.debug(LOG_EXIT, "equals", eq);
+    return eq;
+  }
+  
+  
+  @Override
+  public int hashCode() {
+    logger.debug(LOG_ENTRY, "hashCode");
+    int result = toString().hashCode();
+    logger.debug(LOG_EXIT, "hashCode", result);
+    return result;
+  }
+  
+  @Override 
+  public String toString() { 
+    if (_toString != null) { 
+      return _toString;
+    }
+    
+    List<String> interfaces = new ArrayList<String>(_interfaces);
+    Collections.sort(interfaces);
+    
+    List<String> props = new ArrayList<String>();
+    for (Map.Entry<String, Object> entry : _serviceProperties.entrySet()) {
+      Object entryValue = entry.getValue();
+      String entryText;
+      if (entryValue.getClass().isArray()) { 
+        // Turn arrays into comma separated Strings
+        Object [] entryArray = (Object[]) entryValue;
+        StringBuilder sb = new StringBuilder();
+        for (Object o: entryArray) { 
+          sb.append(String.valueOf(o) + ",");
+        }
+        sb = sb.deleteCharAt(sb.length()-1);
+        entryText = sb.toString();
+      } else { 
+        entryText = String.valueOf(entryValue);
+      }
+      props.add ("<entry> key=\"" + entry.getKey() + "\" value=\"" + entryText + "\"/>");
+    }
+    Collections.sort(props);
+    
+    StringBuffer buf = new StringBuffer("<service>");
+    if(_name != null) {
+      buf.append("<name>" + _name + "</name>");
+    }
+    if (_interfaces.size() > 0) { 
+      buf.append("<interfaces>");
+    }
+    for (String i : interfaces) { 
+      buf.append("<value>" + i + "</value>");
+    }
+    if (_interfaces.size() > 0) { 
+      buf.append("</interfaces>");
+    }
+    if (_serviceProperties.size() > 0) { 
+      buf.append("<service-properties>");
+    }
+    for (String p : props) { 
+      buf.append(p);
+    }
+    if (_serviceProperties.size() > 0) { 
+      buf.append("</service-properties>");
+    }
+    buf.append("</service>");
+    _toString = buf.toString();
+    return _toString;
+  }
+  
+
+  public boolean identicalOrDiffersOnlyByName(WrappedServiceMetadata wsmi) {
+    logger.debug(LOG_ENTRY,"identicalOrDiffersOnlyByName", wsmi);
+    
+    if (this.equals(wsmi)) { 
+      logger.debug(LOG_EXIT, "identicalOrDiffersOnlyByName", true);
+      return true;
+    }
+
+    Set<String> myInterfaces = new HashSet<String>(_interfaces);
+    Set<String> cmpInterfaces = new HashSet<String>(wsmi.getInterfaces());
+    if (!myInterfaces.equals(cmpInterfaces)) { 
+      logger.debug(LOG_EXIT, "identicalOrDiffersOnlyByName", false);
+      return false;
+    }
+    
+    boolean propertiesEqual = _serviceProperties.equals(wsmi.getServiceProperties());
+    if (!propertiesEqual) {
+      logger.debug(LOG_EXIT, "identicalOrDiffersOnlyByName", false);
+      return false;
+    }
+    logger.debug(LOG_EXIT, "identicalOrDiffersOnlyByName", true);
+    return true;
+  }
+
+  
+}

Added: aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedBundleImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedBundleImpl.java?rev=1075132&view=auto
==============================================================================
--- aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedBundleImpl.java (added)
+++ aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedBundleImpl.java Sun Feb 27 20:20:13 2011
@@ -0,0 +1,222 @@
+/*
+ * 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.impl;
+
+
+
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.aries.application.InvalidAttributeException;
+import org.apache.aries.application.modelling.ImportedBundle;
+import org.apache.aries.application.modelling.ModellingConstants;
+import org.apache.aries.application.modelling.Provider;
+import org.apache.aries.application.modelling.ResourceType;
+import org.apache.aries.application.modelling.utils.impl.ModellingHelperImpl;
+import org.apache.aries.application.utils.FilterUtils;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A model of a Bundle imported, or required, by something. For example, an entry in an APPLICATION.MF. 
+ */
+public class ImportedBundleImpl implements ImportedBundle
+{
+ 
+  private final Map<String, String> _attributes;
+  private final String _filterString;
+  private final Filter _filter;
+  private final Logger logger = LoggerFactory.getLogger(ImportedBundleImpl.class);
+  /**
+   * Build an ImportedBundleImpl from filter string and a set of attributes. The filter string is 
+   * most easily obtained ManifestHeaderProcessor.generateFilter() or Requirement.getFilter() - 
+   * be careful if building your own. 
+   * @param filterString For example as obtained from Requirement.getFilter()
+   * @param attributes   
+   * @throws InvalidAttributeException 
+   */
+  public ImportedBundleImpl(String filterString, Map<String, String> attributes) throws InvalidAttributeException
+  {
+    logger.debug(LOG_ENTRY, "ImportedBundleImpl", new Object[]{filterString, attributes});
+    _attributes = new HashMap<String, String> (attributes);
+    String versionRange = _attributes.remove(Constants.BUNDLE_VERSION_ATTRIBUTE);
+    if(versionRange == null) {
+      versionRange = Version.emptyVersion.toString();
+    }
+    if(_attributes.get(Constants.VERSION_ATTRIBUTE) == null) { 
+       _attributes.put(Constants.VERSION_ATTRIBUTE, versionRange);
+    }
+    _filterString = filterString;
+    try { 
+      _filter = FrameworkUtil.createFilter(FilterUtils.removeMandatoryFilterToken(_filterString));
+    } catch (InvalidSyntaxException isx) {
+      InvalidAttributeException iax = new InvalidAttributeException(isx);
+      logger.debug(LOG_EXIT, "ImportedBundleImpl", new Object[]{iax});
+      throw iax;
+    }
+    logger.debug(LOG_EXIT, "ImportedBundleImpl");
+  }
+  
+  /**
+   * Build an ImportedBundleImpl from a bundle name and version range.  
+   * @param bundleName   Bundle symbolic name
+   * @param versionRange Bundle version range
+   * @throws InvalidAttributeException
+   */
+  public ImportedBundleImpl (String bundleName, String versionRange) throws InvalidAttributeException { 
+    logger.debug(LOG_ENTRY, "ImportedBundleImpl", new Object[] {bundleName, versionRange});
+    _attributes = new HashMap<String, String> ();
+    _attributes.put (ModellingConstants.OBR_SYMBOLIC_NAME, bundleName);
+    _attributes.put (Constants.VERSION_ATTRIBUTE, versionRange);
+    _filterString = ManifestHeaderProcessor.generateFilter(_attributes);
+    try { 
+      _filter = FrameworkUtil.createFilter(FilterUtils.removeMandatoryFilterToken(_filterString));
+    } catch (InvalidSyntaxException isx) { 
+      InvalidAttributeException iax = new InvalidAttributeException(isx);
+      logger.debug(LOG_ENTRY, "ImportedBundleImpl", new Object[] {iax});
+      throw iax;
+    }
+    logger.debug(LOG_EXIT, "ImportedBundleImpl"); 
+  }
+ 
+
+  public String getAttributeFilter() {
+    logger.debug(LOG_ENTRY, "getAttributeFilter");
+    logger.debug(LOG_EXIT, "getAttributeFilter", new Object[] {_filterString});
+    return _filterString;
+  }
+
+
+  public ResourceType getType() {
+
+    logger.debug(LOG_ENTRY, "getType");
+    logger.debug(LOG_EXIT, "getType", new Object[] {ResourceType.BUNDLE});
+    return ResourceType.BUNDLE;
+  }
+
+
+  public boolean isMultiple() {
+    logger.debug(LOG_ENTRY, "isMultiple");
+    logger.debug(LOG_EXIT, "isMultiple", new Object[] {false});
+    return false;
+  }
+
+
+  public boolean isOptional() {
+    logger.debug(LOG_ENTRY, "isOptional");
+    boolean optional = false;
+    if (_attributes.containsKey(Constants.RESOLUTION_DIRECTIVE + ":")) {
+      if ((Constants.RESOLUTION_OPTIONAL).equals
+          (_attributes.get(Constants.RESOLUTION_DIRECTIVE + ":"))) { 
+        optional = true;
+      }
+    }
+    logger.debug(LOG_EXIT, "isOptional", optional);
+    return optional;
+  }
+
+  public boolean isSatisfied(Provider capability) {
+    logger.debug(LOG_ENTRY, "isSatisfied", capability);
+    if (capability.getType() != ResourceType.BUNDLE 
+        && capability.getType() != ResourceType.COMPOSITE) { 
+      logger.debug(LOG_EXIT, "isSatisfied", false);
+      return false;
+    }
+    Dictionary<String, Object> dict = new Hashtable<String, Object> (capability.getAttributes());
+    String version = (String) dict.get(Constants.VERSION_ATTRIBUTE);
+    if (version != null) { 
+      dict.put(Constants.VERSION_ATTRIBUTE, Version.parseVersion(version));
+    }
+    boolean allPresent = ModellingHelperImpl.areMandatoryAttributesPresent_(_attributes, capability);
+    boolean result = allPresent && _filter.match(dict);
+    logger.debug(LOG_EXIT, "isSatisfied", result);
+    return result;
+  }
+  
+  /**
+   * Get the version range on this bundle import
+   * @return Imported version range, as a string
+   */
+  public String getVersionRange() {
+    logger.debug(LOG_ENTRY, "getVersionRange");
+    String range = _attributes.get(Constants.VERSION_ATTRIBUTE);
+    String result = (range == null) ? Version.emptyVersion.toString() : range;
+    logger.debug(LOG_EXIT, "getVersionRange", result);
+    return result;
+  }
+  
+  /**
+   * Get the symbolic name of the imported bundle
+   * @return symbolic name
+   */
+  public String getSymbolicName() {
+    logger.debug(LOG_ENTRY, "getSymbolicName");
+    String result = _attributes.get(ModellingConstants.OBR_SYMBOLIC_NAME);
+    logger.debug(LOG_EXIT, "getSymbolicName", result);
+    return result;
+  }
+  
+  /**
+   * Equal if symbolic names match and version strings match
+   */
+  @Override
+  public boolean equals(Object o)
+  {
+    logger.debug(LOG_ENTRY, "equals", o);
+    boolean result = false;
+    if (o == this)
+    {
+      result = true;
+    }
+    else if (o instanceof ImportedBundleImpl)
+    {
+      ImportedBundleImpl ib = (ImportedBundleImpl)o;
+      result = (getSymbolicName().equals(ib.getSymbolicName())
+          && getVersionRange().equals(ib.getVersionRange()));
+    }
+    logger.debug(LOG_EXIT, "equals", result);
+    return result;
+  }
+  
+  @Override
+  public int hashCode()
+  {
+    logger.debug(LOG_ENTRY, "hashCode");
+    int hashCode = getSymbolicName().hashCode() + 31 * getVersionRange().hashCode();
+    logger.debug(LOG_ENTRY, "hashCode", hashCode);
+    return hashCode;
+  }
+  
+  @Override
+  public String toString() {
+    return _filterString;
+  }
+}

Added: aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedPackageImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedPackageImpl.java?rev=1075132&view=auto
==============================================================================
--- aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedPackageImpl.java (added)
+++ aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedPackageImpl.java Sun Feb 27 20:20:13 2011
@@ -0,0 +1,209 @@
+/*
+ * 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.impl;
+
+import static org.apache.aries.application.modelling.ModellingConstants.OPTIONAL_KEY;
+import static org.apache.aries.application.modelling.ResourceType.PACKAGE;
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.aries.application.InvalidAttributeException;
+import org.apache.aries.application.modelling.ImportedPackage;
+import org.apache.aries.application.modelling.Provider;
+import org.apache.aries.application.modelling.ResourceType;
+import org.apache.aries.application.modelling.utils.impl.ModellingHelperImpl;
+import org.apache.aries.application.utils.FilterUtils;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * An imported, or required package. Capable of generating an entry in DEPLOYMENT.MF's Import-Package header. 
+ */
+public class ImportedPackageImpl implements ImportedPackage
+{
+
+  
+  private final boolean _optional;
+  private final String _filterString;
+  private final Filter _filter;
+  private final String _package;
+  private final String _versionRange;
+  private final Map<String,String> _attributes;
+  private final Logger logger = LoggerFactory.getLogger(ImportedPackageImpl.class);
+  /**
+   * Construct a package requirement
+   * @param pkg The name of the required package
+   * @param attributes Other attributes - most commonly, version
+   * @throws InvalidAttributeException
+   */
+  public ImportedPackageImpl (String pkg, Map<String, String> attributes) throws InvalidAttributeException {
+    logger.debug(LOG_ENTRY, "ImportedPackageImpl", new Object[] {pkg, attributes});
+    _package = pkg;
+    String versionRange = null;
+    if (attributes != null) {
+      _optional = (Constants.RESOLUTION_OPTIONAL.equals(attributes.get(OPTIONAL_KEY)));
+      versionRange = attributes.get(Constants.VERSION_ATTRIBUTE);
+      _attributes = new HashMap<String, String>(attributes);
+    } else { 
+      _optional = false;
+      _attributes = new HashMap<String, String>();
+    }
+    if (versionRange == null) {
+      _versionRange = Version.emptyVersion.toString();
+    } else { 
+      _versionRange = versionRange;
+    }
+    
+    _attributes.put(Constants.VERSION_ATTRIBUTE, _versionRange);
+    _filterString = ManifestHeaderProcessor.generateFilter(PACKAGE.toString(), _package, _attributes);
+    try { 
+    _filter = FrameworkUtil.createFilter(FilterUtils.removeMandatoryFilterToken(_filterString));
+    } catch (InvalidSyntaxException isx) { 
+      logger.debug(LOG_EXIT, "ImportedPackageImpl", new Object[] {isx});
+      throw new InvalidAttributeException(isx);
+    }
+    logger.debug(LOG_EXIT, "ImportedPackageImpl");
+  }
+  
+  /**
+   * Get this ImportedPackageImpl's attributes
+   * @return attributes
+   */
+  public Map<String, String> getAttributes() { 
+    logger.debug(LOG_ENTRY, "getAttributes");
+    logger.debug(LOG_EXIT, "getAttributes", new Object[] {_attributes});
+    return Collections.unmodifiableMap(_attributes);
+  }
+  
+  /**
+   * Get the package name
+   * @return package name
+   */
+  public String getPackageName() { 
+    logger.debug(LOG_ENTRY, "getPackageName");
+    logger.debug(LOG_EXIT, "getPackageName", new Object[] {_package});
+    return _package;
+  }
+  
+  /**
+   * Get the imported package's version range
+   * @return version range
+   */
+  public String getVersionRange() {
+    logger.debug(LOG_ENTRY, "getVersionRange");
+    logger.debug(LOG_EXIT, "getVersionRange", new Object[] {_versionRange});
+    return _versionRange;
+  }
+  
+
+  public String getAttributeFilter() {
+    logger.debug(LOG_ENTRY, "getAttributeFilter");
+    logger.debug(LOG_EXIT, "getAttributeFilter", new Object[] {_filterString});
+    return _filterString;
+  }
+
+
+  public ResourceType getType() {
+    logger.debug(LOG_ENTRY, "getType");
+    logger.debug(LOG_EXIT, "getType", new Object[] {PACKAGE});
+    return PACKAGE;
+  }
+
+
+  public boolean isMultiple() {
+    logger.debug(LOG_ENTRY, "isMultiple");
+    logger.debug(LOG_EXIT, "isMultiple", new Object[] {false});
+    return false;   // cannot import a given package more than once
+  }
+
+
+  public boolean isOptional() {
+    logger.debug(LOG_ENTRY, "isOptional");
+    logger.debug(LOG_EXIT, "isOptional", new Object[] {_optional});
+    return _optional;
+  }
+
+
+  public boolean isSatisfied(Provider capability) {
+    logger.debug(LOG_ENTRY, "isSatisfied", new Object[]{capability});
+    if (capability.getType() != PACKAGE) { 
+      logger.debug(LOG_EXIT, "isSatisfied", new Object[] {false});
+      return false;
+    }
+    Dictionary<String, Object> dict = new Hashtable<String, Object> (capability.getAttributes());
+    String version = (String) dict.get(Constants.VERSION_ATTRIBUTE);
+    if (version != null) { 
+      dict.put(Constants.VERSION_ATTRIBUTE, Version.parseVersion(version));
+    }
+    
+    boolean allPresent = ModellingHelperImpl.areMandatoryAttributesPresent_(_attributes, capability);
+    boolean result = allPresent && _filter.match(dict);
+    logger.debug(LOG_EXIT, "isSatisfied", new Object[] {result});
+    return result;
+  }
+
+  
+  
+  /**
+  * This method turns an {@link ImportedPackageImpl} into a string suitable for a 
+  * Provision-Bundle style package import.  
+  * It will not include ;bundle-symbolic-name=bundleName;bundle-version=version attribute pairs
+  * @return A String
+  */
+  @SuppressWarnings("deprecation")
+  public String toDeploymentString() {
+    logger.debug(LOG_ENTRY, "toDeploymentString");
+    StringBuilder sb = new StringBuilder(_package);
+    // Note that the RESOLUTION_DIRECTIVE is set in this map, so it will be
+    // output automatically. p41 of the OSGi Core Spec v4.2 includes an example
+    // Import-Package with a resolution:=mandatory directive on. We could choose to suppress
+    // resolution:=mandatory on packages however, since mandatory is the default.
+    for (Map.Entry<String, String> entry : _attributes.entrySet()) {
+      String key = entry.getKey();
+      String value = entry.getValue();
+      if (!key.equals(Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)
+          && !key.equals(Constants.BUNDLE_VERSION_ATTRIBUTE)
+          && !key.equals(PACKAGE.toString())
+          && !key.equals(Constants.PACKAGE_SPECIFICATION_VERSION)) {
+        sb.append(";").append(key).append("=\"").append(value).append('"');
+      } else {
+        logger.debug("ignoring attribute {" + key + "=" + value + "} in ImportedPackageImpl.toDeploymentString()");
+      }
+    }
+    String result = sb.toString();
+    logger.debug(LOG_EXIT, "toDeploymentString", new Object[]{result});
+    return result;
+  }
+  
+  @Override
+  public String toString() {
+    return toDeploymentString();
+  }
+}

Added: aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedServiceImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedServiceImpl.java?rev=1075132&view=auto
==============================================================================
--- aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedServiceImpl.java (added)
+++ aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ImportedServiceImpl.java Sun Feb 27 20:20:13 2011
@@ -0,0 +1,305 @@
+/*
+ * 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.impl;
+
+import static org.apache.aries.application.modelling.ResourceType.SERVICE;
+import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
+import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.aries.application.InvalidAttributeException;
+import org.apache.aries.application.modelling.ImportedService;
+import org.apache.aries.application.modelling.ModellingConstants;
+import org.apache.aries.application.modelling.Provider;
+import org.apache.aries.application.modelling.ResourceType;
+import org.apache.aries.application.modelling.WrappedReferenceMetadata;
+import org.apache.aries.application.modelling.utils.impl.ModellingHelperImpl;
+import org.apache.aries.application.utils.FilterUtils;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ * an Import-Service entry
+ */
+public class ImportedServiceImpl implements ImportedService
+{
+  private final static String DEPRECATED_FILTER_ATTRIBUTE = "filter";
+  private final boolean _optional;
+  private final String _iface;
+  private final String _componentName;
+  private final String _blueprintFilter;
+  private final Filter _attributeFilter;
+  private final boolean _isMultiple;
+  private final String _id;
+  private final Map<String, String> _attributes;
+  private String _toString;
+  private String _attribFilterString;   // The manner in which we set means it can't be final
+  private final static Pattern SERVICE_EQUALS_SERVICE = Pattern.compile("\\(" + ResourceType.SERVICE.toString()
+      + "=" + ResourceType.SERVICE.toString() + "\\)");
+  private final Logger logger = LoggerFactory.getLogger(ImportedServiceImpl.class);
+  /**
+   * Build an ImportedServiceImpl from its elements
+   * @param optional
+   * @param iface
+   * @param componentName
+   * @param blueprintFilter
+   * @param id
+   * @param isMultiple
+   * @throws InvalidAttributeException
+   */
+  public ImportedServiceImpl (boolean optional, String iface, String componentName, 
+      String blueprintFilter, String id, boolean isMultiple) 
+    throws InvalidAttributeException 
+  {
+    
+    _optional = optional;
+    _iface = iface;
+    _componentName = componentName;
+    _blueprintFilter = FilterUtils.removeMandatoryFilterToken(blueprintFilter);
+    _id = id;
+    _isMultiple = isMultiple;
+    _attributes = new HashMap<String, String>();
+    _attributeFilter = generateAttributeFilter (_attributes);
+    
+    
+  }
+
+  private Filter generateAttributeFilter (Map<String, String> attrsToPopulate) throws InvalidAttributeException {
+    logger.debug(LOG_ENTRY, "generateAttributeFilter", new Object[]{attrsToPopulate});
+    Filter result = null;
+    
+    try {
+      attrsToPopulate.put(ModellingConstants.OBR_SERVICE, ModellingConstants.OBR_SERVICE);
+      if (_blueprintFilter != null) { 
+        // We may get blueprint filters of the form (&(a=b)(c=d)). We can't put these in 'whole' because we'll 
+        // end up generating a filter of the form (&(objectClass=foo)(&(a=b)(c=d)) which subsequent calls to 
+        // parseFilter will choke on. So as an interim fix we'll strip off a leading &( and trailing ) if present. 
+        String reducedBlueprintFilter;
+        if (_blueprintFilter.startsWith("(&")) { 
+          reducedBlueprintFilter = _blueprintFilter.substring(2, _blueprintFilter.length() - 1);
+        } else { 
+          reducedBlueprintFilter = _blueprintFilter;
+        }
+        
+        attrsToPopulate.put(ManifestHeaderProcessor.NESTED_FILTER_ATTRIBUTE, reducedBlueprintFilter);
+      }
+      if (_componentName != null) { 
+        attrsToPopulate.put ("osgi.service.blueprint.compname", _componentName);
+      }
+      if (_iface != null) { 
+        attrsToPopulate.put (Constants.OBJECTCLASS, _iface);
+      }
+      _attribFilterString = ManifestHeaderProcessor.generateFilter(_attributes);
+      if (! "".equals(_attribFilterString)) { 
+        result = FrameworkUtil.createFilter(FilterUtils.removeMandatoryFilterToken(_attribFilterString));
+      } 
+    } catch (InvalidSyntaxException isx) { 
+      
+      InvalidAttributeException iax = new InvalidAttributeException(isx);
+      logger.debug(LOG_EXIT, "generateAttributeFilter", new Object[]{isx});
+      throw iax;
+    }
+    logger.debug(LOG_EXIT, "generateAttributeFilter", new Object[]{result});
+    return result;
+  }
+  
+  /** 
+   * Deprecated constructor for building these from deprecated Export-Service manifest headers. Do not use this 
+   * constructor for any other purpose. 
+   * @param ifaceName
+   * @param attributes
+   * @throws InvalidAttributeException 
+   */
+  @Deprecated
+  public ImportedServiceImpl (String ifaceName, Map<String, String> attributes) throws InvalidAttributeException {
+    
+    _optional = ("optional".equals(attributes.get("availability:")));
+    _iface = ifaceName;
+    _isMultiple = false;
+    _componentName = null;
+    _id = null;
+    _attributes = new HashMap<String, String>(attributes);
+    
+    // The syntax for this deprecated header allows statements of the form, 
+    // ImportService: myService;filter="(a=b")
+    _blueprintFilter = _attributes.remove(DEPRECATED_FILTER_ATTRIBUTE);
+    _attributeFilter = generateAttributeFilter (_attributes);
+    
+    
+  }
+
+  public String getFilter() {
+    logger.debug(LOG_ENTRY, "getFilter");
+    logger.debug(LOG_EXIT, "getFilter", _blueprintFilter);
+    return _blueprintFilter;
+  }
+
+
+  public ResourceType getType() {
+    logger.debug(LOG_ENTRY, "getType");
+    logger.debug(LOG_EXIT, "getType",  ResourceType.SERVICE);
+    return ResourceType.SERVICE;
+  }
+
+
+ public boolean isMultiple() {
+   logger.debug(LOG_ENTRY, "isMultiple");
+   logger.debug(LOG_EXIT, "isMultiple",  _isMultiple);
+    return _isMultiple;
+  }
+
+
+
+  public boolean isOptional() {
+    logger.debug(LOG_ENTRY, "isOptional");
+    logger.debug(LOG_EXIT, "isOptional",  _optional);
+    return _optional;
+  }
+
+
+  public boolean isSatisfied(Provider capability) {
+    logger.debug(LOG_ENTRY, "isSatisfied", capability);
+    
+    if (capability.getType() != SERVICE) { 
+      logger.debug(LOG_EXIT, "isSatisfied",  false);
+      return false;
+    }
+    Dictionary<String, Object> dict = new Hashtable<String, Object> (capability.getAttributes());
+    
+    // If there's a value for ObjectClass, it may be a comma separated list.
+    String objectClass = (String) dict.get(Constants.OBJECTCLASS);
+    if (objectClass != null) { 
+      String [] split = objectClass.split (",");
+      dict.put (Constants.OBJECTCLASS, split);
+    }
+    
+    if (_attributeFilter == null) { 
+      logger.debug(LOG_EXIT, "isSatisfied",  true);
+      return true;
+    }
+    boolean allPresent = ModellingHelperImpl.areMandatoryAttributesPresent_(_attributes, capability);
+    boolean result = allPresent && _attributeFilter.match(dict);
+    logger.debug(LOG_EXIT, "isSatisfied",  result);
+    return result;
+  }
+
+  
+  public String getComponentName() {
+    logger.debug(LOG_ENTRY, "getComponentName");
+    logger.debug(LOG_EXIT, "getComponentName",  _componentName);
+    return _componentName;
+  }
+
+  
+  public String getId() {
+    logger.debug(LOG_ENTRY, "getId");
+    logger.debug(LOG_EXIT, "getId",  _id);
+    return _id;
+  }
+
+  
+  public String getInterface() {
+    logger.debug(LOG_ENTRY, "getInterface");
+    logger.debug(LOG_EXIT, "getInterface",  _iface);
+   return _iface;
+  }
+
+  public boolean isList() {
+    logger.debug(LOG_ENTRY, "isList");    
+    boolean result = isMultiple();
+    logger.debug(LOG_EXIT, "isList",  result);
+    return result;
+  }
+
+
+  public String getAttributeFilter() {
+    logger.debug(LOG_ENTRY, "getAttributeFilter");
+    logger.debug(LOG_EXIT, "getAttributeFilter",  _attribFilterString);
+    return _attribFilterString;
+  }
+  
+  @Override
+  public boolean equals (Object o) { 
+    
+    boolean equal = false;
+    if (o==null) { 
+      equal = false;
+    } else if (o==this) { 
+      equal = true;
+    } else if (!(o instanceof WrappedReferenceMetadata)) { 
+      equal = false;
+    } else { 
+      equal = toString().equals(o.toString());
+    }
+    
+    return equal;
+  }
+  
+  @Override
+  public int hashCode() {
+    
+    int result = toString().hashCode();
+    
+    return result;
+  }
+  
+  @Override 
+  public String toString() { 
+    logger.debug(LOG_ENTRY, "toString");
+    
+    if (_toString != null) { 
+      logger.debug(LOG_EXIT, "toString",  _toString);
+      return _toString;
+    }
+    StringBuffer buf = new StringBuffer("<reference>");
+    buf.append("<componentName>" + _componentName + "</componentName>");
+    buf.append("<id>" + _id + "</id>");
+    buf.append("<interface>" + _iface + "</interface>");
+    buf.append("<isList>" + _isMultiple + "</isList>");
+    buf.append("<isOptional>" + _optional + "</isOptional>");
+    // We don't have a method for writing filters in a canonical form
+    buf.append("<filter>" + _blueprintFilter + "</filter>");
+    _toString = buf.toString();
+    logger.debug(LOG_EXIT, "toString",  _toString);
+    return _toString;
+  }
+
+  /**
+   * A String suitable for use in DeployedImport-Service
+   */
+  public String toDeploymentString() {
+    logger.debug(LOG_ENTRY, "toDeploymentString");    
+    String baseFilter = getAttributeFilter();
+    // We may have one or more (service=service) elements that must be removed.
+    String reducedFilter = SERVICE_EQUALS_SERVICE.matcher(baseFilter).replaceAll("");    
+    // now trim off mandatory:<*service occurrences
+    String result = FilterUtils.removeMandatoryFilterToken(reducedFilter);
+    logger.debug(LOG_EXIT, "toDeploymentString",  result);
+    return result;
+  }
+}

Added: aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ModelledResourceImpl.java
URL: http://svn.apache.org/viewvc/aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ModelledResourceImpl.java?rev=1075132&view=auto
==============================================================================
--- aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ModelledResourceImpl.java (added)
+++ aries/tags/application-0.3/application-modeller/src/main/java/org/apache/aries/application/modelling/impl/ModelledResourceImpl.java Sun Feb 27 20:20:13 2011
@@ -0,0 +1,342 @@
+/*
+ * 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.impl;
+
+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.DYNAMICIMPORT_PACKAGE;
+import static org.osgi.framework.Constants.EXPORT_PACKAGE;
+import static org.osgi.framework.Constants.EXPORT_SERVICE;
+import static org.osgi.framework.Constants.IMPORT_PACKAGE;
+import static org.osgi.framework.Constants.IMPORT_SERVICE;
+import static org.osgi.framework.Constants.REQUIRE_BUNDLE;
+import static org.osgi.framework.Constants.RESOLUTION_DIRECTIVE;
+import static org.osgi.framework.Constants.RESOLUTION_OPTIONAL;
+import static org.osgi.framework.Constants.VERSION_ATTRIBUTE;
+
+import java.util.ArrayList;
+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.InvalidAttributeException;
+import org.apache.aries.application.management.BundleInfo;
+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.ModellingConstants;
+import org.apache.aries.application.modelling.ResourceType;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A model of a bundle or composite. Used for example to supply information to 
+ * RepositoryGenerator.generateRepository()
+ *
+ */
+public class ModelledResourceImpl implements ModelledResource
+{
+  private final Logger logger = LoggerFactory.getLogger(ModelledResourceImpl.class);
+  private final String _fileURI;
+  private final Collection<ImportedService> _importedServices;
+  private final Collection<ExportedService> _exportedServices;
+  private final Collection<ExportedPackage> _exportedPackages;
+  private final Collection<ImportedPackage> _importedPackages;
+  private final Collection<ImportedBundle> _requiredBundles;
+  private final ExportedBundle _exportedBundle; 
+  private final ResourceType _resourceType;     
+  
+  /**
+   * Construct a new {@link ModelledResourceImpl} for the following manifest and services
+   * @param fileURI The location of the bundle, may be null, which indicates a by value bundle
+   * @param bundleInfo The bundle info object
+   * @param importedServices The blueprint references defined by the bundle. May be null
+   * @param exportedServices The blueprint services exported by the bundle. May be null
+   * @throws InvalidAttributeException
+   */
+  public ModelledResourceImpl (String fileURI, BundleInfo bundleInfo, 
+      Collection<ImportedService> importedServices, 
+      Collection<ExportedService> exportedServices) throws InvalidAttributeException
+  {
+    this(fileURI, bundleInfo.getRawAttributes(), importedServices, exportedServices);
+  }
+  /**
+   * Construct a new {@link ModelledResourceImpl} for the following manifest and services
+   * @param fileURI The location of the bundle, may be null, which indicates a by value bundle
+   * @param bundleAttributes The bundle manifest, must not be null
+   * @param importedServices The blueprint references defined by the bundle. May be null
+   * @param exportedServices The blueprint services exported by the bundle. May be null
+   * @throws InvalidAttributeException
+   */
+  @SuppressWarnings("deprecation")
+  public ModelledResourceImpl (String fileURI, Attributes bundleAttributes, ExportedBundle exportedBundle, ResourceType resourceType,
+      Collection<ImportedService> importedServices, 
+      Collection<ExportedService> exportedServices) throws InvalidAttributeException
+  { 
+    this (fileURI, bundleAttributes, resourceType, exportedBundle, importedServices, exportedServices);
+    logger.debug(LOG_ENTRY, "ModelledResourceImpl", new Object[]{fileURI, bundleAttributes, importedServices, exportedServices});
+    logger.debug(LOG_EXIT, "ModelledResourceImpl");
+  }
+
+  /**
+   * Construct a new {@link ModelledResourceImpl} for the following manifest and services
+   * @param fileURI The location of the bundle, may be null, which indicates a by value bundle
+   * @param bundleAttributes The bundle manifest, must not be null
+   * @param importedServices The blueprint references defined by the bundle. May be null
+   * @param exportedServices The blueprint services exported by the bundle. May be null
+   * @throws InvalidAttributeException
+   */
+  @SuppressWarnings("deprecation")
+  public ModelledResourceImpl (String fileURI, Attributes bundleAttributes, 
+      Collection<ImportedService> importedServices, 
+      Collection<ExportedService> exportedServices) throws InvalidAttributeException
+  { 
+    this (fileURI, bundleAttributes, ResourceType.BUNDLE, null, importedServices, exportedServices );
+    logger.debug(LOG_ENTRY, "ModelledResourceImpl", new Object[]{fileURI, bundleAttributes, importedServices, exportedServices});
+    logger.debug(LOG_EXIT, "ModelledResourceImpl");
+  }
+  
+  public ModelledResourceImpl (String fileURI, Attributes bundleAttributes, 
+      ResourceType resourceType, ExportedBundle exportedBundle,
+      Collection<ImportedService> importedServices, 
+      Collection<ExportedService> exportedServices 
+      ) throws InvalidAttributeException 
+  {
+    logger.debug(LOG_ENTRY, "ModelledResourceImpl", new Object[]{fileURI, bundleAttributes, importedServices, exportedServices, 
+        resourceType});
+
+    if (exportedBundle == null) { 
+      _exportedBundle = new ExportedBundleImpl (bundleAttributes);
+    } else { 
+      _exportedBundle = exportedBundle;
+    }
+    _resourceType = resourceType;
+    _fileURI = fileURI;
+    if(importedServices != null)
+      _importedServices = new ArrayList<ImportedService> (importedServices);
+    else
+      _importedServices = new ArrayList<ImportedService>();
+    
+    if(exportedServices != null)
+      _exportedServices = new ArrayList<ExportedService> (exportedServices);
+    else
+      _exportedServices = new ArrayList<ExportedService>();
+    
+    _exportedPackages = new ArrayList<ExportedPackage>();
+    String packageExports = bundleAttributes.getValue(EXPORT_PACKAGE);
+    if (packageExports != null) {
+      List<NameValuePair<String, NameValueMap<String, String>>> exportedPackages = ManifestHeaderProcessor
+        .parseExportString(packageExports);
+      for (NameValuePair<String, NameValueMap<String, String>> exportedPackage : exportedPackages) {
+        _exportedPackages.add(new ExportedPackageImpl(this, exportedPackage.getName(), 
+            new HashMap<String, Object>(exportedPackage.getValue())));
+    
+      }
+    }
+  
+    _importedPackages = new ArrayList<ImportedPackage>();
+    String packageImports = bundleAttributes.getValue(IMPORT_PACKAGE);
+    if (packageImports != null) {
+      Map<String, NameValueMap<String, String>> importedPackages = ManifestHeaderProcessor
+          .parseImportString(packageImports);
+      for (Map.Entry<String, NameValueMap<String, String>> importedPackage : importedPackages.entrySet()) {
+        Map<String, String> atts = importedPackage.getValue();
+        _importedPackages.add(new ImportedPackageImpl(importedPackage.getKey(), atts));
+      }
+    }
+    
+    // Use of Import-Service and Export-Service is deprecated in OSGi. We like Blueprint. 
+    // Blueprint is good. 
+    
+    String serviceExports = null; 
+    if (_resourceType == ResourceType.BUNDLE) { 
+      serviceExports = bundleAttributes.getValue(EXPORT_SERVICE);
+    } 
+    if (serviceExports != null) {
+      List<NameValuePair<String, NameValueMap<String, String>>> expServices = ManifestHeaderProcessor
+          .parseExportString(serviceExports);
+      for (NameValuePair<String, NameValueMap<String, String>> exportedService : expServices) {
+        _exportedServices.add(new ExportedServiceImpl(exportedService.getName(), exportedService.getValue()));
+      }
+    }
+  
+    String serviceImports =null;
+    if (_resourceType == ResourceType.BUNDLE) { 
+      serviceImports = bundleAttributes.getValue(IMPORT_SERVICE);
+    } 
+    if (serviceImports != null) {
+      Map<String, NameValueMap<String, String>> svcImports = ManifestHeaderProcessor
+          .parseImportString(serviceImports);
+      for (Map.Entry<String, NameValueMap<String, String>> importedService : svcImports.entrySet()) {
+        _importedServices.add(new ImportedServiceImpl(importedService.getKey(), importedService.getValue()));
+      }
+    }
+    
+    _requiredBundles = new ArrayList<ImportedBundle>();
+    // Require-Bundle and DynamicImport-Package relevant to Bundles but not Composites
+    if (_resourceType == ResourceType.BUNDLE) { 
+      String requireBundleHeader = bundleAttributes.getValue(REQUIRE_BUNDLE);
+      if (requireBundleHeader != null) {
+        Map<String, NameValueMap<String, String>> requiredBundles = ManifestHeaderProcessor
+            .parseImportString(requireBundleHeader);
+        for (Map.Entry<String, NameValueMap<String, String>> bundle : requiredBundles.entrySet()) {
+          String type = bundle.getKey();
+          Map<String, String> attribs = bundle.getValue();
+          // We may parse a manifest with a header like Require-Bundle: bundle.a;bundle-version=3.0.0
+          // The filter that we generate is intended for OBR in which case we need (version>=3.0.0) and not (bundle-version>=3.0.0)
+          String bundleVersion = attribs.remove(BUNDLE_VERSION_ATTRIBUTE);
+          if (bundleVersion != null && attribs.get(VERSION_ATTRIBUTE) == null) { 
+            attribs.put (VERSION_ATTRIBUTE, bundleVersion);
+          }
+          String filter = ManifestHeaderProcessor.generateFilter(ModellingConstants.OBR_SYMBOLIC_NAME, type, attribs);
+          Map<String, String> atts = new HashMap<String, String>(bundle.getValue());
+          atts.put(ModellingConstants.OBR_SYMBOLIC_NAME,  bundle.getKey());
+          _requiredBundles.add(new ImportedBundleImpl(filter, atts));
+        }
+      }
+    
+      String dynamicImports = bundleAttributes.getValue(DYNAMICIMPORT_PACKAGE);
+      if (dynamicImports != null) {
+        Map<String, NameValueMap<String, String>> dynamicImportPackages = ManifestHeaderProcessor
+            .parseImportString(dynamicImports);
+        for (Map.Entry<String, NameValueMap<String, String>> dynImportPkg : dynamicImportPackages.entrySet()) {
+          if (dynImportPkg.getKey().indexOf("*") == -1) {
+            dynImportPkg.getValue().put(RESOLUTION_DIRECTIVE + ":", RESOLUTION_OPTIONAL);
+            _importedPackages.add(new ImportedPackageImpl(dynImportPkg.getKey(), dynImportPkg.getValue()));
+          }
+        }
+      }
+    }
+    logger.debug(LOG_EXIT, "ModelledResourceImpl");
+  }
+
+
+  public String getLocation() {
+    logger.debug(LOG_ENTRY, "getLocation");
+    logger.debug(LOG_EXIT, "getLocation", _fileURI);
+    return _fileURI;
+  }
+
+
+  public ExportedBundle getExportedBundle() {
+    logger.debug(LOG_ENTRY, "getExportedBundle");
+    logger.debug(LOG_EXIT, "getExportedBundle",  _exportedBundle);
+    return _exportedBundle;
+  }
+
+
+  public Collection<ExportedPackage> getExportedPackages() {
+    logger.debug(LOG_ENTRY, "getExportedPackages");
+    logger.debug(LOG_EXIT, "getExportedPackages",  _exportedPackages);
+    return Collections.unmodifiableCollection(_exportedPackages);
+  }
+  
+
+
+  public Collection<ImportedPackage> getImportedPackages() {
+    logger.debug(LOG_ENTRY, "getImportedPackages");
+    logger.debug(LOG_EXIT, "getImportedPackages",  _importedPackages);
+    return Collections.unmodifiableCollection(_importedPackages);
+  }
+
+  public Collection<ExportedService> getExportedServices() {
+    logger.debug(LOG_ENTRY, "getExportedServices");
+    logger.debug(LOG_EXIT, "getExportedServices",  _exportedServices);
+    return Collections.unmodifiableCollection(_exportedServices);
+  }
+
+
+
+  public Collection<ImportedService> getImportedServices() {
+    logger.debug(LOG_ENTRY, "getImportedServices");
+    logger.debug(LOG_EXIT, "getImportedServices",  _exportedServices);
+    return Collections.unmodifiableCollection(_importedServices);
+  }
+
+
+  public String getSymbolicName() {
+    logger.debug(LOG_ENTRY, "getSymbolicName");
+    String result = _exportedBundle.getSymbolicName();
+    logger.debug(LOG_EXIT, "getSymbolicName",  result);
+    return result;
+  }
+  
+
+  public String getVersion() {
+    logger.debug(LOG_ENTRY, "getVersion");
+    String result = _exportedBundle.getVersion();
+    logger.debug(LOG_EXIT, "getVersion",  result);
+    return result;
+  }
+
+
+  public String toDeploymentString() {
+    logger.debug(LOG_ENTRY, "toDeploymentString");
+    String result = _exportedBundle.toDeploymentString();
+    logger.debug(LOG_EXIT, "toDeploymentString",  result);
+    return result;
+  }
+
+
+  public ResourceType getType() {
+    logger.debug(LOG_ENTRY, "getType");
+    logger.debug(LOG_EXIT, "getType",  ResourceType.BUNDLE);
+    return _resourceType;
+  }
+  
+  @Override
+  public String toString() {
+    return toDeploymentString();
+  }
+
+
+  public Collection<ImportedBundle> getRequiredBundles() {
+    logger.debug(LOG_ENTRY, "getRequiredBundles");
+    logger.debug(LOG_EXIT, "getRequiredBundles",  _requiredBundles);
+    return Collections.unmodifiableCollection(_requiredBundles);
+  }
+
+
+  public ImportedBundle getFragmentHost() {
+    logger.debug(LOG_ENTRY, "getFragmentHost");
+    ImportedBundle result = _exportedBundle.getFragmentHost();
+    logger.debug(LOG_EXIT, "getFragmentHost",  result);
+    return result;
+  }
+
+
+  public boolean isFragment() {
+    logger.debug(LOG_ENTRY, "isFragment");
+    boolean result = _exportedBundle.isFragment();
+    logger.debug(LOG_EXIT, "isFragment",  result);
+    return result;
+  }
+}