1 /******************************************************************************* 2 * Copyright (c) 2003, 2012 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Danail Nachev - ProSyst - bug 218625 14 * Rob Harrop - SpringSource Inc. (bug 247522) 15 *******************************************************************************/ 16 package org.eclipse.osgi.internal.resolver; 17 18 import java.util.Collections; 19 import java.util.Map; 20 import org.eclipse.osgi.internal.framework.EquinoxContainer; 21 import org.eclipse.osgi.internal.resolver.BaseDescriptionImpl.BaseCapability; 22 import org.eclipse.osgi.service.resolver.*; 23 import org.eclipse.osgi.service.resolver.VersionRange; 24 import org.eclipse.osgi.util.ManifestElement; 25 import org.osgi.framework.*; 26 import org.osgi.framework.namespace.AbstractWiringNamespace; 27 import org.osgi.framework.wiring.*; 28 import org.osgi.resource.Capability; 29 import org.osgi.resource.Namespace; 30 31 abstract class VersionConstraintImpl implements VersionConstraint { 32 33 protected final Object monitor = new Object(); 34 35 private String name; 36 private VersionRange versionRange; 37 private BundleDescription bundle; 38 private BaseDescription supplier; 39 private volatile Object userObject; 40 getName()41 public String getName() { 42 synchronized (this.monitor) { 43 if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(name)) { 44 StateImpl state = (StateImpl) getBundle().getContainingState(); 45 return state == null ? EquinoxContainer.NAME : state.getSystemBundle(); 46 } 47 return name; 48 } 49 } 50 getVersionRange()51 public VersionRange getVersionRange() { 52 synchronized (this.monitor) { 53 if (versionRange == null) 54 return VersionRange.emptyRange; 55 return versionRange; 56 } 57 } 58 getBundle()59 public BundleDescription getBundle() { 60 synchronized (this.monitor) { 61 return bundle; 62 } 63 } 64 isResolved()65 public boolean isResolved() { 66 synchronized (this.monitor) { 67 return supplier != null; 68 } 69 } 70 getSupplier()71 public BaseDescription getSupplier() { 72 synchronized (this.monitor) { 73 return supplier; 74 } 75 } 76 isSatisfiedBy(BaseDescription candidate)77 public boolean isSatisfiedBy(BaseDescription candidate) { 78 synchronized (this.monitor) { 79 return false; 80 } 81 } 82 setName(String name)83 protected void setName(String name) { 84 synchronized (this.monitor) { 85 this.name = name; 86 } 87 } 88 setVersionRange(VersionRange versionRange)89 protected void setVersionRange(VersionRange versionRange) { 90 synchronized (this.monitor) { 91 this.versionRange = versionRange; 92 } 93 } 94 setBundle(BundleDescription bundle)95 protected void setBundle(BundleDescription bundle) { 96 synchronized (this.monitor) { 97 this.bundle = bundle; 98 } 99 } 100 setSupplier(BaseDescription supplier)101 protected void setSupplier(BaseDescription supplier) { 102 synchronized (this.monitor) { 103 this.supplier = supplier; 104 } 105 } 106 getInternalNameSpace()107 protected abstract String getInternalNameSpace(); 108 getInternalDirectives()109 protected abstract Map<String, String> getInternalDirectives(); 110 getInteralAttributes()111 protected abstract Map<String, Object> getInteralAttributes(); 112 hasMandatoryAttributes(String[] mandatory)113 protected abstract boolean hasMandatoryAttributes(String[] mandatory); 114 getRequirement()115 public BundleRequirement getRequirement() { 116 String namespace = getInternalNameSpace(); 117 if (namespace == null) 118 return null; 119 return new BundleRequirementImpl(namespace); 120 } 121 getUserObject()122 public Object getUserObject() { 123 return userObject; 124 } 125 setUserObject(Object userObject)126 public void setUserObject(Object userObject) { 127 this.userObject = userObject; 128 } 129 130 class BundleRequirementImpl implements BundleRequirement { 131 private final String namespace; 132 BundleRequirementImpl(String namespace)133 public BundleRequirementImpl(String namespace) { 134 this.namespace = namespace; 135 } 136 getNamespace()137 public String getNamespace() { 138 return namespace; 139 } 140 getDirectives()141 public Map<String, String> getDirectives() { 142 return Collections.unmodifiableMap(getInternalDirectives()); 143 } 144 getAttributes()145 public Map<String, Object> getAttributes() { 146 return Collections.unmodifiableMap(getInteralAttributes()); 147 } 148 getRevision()149 public BundleRevision getRevision() { 150 return getBundle(); 151 } 152 matches(BundleCapability capability)153 public boolean matches(BundleCapability capability) { 154 return isSatisfiedBy(((BaseCapability) capability).getBaseDescription()); 155 } 156 157 @Override hashCode()158 public int hashCode() { 159 return System.identityHashCode(VersionConstraintImpl.this); 160 } 161 getVersionConstraint()162 private VersionConstraintImpl getVersionConstraint() { 163 return VersionConstraintImpl.this; 164 } 165 166 @Override equals(Object obj)167 public boolean equals(Object obj) { 168 if (this == obj) 169 return true; 170 if (!(obj instanceof BundleRequirementImpl)) 171 return false; 172 return ((BundleRequirementImpl) obj).getVersionConstraint() == VersionConstraintImpl.this; 173 } 174 175 @Override toString()176 public String toString() { 177 return getNamespace() + BaseDescriptionImpl.toString(getAttributes(), false) + BaseDescriptionImpl.toString(getDirectives(), true); 178 } 179 matches(Capability capability)180 public boolean matches(Capability capability) { 181 if (capability instanceof BundleCapability) 182 return matches((BundleCapability) capability); 183 // now we must do the generic thing 184 if (!namespace.equals(capability.getNamespace())) 185 return false; 186 String filterSpec = getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE); 187 try { 188 if (filterSpec != null && !FrameworkUtil.createFilter(filterSpec).matches(capability.getAttributes())) 189 return false; 190 } catch (InvalidSyntaxException e) { 191 return false; 192 } 193 return hasMandatoryAttributes(ManifestElement.getArrayFromList(capability.getDirectives().get(AbstractWiringNamespace.CAPABILITY_MANDATORY_DIRECTIVE))); 194 } 195 getResource()196 public BundleRevision getResource() { 197 return getRevision(); 198 } 199 } 200 addFilterAttributes(StringBuilder filter, Map<String, ?> attributes)201 static StringBuilder addFilterAttributes(StringBuilder filter, Map<String, ?> attributes) { 202 for (Map.Entry<String, ?> entry : attributes.entrySet()) { 203 addFilterAttribute(filter, entry.getKey(), entry.getValue()); 204 } 205 return filter; 206 } 207 addFilterAttribute(StringBuilder filter, String attr, Object value)208 static StringBuilder addFilterAttribute(StringBuilder filter, String attr, Object value) { 209 return addFilterAttribute(filter, attr, value, true); 210 } 211 addFilterAttribute(StringBuilder filter, String attr, Object value, boolean escapeWildCard)212 static StringBuilder addFilterAttribute(StringBuilder filter, String attr, Object value, boolean escapeWildCard) { 213 if (value instanceof VersionRange) { 214 VersionRange range = (VersionRange) value; 215 filter.append(range.toFilterString(attr)); 216 } else { 217 filter.append('(').append(attr).append('=').append(escapeValue(value, escapeWildCard)).append(')'); 218 } 219 return filter; 220 } 221 escapeValue(Object o, boolean escapeWildCard)222 private static String escapeValue(Object o, boolean escapeWildCard) { 223 String value = o.toString(); 224 boolean escaped = false; 225 int inlen = value.length(); 226 int outlen = inlen << 1; /* inlen * 2 */ 227 228 char[] output = new char[outlen]; 229 value.getChars(0, inlen, output, inlen); 230 231 int cursor = 0; 232 for (int i = inlen; i < outlen; i++) { 233 char c = output[i]; 234 switch (c) { 235 case '*' : 236 if (!escapeWildCard) 237 break; 238 case '\\' : 239 case '(' : 240 case ')' : 241 output[cursor] = '\\'; 242 cursor++; 243 escaped = true; 244 break; 245 } 246 247 output[cursor] = c; 248 cursor++; 249 } 250 251 return escaped ? new String(output, 0, cursor) : value; 252 } 253 } 254