/*
* 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.resolver.obr.ext;
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 org.apache.aries.application.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.ModellingConstants;
import org.apache.aries.application.modelling.ModellingManager;
import org.apache.aries.application.modelling.ResourceType;
import org.apache.aries.application.modelling.utils.ModellingHelper;
import org.apache.aries.application.resolver.internal.MessageUtil;
import org.apache.aries.application.utils.AppConstants;
import org.apache.aries.util.manifest.ManifestHeaderProcessor;
import org.apache.felix.bundlerepository.Capability;
import org.apache.felix.bundlerepository.Property;
import org.apache.felix.bundlerepository.Requirement;
import org.apache.felix.bundlerepository.Resource;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ModelledBundleResource implements ModelledResource {
private final Resource resource;
private final ExportedBundle exportedBundle;
private final Collection<ImportedPackage> packageRequirements;
private final Collection<ImportedService> serviceRequirements;
private final Collection<ExportedPackage> packageCapabilities;
private final Collection<ExportedService> serviceCapabilties;
private final Collection<ImportedBundle> bundleRequirements;
private final ResourceType type;
private final ModellingManager modellingManager;
private final ModellingHelper modellingHelper;
private final Logger logger = LoggerFactory.getLogger(ModelledBundleResource.class);
public ModelledBundleResource (Resource r, ModellingManager mm, ModellingHelper mh) throws InvalidAttributeException {
logger.debug(LOG_ENTRY, "ModelledBundleResource", new Object[]{r, mm, mh});
resource = r;
modellingManager = mm;
modellingHelper = mh;
List<ExportedBundle> exportedBundles = new ArrayList<ExportedBundle>();
ResourceType thisResourceType = ResourceType.BUNDLE;
// We'll iterate through our Capabilities a second time below. We do this since we later
// build an ExportedPackageImpl for which 'this' is the ModelledResource.
for (Capability cap : r.getCapabilities()) {
String capName = cap.getName();
if (capName.equals(ResourceType.BUNDLE.toString())) {
@SuppressWarnings("unchecked")
Property[] props = cap.getProperties();
Map<String,String> sanitizedMap = new HashMap<String, String>();
for(Property entry : props) {
sanitizedMap.put(entry.getName(), entry.getValue());
}
exportedBundles.add (modellingManager.getExportedBundle(sanitizedMap, modellingHelper.buildFragmentHost(
sanitizedMap.get(Constants.FRAGMENT_HOST))));
} else if (cap.getName().equals(ResourceType.COMPOSITE.toString())) {
thisResourceType = ResourceType.COMPOSITE;
}
}
type = thisResourceType;
if (exportedBundles.size() == 0) {
throw new InvalidAttributeException(MessageUtil.getMessage("NO_EXPORTED_BUNDLE", new Object[0]));
} else if (exportedBundles.size() == 1) {
exportedBundle = exportedBundles.get(0);
} else {
throw new InvalidAttributeException(MessageUtil.getMessage("TOO_MANY_EXPORTED_BUNDLES",
new Object[0]));
}
packageCapabilities = new HashSet<ExportedPackage>();
packageRequirements = new HashSet<ImportedPackage>();
serviceCapabilties = new HashSet<ExportedService>();
serviceRequirements = new HashSet<ImportedService>();
bundleRequirements = new HashSet<ImportedBundle>();
for (Requirement requirement : r.getRequirements())
{
String reqName = requirement.getName();
// Build ImportedPackageImpl, ImportedServiceImpl objects from the Resource's requirments.
// Parse the Requirement's filter and remove from the parsed Map all the entries
// that we will pass in as explicit parameters to the ImportedServiceImpl or ImportedPackageImpl
// constructor.
// (This does mean that we remove 'package=package.name' entries but not 'service=service' -
// the latter is not very useful :)
if (ResourceType.PACKAGE.toString().equals(reqName))
{
Map<String, String> filter = ManifestHeaderProcessor.parseFilter(requirement.getFilter());
// Grab and remove the package name, leaving only additional attributes.
String name = filter.remove(ResourceType.PACKAGE.toString());
if (requirement.isOptional()) {
filter.put(Constants.RESOLUTION_DIRECTIVE + ":", Constants.RESOLUTION_OPTIONAL);
}
ImportedPackage info = modellingManager.getImportedPackage(name, filter);
packageRequirements.add(info);
} else if (ResourceType.SERVICE.toString().equals(requirement.getName())) {
boolean optional = requirement.isOptional();
String iface;
String componentName;
String blueprintFilter;
String id = null;
boolean isMultiple = requirement.isMultiple();
/* It would be much better to pull these keys out of ImportedServiceImpl,
* or even values via static methods
*/
Map<String, String> attrs = ManifestHeaderProcessor.parseFilter(requirement.getFilter());
iface = attrs.get(Constants.OBJECTCLASS);
componentName = attrs.get ("osgi.service.blueprint.compname");
blueprintFilter = requirement.getFilter();
ImportedService svc = modellingManager.getImportedService(optional, iface, componentName,
blueprintFilter, id, isMultiple);
serviceRequirements.add(svc);
} else if (ResourceType.BUNDLE.toString().equals(requirement.getName())) {
String filter =requirement.getFilter();
Map<String,String> atts = ManifestHeaderProcessor.parseFilter(filter);
if (requirement.isOptional()) {
atts.put(Constants.RESOLUTION_DIRECTIVE + ":", Constants.RESOLUTION_OPTIONAL);
}
bundleRequirements.add(modellingManager.getImportedBundle(filter, atts));
}
}
for (Capability capability : r.getCapabilities())
{
Map<String, Object> props = new HashMap<String, Object>();
Property[] properties = capability.getProperties();
for (Property prop : properties) {
props.put(prop.getName(), prop.getValue());
}
if (ResourceType.PACKAGE.toString().equals(capability.getName()))
{
// Grab and remove the package name, leaving only additional attributes.
Object pkg = props.remove(ResourceType.PACKAGE.toString());
// bundle symbolic name and version will be in additionalProps, so do not
// need to be passed in separately.
ExportedPackage info = modellingManager.getExportedPackage(this, pkg.toString(), props);
packageCapabilities.add(info);
} else if (ResourceType.SERVICE.toString().equals(capability.getName())) {
String name = null; // we've lost this irretrievably
int ranking = 0;
Collection<String> ifaces;
String rankingText = (String) props.remove(Constants.SERVICE_RANKING);
if (rankingText != null) ranking = Integer.parseInt(rankingText);
// objectClass may come out as a String or String[]
Object rawObjectClass = props.remove (Constants.OBJECTCLASS);
if (rawObjectClass == null) {
// get it from service
ifaces = Arrays.asList((String)props.get(ModellingConstants.OBR_SERVICE));
} else {
if (rawObjectClass.getClass().isArray()) {
ifaces = Arrays.asList((String[])rawObjectClass);
} else {
ifaces = Arrays.asList((String)rawObjectClass);
}
}
ExportedService svc = modellingManager.getExportedService(name, ranking, ifaces, props);
serviceCapabilties.add(svc);
}
}
logger.debug(LOG_EXIT, "ModelledBundleResource");
}
public ExportedBundle getExportedBundle() {
logger.debug(LOG_ENTRY, "AbstractExportedBundle");
logger.debug(LOG_EXIT, "AbstractExportedBundle",exportedBundle );
return exportedBundle;
}
public Collection<? extends ExportedPackage> getExportedPackages() {
logger.debug(LOG_ENTRY, "getExportedPackages");
logger.debug(LOG_EXIT, "getExportedPackages", packageCapabilities );
return Collections.unmodifiableCollection(packageCapabilities);
}
public Collection<? extends ExportedService> getExportedServices() {
logger.debug(LOG_ENTRY, "getExportedServices");
logger.debug(LOG_EXIT, "getExportedServices", serviceCapabilties );
return Collections.unmodifiableCollection(serviceCapabilties);
}
public Collection<? extends ImportedPackage> getImportedPackages() {
logger.debug(LOG_ENTRY, "getImportedPackages");
logger.debug(LOG_EXIT, "getImportedPackages", packageRequirements );
return Collections.unmodifiableCollection(packageRequirements);
}
public Collection<? extends ImportedService> getImportedServices() {
logger.debug(LOG_ENTRY, "getImportedServices");
logger.debug(LOG_EXIT, "getImportedServices", serviceRequirements );
return Collections.unmodifiableCollection(serviceRequirements);
}
public Collection<? extends ImportedBundle> getRequiredBundles() {
logger.debug(LOG_ENTRY, "getRequiredBundles");
logger.debug(LOG_EXIT, "getRequiredBundles", bundleRequirements );
return Collections.unmodifiableCollection(bundleRequirements);
}
public String getSymbolicName() {
logger.debug(LOG_ENTRY, "getSymbolicName");
String result = resource.getSymbolicName();
logger.debug(LOG_EXIT, "getSymbolicName", result );
return result;
}
public String getLocation() {
logger.debug(LOG_ENTRY, "getLocation");
logger.debug(LOG_EXIT, "getLocation", resource.getURI());
return resource.getURI();
}
public String getVersion() {
logger.debug(LOG_ENTRY, "getVersion");
String result = resource.getVersion().toString();
logger.debug(LOG_EXIT, "getVersion", result);
return result;
}
public String toDeploymentString() {
logger.debug(LOG_ENTRY, "toDeploymentString");
String result = getSymbolicName() + ";" + AppConstants.DEPLOYMENT_BUNDLE_VERSION + "=" + getVersion();
logger.debug(LOG_EXIT, "toDeploymentString", result);
return result;
}
public String toString() {
logger.debug(LOG_ENTRY, "toString");
String result = toDeploymentString() + " uri=" + getLocation();
logger.debug(LOG_EXIT, "toString", result);
return result;
}
public ResourceType getType() {
logger.debug(LOG_ENTRY, "getType");
logger.debug(LOG_EXIT, "getType", type);
return type;
}
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;
}
}