blob: dca145cd34d9c72737f8269bbf032b745737e2dc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.internal.composite;
import java.util.*;
import org.eclipse.osgi.service.resolver.*;
import org.osgi.framework.*;
class CompositeInfo {
private final CompositeInfo parent;
private final List<CompositeInfo> children = Collections.synchronizedList(new ArrayList<CompositeInfo>(0));
private final long id;
private String name;
private Version version;
private ClassSpacePolicyInfo[] importPackagePolicy;
private ClassSpacePolicyInfo[] exportPackagePolicy;
private ClassSpacePolicyInfo[] requireBundlePolicy;
private ClassSpacePolicyInfo[] provideBundlePolicy;
private ServicePolicyInfo[] importServicePolicy;
private ServicePolicyInfo[] exportServicePolicy;
CompositeInfo(long id, String name, Version version, CompositeInfo parent, ClassSpacePolicyInfo[] importPackagePolicy, ClassSpacePolicyInfo[] exportPackagePolicy, ClassSpacePolicyInfo[] requireBundlePolicy, ClassSpacePolicyInfo[] provideBundlePolicy, ServicePolicyInfo[] importServicePolicy, ServicePolicyInfo[] exportServicePolicy) {
this.id = id;
this.name = name == null ? "" : name; //$NON-NLS-1$
this.version = version == null ? Version.emptyVersion : version;
this.parent = parent;
this.importPackagePolicy = importPackagePolicy;
this.exportPackagePolicy = exportPackagePolicy;
this.requireBundlePolicy = requireBundlePolicy;
this.provideBundlePolicy = provideBundlePolicy;
this.importServicePolicy = importServicePolicy;
this.exportServicePolicy = exportServicePolicy;
}
synchronized void update(CompositeInfo updatedInfo) {
this.name = updatedInfo.name;
this.version = updatedInfo.version;
this.importPackagePolicy = updatedInfo.importPackagePolicy;
this.exportPackagePolicy = updatedInfo.exportPackagePolicy;
this.requireBundlePolicy = updatedInfo.requireBundlePolicy;
this.provideBundlePolicy = updatedInfo.provideBundlePolicy;
this.importServicePolicy = updatedInfo.importServicePolicy;
this.exportServicePolicy = updatedInfo.exportServicePolicy;
}
boolean isVisible(Object provider, CompositeInfo origin, CompositeInfo providerComposite) {
return isVisible0(provider, origin, null, providerComposite);
}
boolean isVisible0(Object provider, CompositeInfo origin, PolicyInfo<?, ?> peerPolicy, CompositeInfo providerComposite) {
// first check if the the import policy allows the parent to provide
// we only allow for parent delegation if the peer policy does not have affinity
if (origin != parent && (peerPolicy == null || !peerPolicy.hasPeerConstraint())) {
// this request did not come from the parent
PolicyInfo<?, ?> matchedPolicy = matchImportPolicy(provider);
if (matchedPolicy != null) {
// Found a match policy that allows the provider to be imported; we have not checked the peer constraints yet
if (providerComposite == parent && !matchedPolicy.hasPeerConstraint())
// the parent actually provides this; a parent can only provide that if there is no peer constraint
return true;
// check if the provider is visible from the parent policy perspective;
if (parent.isVisible0(provider, this, matchedPolicy, providerComposite))
return true;
}
}
// not able to import from parent; check the children now
// get a snap shot of the children
CompositeInfo[] currentChildren = children.toArray(new CompositeInfo[children.size()]);
for (int i = 0; i < currentChildren.length; i++) {
if (origin != currentChildren[i]) {
// this request did not come from the child
if (currentChildren[i].matchExportPolicy(provider, peerPolicy) != null) {
// the child policy allows the provider to be exported from the child.
if (providerComposite == currentChildren[i])
// the child actually provides this
return true;
if (currentChildren[i].isVisible0(provider, this, null, providerComposite))
return true;
}
}
}
// cannot import from parent or children
return false;
}
synchronized boolean hasBundlePolicyEquivalent(BundleDescription singleton) {
if (requireBundlePolicy != null) {
for (ClassSpacePolicyInfo policy : requireBundlePolicy)
if (policy.matchName(singleton))
return true;
}
if (provideBundlePolicy != null) {
for (ClassSpacePolicyInfo policy : provideBundlePolicy)
if (policy.matchName(singleton))
return true;
}
return false;
}
private synchronized PolicyInfo<?, ?> matchImportPolicy(Object provider) {
if (provider instanceof ServiceReference<?>)
return matchFilters((ServiceReference<?>) provider, importServicePolicy, this, null);
if (provider instanceof ExportPackageDescription)
return matchConstraints((BaseDescription) provider, importPackagePolicy, this, null);
if (provider instanceof BundleDescription)
return matchConstraints((BaseDescription) provider, requireBundlePolicy, this, null);
return null;
}
private synchronized PolicyInfo<?, ?> matchExportPolicy(Object provider, PolicyInfo<?, ?> peerPolicy) {
if (provider instanceof ServiceReference<?>)
return matchFilters((ServiceReference<?>) provider, exportServicePolicy, this, (ServicePolicyInfo) peerPolicy);
if (provider instanceof ExportPackageDescription)
return matchConstraints((BaseDescription) provider, exportPackagePolicy, this, (ClassSpacePolicyInfo) peerPolicy);
if (provider instanceof BundleDescription)
return matchConstraints((BaseDescription) provider, provideBundlePolicy, this, (ClassSpacePolicyInfo) peerPolicy);
return null;
}
private static ServicePolicyInfo matchFilters(ServiceReference<?> provider, ServicePolicyInfo[] servicePolicy, CompositeInfo providerComposite, ServicePolicyInfo peerPolicy) {
if (servicePolicy == null)
return null;
for (ServicePolicyInfo policy : servicePolicy)
if (policy.match(provider, providerComposite, peerPolicy))
return policy;
return null;
}
private static ClassSpacePolicyInfo matchConstraints(BaseDescription provider, ClassSpacePolicyInfo[] constraints, CompositeInfo providerComposite, ClassSpacePolicyInfo peerPolicy) {
if (constraints == null)
return null;
for (ClassSpacePolicyInfo policy : constraints)
if (policy.match(provider, providerComposite, peerPolicy))
return policy;
return null;
}
void addChild(CompositeInfo child) {
children.add(child);
}
private void removeChild(CompositeInfo child) {
children.remove(child);
}
void orphaned() {
parent.removeChild(this);
}
boolean noChildren() {
return children.isEmpty();
}
long getId() {
return id;
}
String getName() {
return name;
}
Version getVersion() {
return version;
}
static abstract class PolicyInfo<C, P> {
protected final String peerCompositeName;
protected final VersionRange peerCompositeRange;
protected final C spec;
public PolicyInfo(String peerCompositeName, VersionRange peerCompositeRange, C spec) {
this.peerCompositeName = peerCompositeName;
this.peerCompositeRange = peerCompositeRange;
this.spec = spec;
}
public final boolean match(P provider, CompositeInfo providerComposite, PolicyInfo<C, P> peerPolicy) {
if (peerPolicy != null && !peerPolicy.matchPeerConstraint(providerComposite))
return false;
return matchProvider(provider);
}
boolean hasPeerConstraint() {
return peerCompositeName != null || peerCompositeRange != null;
}
private boolean matchPeerConstraint(CompositeInfo providerComposite) {
if (peerCompositeName != null && !peerCompositeName.equals(providerComposite.getName()))
return false;
if (peerCompositeRange != null && !peerCompositeRange.isIncluded(providerComposite.getVersion()))
return false;
return true;
}
protected abstract boolean matchProvider(P provider);
}
static class ClassSpacePolicyInfo extends PolicyInfo<VersionConstraint, BaseDescription> {
public ClassSpacePolicyInfo(String peerCompositeName, VersionRange peerCompositeRange, VersionConstraint spec) {
super(peerCompositeName, peerCompositeRange, spec);
}
public boolean matchName(BundleDescription singleton) {
return spec.getName().equals(singleton.getName());
}
protected boolean matchProvider(BaseDescription provider) {
return spec.isSatisfiedBy(provider);
}
}
static class ServicePolicyInfo extends PolicyInfo<Filter, ServiceReference<?>> {
public ServicePolicyInfo(String peerCompositeName, VersionRange peerCompositeRange, Filter spec) {
super(peerCompositeName, peerCompositeRange, spec);
}
protected boolean matchProvider(ServiceReference<?> provider) {
return spec.match(provider);
}
}
synchronized CompositeInfo getChildCompositeInfo(long compositeId) {
if (compositeId < getId() || noChildren())
return null; // We assume that nested child composites will always have a higher id
// get a snap shot of the children
CompositeInfo[] currentChildren = children.toArray(new CompositeInfo[children.size()]);
for (CompositeInfo childInfo : currentChildren) {
if (childInfo.getId() == compositeId)
return childInfo;
CompositeInfo result = childInfo.getChildCompositeInfo(compositeId);
if (result != null)
return result;
}
return null;
}
}