
aQute.bnd.osgi.resource.ResourceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of biz.aQute.bndlib Show documentation
Show all versions of biz.aQute.bndlib Show documentation
bndlib: A Swiss Army Knife for OSGi
The newest version!
package aQute.bnd.osgi.resource;
import static aQute.lib.collections.Logic.retain;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.osgi.framework.namespace.BundleNamespace;
import org.osgi.framework.namespace.HostNamespace;
import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.framework.namespace.PackageNamespace;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
import org.osgi.service.repository.RepositoryContent;
import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.resource.ResourceUtils.ContentCapability;
import aQute.bnd.service.resource.SupportingResource;
import aQute.bnd.unmodifiable.Lists;
class ResourceImpl implements Resource, SupportingResource, Comparable, RepositoryContent {
boolean built = false;
List allCapabilities;
Map> capabilityMap;
List allRequirements;
Map> requirementMap;
List supportingResources;
Map locations;
int hashCode = -1;
final SupportingResource parent;
ResourceImpl(SupportingResource parent) {
this.parent = parent;
}
@SuppressWarnings({
"rawtypes", "unchecked"
})
@Override
public List getCapabilities(String namespace) {
assert built;
if (namespace == null)
return (List) allCapabilities;
return (List) capabilityMap.getOrDefault(namespace, Collections.emptyList());
}
@SuppressWarnings({
"rawtypes", "unchecked"
})
@Override
public List getRequirements(String namespace) {
assert built;
if (namespace == null)
return (List) allRequirements;
return (List) requirementMap.getOrDefault(namespace, Collections.emptyList());
}
@Override
public String toString() {
if (!built) {
return "Resource[not built yet]";
}
List identities = getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE);
if (identities.size() == 1) {
Map attributes = identities.get(0)
.getAttributes();
String id = String.valueOf(attributes.get(IdentityNamespace.IDENTITY_NAMESPACE));
return switch (id) {
case Constants.IDENTITY_INITIAL_RESOURCE, Constants.IDENTITY_SYSTEM_RESOURCE -> id;
default -> {
StringBuilder builder = new StringBuilder(id);
Object version = attributes.get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
if (version != null) {
builder.append(" version=")
.append(version);
}
Object type = attributes.getOrDefault(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE,
IdentityNamespace.TYPE_UNKNOWN);
if (!IdentityNamespace.TYPE_BUNDLE.equals(type)) {
builder.append(" type=")
.append(type);
}
yield builder.toString();
}
};
}
// Generic toString
return new StringBuilder("ResourceImpl [caps=").append(allCapabilities)
.append(", reqs=")
.append(allRequirements)
.append(']')
.toString();
}
@Override
public int compareTo(Resource o) {
return ResourceUtils.compareTo(this, o);
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (other instanceof Resource resource) {
Map otherLocations = (resource instanceof ResourceImpl resourceImpl) ? resourceImpl.locations
: ResourceUtils.getLocations(resource);
Collection overlap = retain(locations.keySet(), otherLocations.keySet());
return overlap.stream()
.anyMatch(uri -> {
String thisSha = locations.get(uri);
String otherSha = otherLocations.get(uri);
return Objects.equals(thisSha, otherSha);
});
}
return false;
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public InputStream getContent() {
assert built;
try {
ContentCapability c = ResourceUtils.getContentCapability(this);
URI url = c.url();
return url.toURL()
.openStream();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public List getSupportingResources() {
assert built;
return supportingResources;
}
SupportingResource build(Map> capabilities,
Map> requirements, List support, SupportingResource parent) {
assert !this.built;
this.built = true;
this.allCapabilities = Collections.unmodifiableList(flatten(capabilities));
this.allRequirements = Collections.unmodifiableList(flatten(requirements));
this.supportingResources = Collections.unmodifiableList(new ArrayList<>(support));
this.capabilityMap = allCapabilities.stream()
.collect(groupingBy(Capability::getNamespace, Lists.toList()));
this.requirementMap = allRequirements.stream()
.collect(groupingBy(Requirement::getNamespace, Lists.toList()));
this.locations = ResourceUtils.getLocations(this);
this.hashCode = this.locations.keySet()
.stream()
.map(URI::toString)
.sorted()
.map(String::hashCode)
.reduce(0, (prev, next) -> prev * 31 + next);
return this;
}
static List flatten(Map> capabilities) {
return capabilities.values()
.stream()
.flatMap(List::stream)
.distinct()
.sorted(ResourceImpl::compare)
.collect(toList());
}
/**
* We order the wiring namespaces ahead of the other namespaces. This makes
* the resolver happier in some tests which otherwise fail when using simple
* namespace ordering.
*/
static int compare(T left, T right) {
return map(left).compareTo(map(right));
}
static String map(CapReq capreq) {
return switch (capreq.getNamespace()) {
case IdentityNamespace.IDENTITY_NAMESPACE -> " 1";
case PackageNamespace.PACKAGE_NAMESPACE -> " 2";
case BundleNamespace.BUNDLE_NAMESPACE -> " 3";
case HostNamespace.HOST_NAMESPACE -> " 4";
default -> capreq.getNamespace();
};
}
@Override
public Optional getParent() {
return Optional.ofNullable(parent);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy