package org.osgi.service.indexer.impl;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import org.osgi.framework.Version;
import org.osgi.service.indexer.Builder;
import org.osgi.service.indexer.Capability;
import org.osgi.service.indexer.Requirement;
import org.osgi.service.indexer.Resource;
import org.osgi.service.indexer.ResourceAnalyzer;
import org.osgi.service.indexer.impl.types.SymbolicName;
import org.osgi.service.indexer.impl.types.VersionRange;
import org.osgi.service.indexer.impl.util.OSGiHeader;
public class KnownBundleAnalyzer implements ResourceAnalyzer {
private final Properties defaultProperties;
private Properties extraProperties = null;
public KnownBundleAnalyzer() {
defaultProperties = new Properties();
InputStream stream = KnownBundleAnalyzer.class.getResourceAsStream("known-bundles.properties");
if (stream != null) {
try {
defaultProperties.load(stream);
} catch (IOException e) {
// ignore
} finally {
try { stream.close(); } catch (IOException e) {}
}
}
}
public KnownBundleAnalyzer(Properties properties) {
this.defaultProperties = properties;
}
public void setKnownBundlesExtra(Properties extras) {
this.extraProperties = extras;
}
public void analyzeResource(Resource resource, List<Capability> caps, List<Requirement> reqs) throws Exception {
SymbolicName resourceName = Util.getSymbolicName(resource);
for (Enumeration<?> names = defaultProperties.propertyNames(); names.hasMoreElements(); ) {
String propName = (String) names.nextElement();
processPropertyName(resource, caps, reqs, resourceName, propName, defaultProperties);
}
if (extraProperties != null)
for (Enumeration<?> names = extraProperties.propertyNames(); names.hasMoreElements(); ) {
String propName = (String) names.nextElement();
processPropertyName(resource, caps, reqs, resourceName, propName, extraProperties, defaultProperties);
}
}
private static void processPropertyName(Resource resource, List<Capability> caps, List<Requirement> reqs, SymbolicName resourceName, String name, Properties... propertiesList) throws IOException {
String[] bundleRef = name.split(";");
String bsn = bundleRef[0];
if (resourceName.getName().equals(bsn)) {
VersionRange versionRange = null;
if (bundleRef.length > 1)
versionRange = new VersionRange(bundleRef[1]);
Version version = Util.getVersion(resource);
if (versionRange == null || versionRange.match(version)) {
processClause(name, Util.readProcessedProperty(name, propertiesList), caps, reqs);
}
}
}
private static void processClause(String bundleRef, String clauseStr, List<Capability> caps, List<Requirement> reqs) {
Map<String, Map<String, String>> header = OSGiHeader.parseHeader(clauseStr);
for (Entry<String, Map<String,String>> entry : header.entrySet()) {
String indicator = OSGiHeader.removeDuplicateMarker(entry.getKey());
String[] parsedIndicator = indicator.split("@", 2);
if (parsedIndicator.length == 2) {
String type = parsedIndicator[0];
String namespace = parsedIndicator[1];
Builder builder = new Builder().setNamespace(namespace);
Map<String, String> attribs = entry.getValue();
Util.copyAttribsToBuilder(builder, attribs);
if ("capability".equalsIgnoreCase(type) || "cap".equalsIgnoreCase(type))
caps.add(builder.buildCapability());
else if ("requirement".equalsIgnoreCase(type) || "req".equalsIgnoreCase(type))
reqs.add(builder.buildRequirement());
else throw new IllegalArgumentException(MessageFormat.format("Invalid indicator type in known-bundle parsing for bundle \"{0}\", must be either cap[ability] or req[uirement], found \"{1}\".", bundleRef));
} else {
throw new IllegalArgumentException(MessageFormat.format("Invalid indicator format in known-bundle parsing for bundle \"{0}\", expected type@namespace, found \"{1}\".", bundleRef, indicator));
}
}
}
}