diff options
author | Thomas Watson | 2012-08-30 15:47:25 +0000 |
---|---|---|
committer | Thomas Watson | 2012-10-02 18:54:42 +0000 |
commit | 2f49cd7039cbda2ec95446c7c202a24a47100221 (patch) | |
tree | 786a3e44ca92e349f3b516d262c605627e57746a /bundles/org.eclipse.osgi.compatibility.state | |
parent | f98dd6b7b33f9762c389b0cb35f9d4023273fb54 (diff) | |
download | rt.equinox.framework-2f49cd7039cbda2ec95446c7c202a24a47100221.tar.gz rt.equinox.framework-2f49cd7039cbda2ec95446c7c202a24a47100221.tar.xz rt.equinox.framework-2f49cd7039cbda2ec95446c7c202a24a47100221.zip |
Initial work on the PlatformAdmin implementation
Diffstat (limited to 'bundles/org.eclipse.osgi.compatibility.state')
-rw-r--r-- | bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/FilterParser.java | 416 | ||||
-rw-r--r-- | bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java | 71 | ||||
-rw-r--r-- | bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/ReadOnlyState.java (renamed from bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/internal/resolver/ReadOnlyState.java) | 51 | ||||
-rw-r--r-- | bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/ReadOnlySystemState.java | 317 | ||||
-rw-r--r-- | bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java | 197 |
5 files changed, 696 insertions, 356 deletions
diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/FilterParser.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/FilterParser.java new file mode 100644 index 000000000..8a9251d05 --- /dev/null +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/FilterParser.java @@ -0,0 +1,416 @@ +/******************************************************************************* + * Copyright (c) 2012 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 - Initial API and implementation + ******************************************************************************/ +package org.eclipse.osgi.compatibility.state; + +import java.util.*; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.Version; + +public class FilterParser { + static class Range { + private char leftRule = 0; + private Version leftVersion; + private Version rightVersion; + private char rightRule = 0; + private Collection<Version> excludes = new ArrayList<Version>(0); + + public String toString() { + if (rightVersion == null) { + return leftVersion.toString(); + } + return leftRule + leftVersion.toString() + ',' + rightVersion.toString() + rightRule; + } + + void addExclude(Version exclude) { + this.excludes.add(exclude); + setLeft(leftRule, leftVersion); + setRight(rightRule, rightVersion); + } + + boolean setLeft(char leftRule, Version leftVersion) { + if (this.leftVersion != null && this.leftVersion != leftVersion) + return false; + this.leftRule = excludes.contains(leftVersion) ? '(' : leftRule; + this.leftVersion = leftVersion; + return true; + } + + boolean setRight(char rightRule, Version rightVersion) { + if (this.rightVersion != null && this.rightVersion != rightVersion) + return false; + this.rightRule = excludes.contains(rightVersion) ? ')' : rightRule; + this.rightVersion = rightVersion; + return true; + } + } + + public static class FilterComponent { + /* filter operators */ + public static final int EQUAL = 1; + public static final int APPROX = 2; + public static final int GREATER = 3; + public static final int LESS = 4; + public static final int AND = 7; + public static final int OR = 8; + public static final int NOT = 9; + + private final int op; + private final String attr; + private final String value; + private final List<FilterComponent> nested; + + public FilterComponent(int op, List<FilterComponent> nested) { + this.op = op; + this.attr = null; + this.value = null; + this.nested = nested; + } + + public FilterComponent(int op, String attr, String value) { + this.op = op; + this.attr = attr; + this.value = value; + this.nested = Collections.emptyList(); + } + + public int getOp() { + return op; + } + + public String getAttr() { + return attr; + } + + public String getValue() { + return value; + } + + public List<FilterComponent> getNested() { + return nested; + } + + public Map<String, String> getStandardOSGiAttributes(String... versions) { + if (op != AND && op != EQUAL) + throw new IllegalStateException("Invalid filter for Starndard OSGi Attributes: " + op); //$NON-NLS-1$ + Map<String, String> result = new HashMap<String, String>(); + Map<String, Range> versionAttrs = new HashMap<String, Range>(); + if (versions != null) { + for (String versionAttr : versions) { + versionAttrs.put(versionAttr, null); + } + } + addAttributes(result, versionAttrs, false); + for (Map.Entry<String, Range> entry : versionAttrs.entrySet()) { + Range range = entry.getValue(); + if (range != null) { + result.put(entry.getKey(), range.toString()); + } + } + + return result; + } + + private void addAttributes(Map<String, String> attributes, Map<String, Range> versionAttrs, boolean not) { + if (op == EQUAL) { + if (!versionAttrs.containsKey(attr)) { + attributes.put(attr, value); + } else { + // this is an exact range e.g. [value,value] + Range currentRange = versionAttrs.get(attr); + if (currentRange != null) { + if (not) { + // this is an expanded for of the filter, e.g.: + // [1.0,2.0) -> (&(version>=1.0)(version<=2.0)(!(version=2.0))) + currentRange.addExclude(new Version(value)); + } else { + throw new IllegalStateException("Invalid range for: " + attr); //$NON-NLS-1$ + } + } + currentRange = new Range(); + Version version = new Version(value); + currentRange.setLeft('[', version); + currentRange.setRight(']', version); + versionAttrs.put(attr, currentRange); + } + } else if (op == LESS) { + if (!versionAttrs.containsKey(attr)) + throw new IllegalStateException("Invalid attribute: " + attr); //$NON-NLS-1$ + Range currentRange = versionAttrs.get(attr); + if (currentRange == null) { + currentRange = new Range(); + versionAttrs.put(attr, currentRange); + } + if (not) { + // this must be a range start "(value" + if (!currentRange.setLeft('(', new Version(value))) + throw new IllegalStateException("range start is already processed for attribute: " + attr); //$NON-NLS-1$ + } else { + // this must be a range end "value]" + if (!currentRange.setRight(']', new Version(value))) + throw new IllegalStateException("range end is already processed for attribute: " + attr); //$NON-NLS-1$ + } + } else if (op == GREATER) { + if (!versionAttrs.containsKey(attr)) + throw new IllegalStateException("Invalid attribute: " + attr); //$NON-NLS-1$ + Range currentRange = versionAttrs.get(attr); + if (currentRange == null) { + currentRange = new Range(); + versionAttrs.put(attr, currentRange); + } + if (not) { + // this must be a range end "value)" + if (!currentRange.setRight(')', new Version(value))) + throw new IllegalStateException("range end is already processed for attribute: " + attr); //$NON-NLS-1$ + } else { + // this must be a range start "[value" + if (!currentRange.setLeft('[', new Version(value))) + throw new IllegalStateException("range start is already processed for attribute: " + attr); //$NON-NLS-1$ + } + } else if (op == AND) { + for (FilterComponent component : nested) { + component.addAttributes(attributes, versionAttrs, false); + } + } else if (op == NOT) { + nested.get(0).addAttributes(attributes, versionAttrs, true); + } else { + throw new IllegalStateException("Invalid filter for standard OSGi requirements: " + op); //$NON-NLS-1$ + } + } + } + + private final String filterstring; + private final char[] filterChars; + private int pos; + + public FilterParser(String filterstring) { + this.filterstring = filterstring; + filterChars = filterstring.toCharArray(); + pos = 0; + } + + public FilterComponent parse() throws InvalidSyntaxException { + FilterComponent filter; + try { + filter = parse_filter(); + } catch (ArrayIndexOutOfBoundsException e) { + throw new InvalidSyntaxException("Filter ended abruptly", filterstring, e); //$NON-NLS-1$ + } + + if (pos != filterChars.length) { + throw new InvalidSyntaxException("Extraneous trailing characters: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ + } + return filter; + } + + private FilterComponent parse_filter() throws InvalidSyntaxException { + FilterComponent filter; + skipWhiteSpace(); + + if (filterChars[pos] != '(') { + throw new InvalidSyntaxException("Missing '(': " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ + } + + pos++; + + filter = parse_filtercomp(); + + skipWhiteSpace(); + + if (filterChars[pos] != ')') { + throw new InvalidSyntaxException("Missing ')': " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ + } + + pos++; + + skipWhiteSpace(); + + return filter; + } + + private FilterComponent parse_filtercomp() throws InvalidSyntaxException { + skipWhiteSpace(); + + char c = filterChars[pos]; + + switch (c) { + case '&' : { + pos++; + return parse_and(); + } + case '|' : { + pos++; + return parse_or(); + } + case '!' : { + pos++; + return parse_not(); + } + } + return parse_item(); + } + + private FilterComponent parse_and() throws InvalidSyntaxException { + int lookahead = pos; + skipWhiteSpace(); + + if (filterChars[pos] != '(') { + pos = lookahead - 1; + return parse_item(); + } + + List<FilterComponent> operands = new ArrayList<FilterComponent>(10); + + while (filterChars[pos] == '(') { + FilterComponent child = parse_filter(); + operands.add(child); + } + + return new FilterComponent(FilterComponent.AND, operands); + } + + private FilterComponent parse_or() throws InvalidSyntaxException { + int lookahead = pos; + skipWhiteSpace(); + + if (filterChars[pos] != '(') { + pos = lookahead - 1; + return parse_item(); + } + + List<FilterComponent> operands = new ArrayList<FilterComponent>(10); + + while (filterChars[pos] == '(') { + FilterComponent child = parse_filter(); + operands.add(child); + } + + return new FilterComponent(FilterComponent.OR, operands); + } + + private FilterComponent parse_not() throws InvalidSyntaxException { + int lookahead = pos; + skipWhiteSpace(); + + if (filterChars[pos] != '(') { + pos = lookahead - 1; + return parse_item(); + } + + List<FilterComponent> operands = new ArrayList<FilterComponent>(1); + FilterComponent child = parse_filter(); + operands.add(child); + + return new FilterComponent(FilterComponent.NOT, operands); + } + + private FilterComponent parse_item() throws InvalidSyntaxException { + String attr = parse_attr(); + + skipWhiteSpace(); + + switch (filterChars[pos]) { + case '~' : { + if (filterChars[pos + 1] == '=') { + pos += 2; + return new FilterComponent(FilterComponent.APPROX, attr, parse_value()); + } + break; + } + case '>' : { + if (filterChars[pos + 1] == '=') { + pos += 2; + return new FilterComponent(FilterComponent.GREATER, attr, parse_value()); + } + break; + } + case '<' : { + if (filterChars[pos + 1] == '=') { + pos += 2; + return new FilterComponent(FilterComponent.LESS, attr, parse_value()); + } + break; + } + case '=' : { + pos++; + return new FilterComponent(FilterComponent.EQUAL, attr, parse_value()); + } + } + + throw new InvalidSyntaxException("Invalid operator: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ + } + + private String parse_attr() throws InvalidSyntaxException { + skipWhiteSpace(); + + int begin = pos; + int end = pos; + + char c = filterChars[pos]; + + while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') { + pos++; + + if (!Character.isWhitespace(c)) { + end = pos; + } + + c = filterChars[pos]; + } + + int length = end - begin; + + if (length == 0) { + throw new InvalidSyntaxException("Missing attr: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ + } + + return new String(filterChars, begin, length); + } + + private String parse_value() throws InvalidSyntaxException { + StringBuffer sb = new StringBuffer(filterChars.length - pos); + + parseloop: while (true) { + char c = filterChars[pos]; + + switch (c) { + case ')' : { + break parseloop; + } + + case '(' : { + throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ + } + + case '\\' : { + pos++; + c = filterChars[pos]; + /* fall through into default */ + } + + default : { + sb.append(c); + pos++; + break; + } + } + } + + if (sb.length() == 0) { + throw new InvalidSyntaxException("Missing value: " + filterstring.substring(pos), filterstring); //$NON-NLS-1$ + } + + return sb.toString(); + } + + private void skipWhiteSpace() { + for (int length = filterChars.length; (pos < length) && Character.isWhitespace(filterChars[pos]);) { + pos++; + } + } +} diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java index 735ee2ccf..25c5c88b5 100644 --- a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/PlatformAdminImpl.java @@ -9,27 +9,30 @@ ******************************************************************************/ package org.eclipse.osgi.compatibility.state; -import org.eclipse.osgi.container.ModuleContainer; -import org.eclipse.osgi.container.ModuleDatabase; +import java.util.*; +import org.eclipse.osgi.container.*; import org.eclipse.osgi.internal.framework.BundleContextImpl; +import org.eclipse.osgi.internal.framework.EquinoxContainer; import org.eclipse.osgi.internal.module.ResolverImpl; import org.eclipse.osgi.internal.resolver.StateHelperImpl; import org.eclipse.osgi.internal.resolver.StateObjectFactoryImpl; import org.eclipse.osgi.service.resolver.*; -import org.eclipse.osgi.storage.Storage; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; public class PlatformAdminImpl implements PlatformAdmin { private final StateHelper stateHelper = new StateHelperImpl(); private final StateObjectFactory factory = new StateObjectFactoryImpl(); - private volatile ModuleContainer container; - private volatile ModuleDatabase database; + private final Object monitor = new Object(); + private EquinoxContainer equinoxContainer; + private State systemState; + @SuppressWarnings("unused") + // this is used by DS to activate us private void activate(BundleContext context) { - Storage storage = ((BundleContextImpl) context).getContainer().getStorage(); - this.container = storage.getModuleContainer(); - this.database = storage.getModuleDatabase(); + synchronized (this.monitor) { + equinoxContainer = ((BundleContextImpl) context).getContainer(); + } context.registerService(PlatformAdmin.class, this, null); } @@ -41,26 +44,66 @@ public class PlatformAdminImpl implements PlatformAdmin { @Override public State getState(boolean mutable) { if (mutable) { - return stateCopy(); + return factory.createState(getSystemState()); } - return new ReadOnlySystemState(container, database); + return new ReadOnlyState(this); } - private State stateCopy() { - // TODO - throw new UnsupportedOperationException(); + State getSystemState() { + synchronized (this.monitor) { + if (systemState == null) { + systemState = createSystemState(); + } + return systemState; + } + } + + long getTimeStamp() { + synchronized (this.monitor) { + return equinoxContainer.getStorage().getModuleDatabase().getTimestamp(); + } + } + + private State createSystemState() { + State state = factory.createState(true); + StateConverter converter = new StateConverter(state); + ModuleDatabase database = equinoxContainer.getStorage().getModuleDatabase(); + database.lockRead(); + try { + List<Module> modules = equinoxContainer.getStorage().getModuleContainer().getModules(); + for (Module module : modules) { + ModuleRevision current = module.getCurrentRevision(); + BundleDescription description = converter.createDescription(current); + state.addBundle(description); + state.setPlatformProperties(asDictionary(equinoxContainer.getConfiguration().asMap())); + } + state.setTimeStamp(database.getTimestamp()); + // TODO add hooks to get the resolution correct + // TODO add listeners to keep state copy in sync + } finally { + database.unlockRead(); + } + return state; + } + + private Dictionary<String, String> asDictionary(Map<String, String> map) { + return new Hashtable<String, String>(map); } @Override public StateHelper getStateHelper() { - return stateHelper; + return StateHelperImpl.getInstance(); } + /** + * @throws BundleException + */ @Override public void commit(State state) throws BundleException { throw new UnsupportedOperationException(); } + @Deprecated @Override public Resolver getResolver() { return createResolver(); diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/internal/resolver/ReadOnlyState.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/ReadOnlyState.java index d0bc359ae..be8a87637 100644 --- a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/internal/resolver/ReadOnlyState.java +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/ReadOnlyState.java @@ -10,19 +10,20 @@ * Danail Nachev - ProSyst - bug 218625 * Rob Harrop - SpringSource Inc. (bug 247522) *******************************************************************************/ -package org.eclipse.osgi.internal.resolver; +package org.eclipse.osgi.compatibility.state; import java.util.*; +import org.eclipse.osgi.internal.resolver.StateHelperImpl; import org.eclipse.osgi.service.resolver.*; import org.osgi.framework.BundleException; import org.osgi.framework.Version; import org.osgi.framework.hooks.resolver.ResolverHookFactory; public final class ReadOnlyState implements State { - private final State target; + private final PlatformAdminImpl platformAdmin; - public ReadOnlyState(State target) { - this.target = target; + public ReadOnlyState(PlatformAdminImpl platformAdmin) { + this.platformAdmin = platformAdmin; } public boolean addBundle(BundleDescription description) { @@ -30,55 +31,55 @@ public final class ReadOnlyState implements State { } public StateDelta compare(State state) throws BundleException { - return target.compare(state); + return platformAdmin.getSystemState().compare(state); } public BundleDescription getBundle(long id) { - return target.getBundle(id); + return platformAdmin.getSystemState().getBundle(id); } public BundleDescription getBundle(String symbolicName, Version version) { - return target.getBundle(symbolicName, version); + return platformAdmin.getSystemState().getBundle(symbolicName, version); } public BundleDescription getBundleByLocation(String location) { - return target.getBundleByLocation(location); + return platformAdmin.getSystemState().getBundleByLocation(location); } public BundleDescription[] getBundles() { - return target.getBundles(); + return platformAdmin.getSystemState().getBundles(); } public BundleDescription[] getBundles(String symbolicName) { - return target.getBundles(symbolicName); + return platformAdmin.getSystemState().getBundles(symbolicName); } public StateDelta getChanges() { - return target.getChanges(); + return platformAdmin.getSystemState().getChanges(); } public ExportPackageDescription[] getExportedPackages() { - return target.getExportedPackages(); + return platformAdmin.getSystemState().getExportedPackages(); } public StateObjectFactory getFactory() { - return target.getFactory(); + return platformAdmin.getSystemState().getFactory(); } public BundleDescription[] getResolvedBundles() { - return target.getResolvedBundles(); + return platformAdmin.getSystemState().getResolvedBundles(); } public long getTimeStamp() { - return target.getTimeStamp(); + return platformAdmin.getTimeStamp(); } public boolean isEmpty() { - return target.isEmpty(); + return platformAdmin.getSystemState().isEmpty(); } public boolean isResolved() { - return target.isResolved(); + return platformAdmin.getSystemState().isResolved(); } public boolean removeBundle(BundleDescription bundle) { @@ -158,7 +159,7 @@ public final class ReadOnlyState implements State { @SuppressWarnings("rawtypes") public Dictionary[] getPlatformProperties() { - return target.getPlatformProperties(); + return platformAdmin.getSystemState().getPlatformProperties(); } public ExportPackageDescription linkDynamicImport(BundleDescription importingBundle, String requestedPackage) { @@ -170,7 +171,7 @@ public final class ReadOnlyState implements State { } public ExportPackageDescription[] getSystemPackages() { - return target.getSystemPackages(); + return platformAdmin.getSystemState().getSystemPackages(); } public void addResolverError(BundleDescription bundle, int type, String data, VersionConstraint unsatisfied) { @@ -178,7 +179,7 @@ public final class ReadOnlyState implements State { } public ResolverError[] getResolverErrors(BundleDescription bundle) { - return target.getResolverErrors(bundle); + return platformAdmin.getSystemState().getResolverErrors(bundle); } public void removeResolverErrors(BundleDescription bundle) { @@ -190,7 +191,7 @@ public final class ReadOnlyState implements State { } public long getHighestBundleId() { - return target.getHighestBundleId(); + return platformAdmin.getSystemState().getHighestBundleId(); } public void setNativePathsInvalid(NativeCodeDescription nativeCodeDescription, boolean hasInvalidPaths) { @@ -198,7 +199,7 @@ public final class ReadOnlyState implements State { } public BundleDescription[] getDisabledBundles() { - return target.getDisabledBundles(); + return platformAdmin.getSystemState().getDisabledBundles(); } public void addDisabledInfo(DisabledInfo disabledInfo) { @@ -206,11 +207,11 @@ public final class ReadOnlyState implements State { } public DisabledInfo[] getDisabledInfos(BundleDescription bundle) { - return target.getDisabledInfos(bundle); + return platformAdmin.getSystemState().getDisabledInfos(bundle); } public DisabledInfo getDisabledInfo(BundleDescription bundle, String policyName) { - return target.getDisabledInfo(bundle, policyName); + return platformAdmin.getSystemState().getDisabledInfo(bundle, policyName); } public void removeDisabledInfo(DisabledInfo disabledInfo) { @@ -222,7 +223,7 @@ public final class ReadOnlyState implements State { } public Collection<BundleDescription> getDependencyClosure(Collection<BundleDescription> bundles) { - return target.getDependencyClosure(bundles); + return platformAdmin.getSystemState().getDependencyClosure(bundles); } public void addDynamicImportPackages(BundleDescription importingBundle, ImportPackageSpecification[] dynamicImports) { diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/ReadOnlySystemState.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/ReadOnlySystemState.java deleted file mode 100644 index a2ff5a587..000000000 --- a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/ReadOnlySystemState.java +++ /dev/null @@ -1,317 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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.compatibility.state; - -import java.util.*; -import org.eclipse.osgi.container.ModuleContainer; -import org.eclipse.osgi.container.ModuleDatabase; -import org.eclipse.osgi.service.resolver.*; -import org.osgi.framework.BundleException; -import org.osgi.framework.Version; -import org.osgi.framework.hooks.resolver.ResolverHookFactory; - -public class ReadOnlySystemState implements State { - - private final ModuleContainer container; - private final ModuleDatabase database; - private final StateDelta delta = new StateDelta() { - @Override - public State getState() { - // TODO Auto-generated method stub - return ReadOnlySystemState.this; - } - - @Override - public ResolverHookException getResovlerHookException() { - return null; - } - - @Override - public BundleDelta[] getChanges(int mask, boolean exact) { - return new BundleDelta[0]; - } - - @Override - public BundleDelta[] getChanges() { - return new BundleDelta[0]; - } - }; - - public ReadOnlySystemState(ModuleContainer container, ModuleDatabase database) { - this.container = container; - this.database = database; - } - - @Override - public boolean addBundle(BundleDescription description) { - throw new UnsupportedOperationException(); - } - - @Override - public StateDelta compare(State baseState) throws BundleException { - return delta; - } - - @Override - public BundleDescription removeBundle(long bundleId) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeBundle(BundleDescription bundle) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean updateBundle(BundleDescription newDescription) { - throw new UnsupportedOperationException(); - } - - @Override - public StateDelta getChanges() { - return delta; - } - - @Override - public BundleDescription[] getBundles() { - // TODO Auto-generated method stub - return null; - } - - @Override - public BundleDescription getBundle(long id) { - // TODO Auto-generated method stub - return null; - } - - @Override - public BundleDescription getBundle(String symbolicName, Version version) { - // TODO Auto-generated method stub - return null; - } - - @Override - public BundleDescription getBundleByLocation(String location) { - // TODO Auto-generated method stub - return null; - } - - @Override - public long getTimeStamp() { - return database.getRevisionsTimestamp(); - } - - @Override - public void setTimeStamp(long newTimeStamp) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isResolved() { - return true; - } - - @Override - public void resolveConstraint(VersionConstraint constraint, BaseDescription supplier) { - throw new UnsupportedOperationException(); - } - - @Override - public void resolveBundle(BundleDescription bundle, boolean status, BundleDescription[] hosts, ExportPackageDescription[] selectedExports, BundleDescription[] resolvedRequires, ExportPackageDescription[] resolvedImports) { - throw new UnsupportedOperationException(); - } - - @Override - public void resolveBundle(BundleDescription bundle, boolean status, BundleDescription[] hosts, ExportPackageDescription[] selectedExports, ExportPackageDescription[] substitutedExports, BundleDescription[] resolvedRequires, ExportPackageDescription[] resolvedImports) { - throw new UnsupportedOperationException(); - } - - @Override - public void resolveBundle(BundleDescription bundle, boolean status, BundleDescription[] hosts, ExportPackageDescription[] selectedExports, ExportPackageDescription[] substitutedExports, GenericDescription[] selectedCapabilities, BundleDescription[] resolvedRequires, ExportPackageDescription[] resolvedImports, GenericDescription[] resolvedCapabilities, Map<String, List<StateWire>> resolvedWires) { - throw new UnsupportedOperationException(); - } - - @Override - public void removeBundleComplete(BundleDescription bundle) { - throw new UnsupportedOperationException(); - } - - @Override - public void addResolverError(BundleDescription bundle, int type, String data, VersionConstraint unsatisfied) { - throw new UnsupportedOperationException(); - } - - @Override - public void removeResolverErrors(BundleDescription bundle) { - throw new UnsupportedOperationException(); - } - - @Override - public ResolverError[] getResolverErrors(BundleDescription bundle) { - throw new UnsupportedOperationException(); - } - - @Override - public Resolver getResolver() { - return null; - } - - @Override - public void setResolver(Resolver value) { - throw new UnsupportedOperationException(); - } - - @Override - public StateDelta resolve(boolean incremental) { - throw new UnsupportedOperationException(); - } - - @Override - public StateDelta resolve() { - throw new UnsupportedOperationException(); - } - - @Override - public StateDelta resolve(BundleDescription[] discard) { - throw new UnsupportedOperationException(); - } - - @Override - public StateDelta resolve(BundleDescription[] resolve, boolean discard) { - throw new UnsupportedOperationException(); - } - - @Override - public void setOverrides(Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public BundleDescription[] getResolvedBundles() { - // TODO Auto-generated method stub - return null; - } - - @Override - public BundleDescription[] getRemovalPending() { - throw new UnsupportedOperationException(); - } - - @Override - public Collection<BundleDescription> getDependencyClosure(Collection<BundleDescription> bundles) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean isEmpty() { - // TODO Auto-generated method stub - return false; - } - - @Override - public ExportPackageDescription[] getExportedPackages() { - // TODO Auto-generated method stub - return null; - } - - @Override - public BundleDescription[] getBundles(String symbolicName) { - // TODO Auto-generated method stub - return null; - } - - @Override - public StateObjectFactory getFactory() { - // TODO Auto-generated method stub - return null; - } - - @Override - public ExportPackageDescription linkDynamicImport(BundleDescription importingBundle, String requestedPackage) { - throw new UnsupportedOperationException(); - } - - @Override - public void addDynamicImportPackages(BundleDescription importingBundle, ImportPackageSpecification[] dynamicImports) { - throw new UnsupportedOperationException(); - - } - - @Override - public boolean setPlatformProperties(Dictionary<?, ?> platformProperties) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean setPlatformProperties(Dictionary<?, ?>[] platformProperties) { - throw new UnsupportedOperationException(); - } - - @Override - public Dictionary[] getPlatformProperties() { - // TODO Auto-generated method stub - return null; - } - - @Override - public ExportPackageDescription[] getSystemPackages() { - // TODO Auto-generated method stub - return null; - } - - @Override - public StateHelper getStateHelper() { - // TODO Auto-generated method stub - return null; - } - - @Override - public long getHighestBundleId() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void setNativePathsInvalid(NativeCodeDescription nativeCodeDescription, boolean hasInvalidNativePaths) { - throw new UnsupportedOperationException(); - } - - @Override - public BundleDescription[] getDisabledBundles() { - throw new UnsupportedOperationException(); - } - - @Override - public void addDisabledInfo(DisabledInfo disabledInfo) { - throw new UnsupportedOperationException(); - } - - @Override - public void removeDisabledInfo(DisabledInfo disabledInfo) { - throw new UnsupportedOperationException(); - } - - @Override - public DisabledInfo[] getDisabledInfos(BundleDescription bundle) { - throw new UnsupportedOperationException(); - } - - @Override - public DisabledInfo getDisabledInfo(BundleDescription bundle, String policyName) { - throw new UnsupportedOperationException(); - } - - @Override - public void setResolverHookFactory(ResolverHookFactory hookFactory) { - throw new UnsupportedOperationException(); - } - -} diff --git a/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java new file mode 100644 index 000000000..7c6754e7d --- /dev/null +++ b/bundles/org.eclipse.osgi.compatibility.state/src/org/eclipse/osgi/compatibility/state/StateConverter.java @@ -0,0 +1,197 @@ +package org.eclipse.osgi.compatibility.state; + +import java.util.*; +import java.util.Map.Entry; +import org.eclipse.osgi.compatibility.state.FilterParser.FilterComponent; +import org.eclipse.osgi.service.resolver.*; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.Version; +import org.osgi.framework.namespace.*; +import org.osgi.framework.wiring.BundleRevision; +import org.osgi.resource.*; + +class StateConverter { + private final State state; + + StateConverter(State state) { + this.state = state; + } + + BundleDescription createDescription(BundleRevision resource) { + + Collection<Capability> idList = resource.getCapabilities(IdentityNamespace.IDENTITY_NAMESPACE); + if (idList.size() != 1) + throw new IllegalArgumentException("Bogus osgi.identity: " + idList); //$NON-NLS-1$ + Capability id = idList.iterator().next(); + + Map<String, Object> idAttrs = new HashMap<String, Object>(id.getAttributes()); + + String symbolicName = (String) idAttrs.remove(IdentityNamespace.IDENTITY_NAMESPACE); + Version version = (Version) idAttrs.remove(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE); + + String symbolicNameSpecification = symbolicName + toString(idAttrs, "=", true) + toString(id.getDirectives(), ":=", true); //$NON-NLS-1$ //$NON-NLS-2$ + + List<ExportPackageDescription> exportPackages = new ArrayList<ExportPackageDescription>(); + List<GenericDescription> provideCapabilities = new ArrayList<GenericDescription>(); + List<ImportPackageSpecification> importPackages = new ArrayList<ImportPackageSpecification>(); + List<GenericSpecification> requireCapabilities = new ArrayList<GenericSpecification>(); + List<HostSpecification> fragmentHost = new ArrayList<HostSpecification>(0); + List<BundleSpecification> requireBundles = new ArrayList<BundleSpecification>(); + + Collection<Capability> capabilities = resource.getCapabilities(null); + + Capability osgiIdentity = null; + for (Capability capability : capabilities) { + String namespace = capability.getNamespace(); + if (IdentityNamespace.IDENTITY_NAMESPACE.equals(namespace)) { + osgiIdentity = capability; + } else if (BundleRevision.HOST_NAMESPACE.equals(namespace) || BundleRevision.BUNDLE_NAMESPACE.equals(namespace)) { + continue; + } else if (BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) { + exportPackages.addAll(creatExportPackage(capability)); + } else { + provideCapabilities.addAll(createProvideCapability(capability)); + } + } + + Collection<Requirement> requirements = resource.getRequirements(null); + for (Requirement requirement : requirements) { + String namespace = requirement.getNamespace(); + if (BundleRevision.BUNDLE_NAMESPACE.equals(namespace)) { + requireBundles.addAll(createRequireBundle(requirement)); + } else if (BundleRevision.HOST_NAMESPACE.equals(namespace)) { + fragmentHost.addAll(createFragmentHost(requirement)); + } else if (BundleRevision.PACKAGE_NAMESPACE.equals(namespace)) { + importPackages.addAll(createImportPackage(requirement)); + } else { + requireCapabilities.addAll(createRequireCapability(requirement)); + } + } + + BundleDescription result = state.getFactory().createBundleDescription(resource.getBundle().getBundleId(), symbolicNameSpecification, version, null, requireBundles.toArray(new BundleSpecification[requireBundles.size()]), fragmentHost.size() == 0 ? null : fragmentHost.get(0), importPackages.toArray(new ImportPackageSpecification[importPackages.size()]), exportPackages.toArray(new ExportPackageDescription[exportPackages.size()]), null, null, requireCapabilities.toArray(new GenericSpecification[requireCapabilities.size()]), provideCapabilities.toArray(new GenericDescription[provideCapabilities.size()]), null); + result.setUserObject(resource); + GenericDescription[] genericDescs = result.getGenericCapabilities(); + for (GenericDescription genericDesc : genericDescs) { + if (IdentityNamespace.IDENTITY_NAMESPACE.equals(genericDesc.getType())) + genericDesc.setUserObject(osgiIdentity); + } + return result; + + } + + private List<ExportPackageDescription> creatExportPackage(Capability capability) { + Map<String, Object> attributes = new HashMap<String, Object>(capability.getAttributes()); + Map<String, String> directives = capability.getDirectives(); + String packageName = (String) attributes.remove(PackageNamespace.PACKAGE_NAMESPACE); + // remove invalid attributes + attributes.remove(PackageNamespace.CAPABILITY_BUNDLE_SYMBOLICNAME_ATTRIBUTE); + attributes.remove(PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE); + String declaration = packageName + toString(attributes, "=", true) + toString(directives, ":=", true); //$NON-NLS-1$//$NON-NLS-2$ + List<ExportPackageDescription> result = state.getFactory().createExportPackageDescriptions(declaration); + for (ExportPackageDescription export : result) { + export.setUserObject(capability); + } + return result; + } + + private List<GenericDescription> createProvideCapability(Capability capability) { + Map<String, Object> attributes = capability.getAttributes(); + Map<String, String> directives = capability.getDirectives(); + + String declaration = capability.getNamespace() + toString(attributes, "=", false) + toString(directives, ":=", true); //$NON-NLS-1$//$NON-NLS-2$ + List<GenericDescription> result = state.getFactory().createGenericDescriptions(declaration); + for (GenericDescription genericDescription : result) { + genericDescription.setUserObject(capability); + } + return result; + } + + private List<BundleSpecification> createRequireBundle(Requirement requirement) { + String declaration = createOSGiRequirement(requirement, BundleNamespace.BUNDLE_NAMESPACE, BundleNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); + List<BundleSpecification> result = state.getFactory().createBundleSpecifications(declaration); + for (BundleSpecification bundleSpecification : result) { + bundleSpecification.setUserObject(requirement); + } + return result; + } + + private List<HostSpecification> createFragmentHost(Requirement requirement) { + String declaration = createOSGiRequirement(requirement, HostNamespace.HOST_NAMESPACE, HostNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); + List<HostSpecification> result = state.getFactory().createHostSpecifications(declaration); + for (HostSpecification hostSpecification : result) { + hostSpecification.setUserObject(requirement); + } + return result; + } + + private List<ImportPackageSpecification> createImportPackage(Requirement requirement) { + String declaration = createOSGiRequirement(requirement, PackageNamespace.PACKAGE_NAMESPACE, PackageNamespace.CAPABILITY_VERSION_ATTRIBUTE, PackageNamespace.CAPABILITY_BUNDLE_VERSION_ATTRIBUTE); + List<ImportPackageSpecification> result = state.getFactory().createImportPackageSpecifications(declaration); + for (ImportPackageSpecification importPackageSpecification : result) { + importPackageSpecification.setUserObject(requirement); + } + return result; + } + + private List<GenericSpecification> createRequireCapability(Requirement requirement) { + String declaration = requirement.getNamespace() + toString(requirement.getAttributes(), "=", false) + toString(requirement.getDirectives(), ":=", true); //$NON-NLS-1$ //$NON-NLS-2$ + List<GenericSpecification> result = state.getFactory().createGenericSpecifications(declaration); + for (GenericSpecification genericSpecification : result) { + genericSpecification.setUserObject(requirement); + } + return result; + } + + private String createOSGiRequirement(Requirement requirement, String namespace, String... versions) { + Map<String, String> directives = new HashMap<String, String>(requirement.getDirectives()); + String filter = directives.remove(Namespace.REQUIREMENT_FILTER_DIRECTIVE); + if (filter == null) + throw new IllegalArgumentException("No filter directive found:" + requirement); //$NON-NLS-1$ + FilterParser parser = new FilterParser(filter); + FilterComponent component = null; + try { + component = parser.parse(); + } catch (InvalidSyntaxException e) { + throw new IllegalArgumentException("Invalid filter directive", e); //$NON-NLS-1$ + } + Map<String, String> matchingAttributes = component.getStandardOSGiAttributes(versions); + String name = matchingAttributes.remove(namespace); + if (name == null) + throw new IllegalArgumentException("Invalid requirement: " + requirement); //$NON-NLS-1$ + return name + toString(matchingAttributes, "=", true) + toString(directives, ":=", true); //$NON-NLS-1$ //$NON-NLS-2$ + } + + static <V> String toString(Map<String, V> map, String assignment, boolean stringsOnly) { + if (map.isEmpty()) + return ""; //$NON-NLS-1$ + Set<Entry<String, V>> set = map.entrySet(); + StringBuffer sb = new StringBuffer(); + for (Entry<String, V> entry : set) { + sb.append("; "); //$NON-NLS-1$ + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof List) { + @SuppressWarnings("unchecked") + List<Object> list = (List<Object>) value; + if (list.size() == 0) + continue; + Object component = list.get(0); + String className = component.getClass().getName(); + String type = className.substring(className.lastIndexOf('.') + 1); + sb.append(key).append(':').append("List<").append(type).append(">").append(assignment).append('"'); //$NON-NLS-1$ //$NON-NLS-2$ + for (Object object : list) + sb.append(object).append(','); + sb.setLength(sb.length() - 1); + sb.append('"'); + } else { + String type = ""; //$NON-NLS-1$ + if (!(value instanceof String) && !stringsOnly) { + String className = value.getClass().getName(); + type = ":" + className.substring(className.lastIndexOf('.') + 1); //$NON-NLS-1$ + } + sb.append(key).append(type).append(assignment).append('"').append(value).append('"'); + } + } + return sb.toString(); + } +} |