1 /*******************************************************************************
2  * Copyright (c) 2003, 2016 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  *     Rob Harrop - SpringSource Inc. (bug 247522)
14  *******************************************************************************/
15 package org.eclipse.osgi.internal.resolver;
16 
17 import java.util.*;
18 import org.eclipse.osgi.service.resolver.*;
19 import org.osgi.framework.Constants;
20 import org.osgi.framework.wiring.BundleRevision;
21 
22 public class BundleSpecificationImpl extends VersionConstraintImpl implements BundleSpecification {
23 	private boolean exported;
24 	private boolean optional;
25 	private Map<String, Object> attributes;
26 	private Map<String, String> arbitraryDirectives;
27 
setExported(boolean exported)28 	protected void setExported(boolean exported) {
29 		synchronized (this.monitor) {
30 			this.exported = exported;
31 		}
32 	}
33 
setOptional(boolean optional)34 	protected void setOptional(boolean optional) {
35 		synchronized (this.monitor) {
36 			this.optional = optional;
37 		}
38 	}
39 
isExported()40 	public boolean isExported() {
41 		synchronized (this.monitor) {
42 			return exported;
43 		}
44 	}
45 
isOptional()46 	public boolean isOptional() {
47 		synchronized (this.monitor) {
48 			return optional;
49 		}
50 	}
51 
getAttributes()52 	Map<String, Object> getAttributes() {
53 		synchronized (this.monitor) {
54 			return attributes;
55 		}
56 	}
57 
58 	@SuppressWarnings("unchecked")
setAttributes(Map<String, ?> attributes)59 	void setAttributes(Map<String, ?> attributes) {
60 		synchronized (this.monitor) {
61 			this.attributes = (Map<String, Object>) attributes;
62 		}
63 	}
64 
getArbitraryDirectives()65 	Map<String, String> getArbitraryDirectives() {
66 		synchronized (this.monitor) {
67 			return arbitraryDirectives;
68 		}
69 	}
70 
71 	@SuppressWarnings("unchecked")
setArbitraryDirectives(Map<String, ?> directives)72 	void setArbitraryDirectives(Map<String, ?> directives) {
73 		synchronized (this.monitor) {
74 			this.arbitraryDirectives = (Map<String, String>) directives;
75 		}
76 	}
77 
78 	@Override
isSatisfiedBy(BaseDescription supplier)79 	public boolean isSatisfiedBy(BaseDescription supplier) {
80 		if (!(supplier instanceof BundleDescriptionImpl))
81 			return false;
82 		BundleDescriptionImpl candidate = (BundleDescriptionImpl) supplier;
83 		if (candidate.getHost() != null)
84 			return false;
85 		Map<String, ?> requiredAttrs = getAttributes();
86 		if (requiredAttrs != null) {
87 			Map<String, ?> prividerAttrs = candidate.getAttributes();
88 			if (prividerAttrs == null)
89 				return false;
90 			for (String key : requiredAttrs.keySet()) {
91 				Object requiredValue = requiredAttrs.get(key);
92 				Object prividedValue = prividerAttrs.get(key);
93 				if (prividedValue == null || !requiredValue.equals(prividedValue))
94 					return false;
95 			}
96 		}
97 		String[] mandatory = (String[]) candidate.getDirective(Constants.MANDATORY_DIRECTIVE);
98 		if (!hasMandatoryAttributes(mandatory))
99 			return false;
100 		if (getName() != null && getName().equals(candidate.getSymbolicName()) && (getVersionRange() == null || getVersionRange().isIncluded(candidate.getVersion())))
101 			return true;
102 		return false;
103 	}
104 
105 	@Override
hasMandatoryAttributes(String[] mandatory)106 	protected boolean hasMandatoryAttributes(String[] mandatory) {
107 		if (mandatory != null) {
108 			Map<String, ?> requiredAttrs = getAttributes();
109 			for (String key : mandatory) {
110 				if (Constants.BUNDLE_VERSION_ATTRIBUTE.equals(key))
111 					continue; // has a default value of 0.0.0
112 				if (requiredAttrs == null || requiredAttrs.get(key) == null)
113 					return false;
114 			}
115 		}
116 		return true;
117 	}
118 
119 	@Override
toString()120 	public String toString() {
121 		return "Require-Bundle: " + getName() + "; bundle-version=\"" + getVersionRange() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
122 	}
123 
124 	@Override
getInternalDirectives()125 	protected Map<String, String> getInternalDirectives() {
126 		Map<String, String> result = new HashMap<>(2);
127 		synchronized (this.monitor) {
128 			if (arbitraryDirectives != null)
129 				result.putAll(arbitraryDirectives);
130 			if (exported)
131 				result.put(Constants.VISIBILITY_DIRECTIVE, Constants.VISIBILITY_REEXPORT);
132 			if (optional)
133 				result.put(Constants.RESOLUTION_DIRECTIVE, Constants.RESOLUTION_OPTIONAL);
134 			result.put(Constants.FILTER_DIRECTIVE, createFilterDirective());
135 			return result;
136 		}
137 	}
138 
createFilterDirective()139 	private String createFilterDirective() {
140 		StringBuilder filter = new StringBuilder();
141 		filter.append("(&"); //$NON-NLS-1$
142 		synchronized (this.monitor) {
143 			addFilterAttribute(filter, BundleRevision.BUNDLE_NAMESPACE, getName());
144 			VersionRange range = getVersionRange();
145 			if (range != null && range != VersionRange.emptyRange)
146 				addFilterAttribute(filter, Constants.BUNDLE_VERSION_ATTRIBUTE, range);
147 			if (attributes != null)
148 				addFilterAttributes(filter, attributes);
149 		}
150 		filter.append(')');
151 		return filter.toString();
152 	}
153 
154 	@Override
getInteralAttributes()155 	protected Map<String, Object> getInteralAttributes() {
156 		return Collections.<String, Object> emptyMap();
157 	}
158 
159 	@Override
getInternalNameSpace()160 	protected String getInternalNameSpace() {
161 		return BundleRevision.BUNDLE_NAMESPACE;
162 	}
163 }
164