001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.bundles;
006:
007: import org.knopflerfish.framework.VersionRange;
008:
009: import com.tc.bundles.Version;
010:
011: import java.util.HashMap;
012: import java.util.Map;
013:
014: /**
015: * Specification for the Require-Bundle attribute
016: *
017: * <pre>
018: * SYNTAX:
019: * Require-Bundle ::= bundle {, bundle...}
020: * bundle ::= symbolic-name{;bundle-version:="constraint"{;resolution:=optional}}
021: * constraint ::= [range] || (range)
022: * range ::= min, {max}
023: *
024: * EXAMPLES:
025: * Require-Bundle: foo.bar.baz.widget - require widget bundle from group foo.bar.baz
026: * Require-Bundle: foo.bar.baz.widget, foo.bar.baz.gadget - require widget and gadget bundles
027: * Require-Bundle: foo.bar.baz.widget;bundle-version:="1.0.0" - widget bundle must be version 1.0.0
028: * Require-Bundle: foo.bar.baz.widget;bundle-version:="[1.0.0, 2.0.0]" - bundle version must > 1.0.0 and < 2.0.0
029: * Require-Bundle: foo.bar.baz.widget;bundle-version:="[1.0.0, 2.0.0)" - bundle version must > 1.0.0 and <= 2.0.0
030: * Require-Bundle: foo.bar.baz.widget;bundle-version:="(1.0.0, 2.0.0)" - bundle version must >= 1.0.0 and <= 2.0.0
031: * Require-Bundle: foo.bar.baz.widget;bundle-version:="(1.0.0, 2.0.0]" - bundle version must >= 1.0.0 and < 2.0.0
032: * Require-Bundle: foo.bar.baz.widget;bundle-version:="[1.0.0,]" - bundle version must > 1.0.0
033: * Require-Bundle: foo.bar.baz.widget;bundle-version:="(1.0.0,)" - bundle version must >= 1.0.0
034: * Require-Bundle: foo.bar.baz.widget;resolution:=optional - bundle is optional (recognized but not supported)
035: * </pre>
036: */
037: final class BundleSpecImpl extends BundleSpec {
038: private final String symbolicName;
039: private final Map attributes = new HashMap();
040:
041: BundleSpecImpl(final String spec) {
042: final String[] data = spec.split(";");
043: this .symbolicName = data[0];
044: for (int i = 1; i < data.length; i++) {
045: final String[] pairs = data[i].replaceAll(" ", "").split(
046: ":=");
047: attributes.put(pairs[0], pairs[1].replaceAll("\\\"", ""));
048: }
049: }
050:
051: public String getSymbolicName() {
052: return this .symbolicName;
053: }
054:
055: public String getName() {
056: return extractInfo("name");
057: }
058:
059: public String getGroupId() {
060: return extractInfo("group-id");
061: }
062:
063: private String extractInfo(final String n) {
064: final String[] pieces = this .symbolicName.split("\\.");
065: int k = 0;
066: for (int i = pieces.length - 1; i >= 0; i--) {
067: if (pieces[i].matches("^" + BUNDLE_SYMBOLIC_NAME_REGEX)) {
068: k = i;
069: break;
070: }
071: }
072: final int start = "name".equals(n) ? k : 0;
073: final int end = "name".equals(n) ? pieces.length : k;
074: final StringBuffer result = new StringBuffer();
075: for (int j = start; j < end; j++) {
076: result.append(pieces[j]).append(".");
077: }
078: return result.toString().replaceFirst("\\.$", "");
079: }
080:
081: public String getVersion() {
082: final String bundleversion = (String) attributes
083: .get(PROP_KEY_BUNDLE_VERSION);
084: return (bundleversion == null) ? "(any-version)"
085: : bundleversion;
086: }
087:
088: public boolean isOptional() {
089: final String resolution = (String) attributes
090: .get(PROP_KEY_RESOLUTION);
091: return (resolution != null) && resolution.equals("optional");
092: }
093:
094: public boolean isCompatible(final String symname,
095: final String version) {
096: // symbolic-names must match
097: if (!BundleSpec.isMatchingSymbolicName(this .symbolicName,
098: symname))
099: return false;
100:
101: // if symbolic-names are matching, then check for version compatibility
102: String spec = (String) attributes.get(PROP_KEY_BUNDLE_VERSION);
103:
104: // no specific bundle-version required/specified
105: // so it must be compatible with the version
106: if (spec == null)
107: return true;
108:
109: final Version target = new Version(version);
110: VersionRange range = new VersionRange(spec);
111:
112: return range.withinRange(target);
113: }
114: }
|