package org.osgi.service.indexer.impl;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import java.util.StringTokenizer;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.osgi.framework.Version;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.indexer.Builder;
import org.osgi.service.indexer.Capability;
import org.osgi.service.indexer.Namespaces;
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.VersionKey;
import org.osgi.service.indexer.impl.types.VersionRange;
import org.osgi.service.log.LogService;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SCRAnalyzer implements ResourceAnalyzer {
public static final String NS_1_0 = "http://www.osgi.org/xmlns/scr/v1.0.0";
public static final String NS_1_1 = "http://www.osgi.org/xmlns/scr/v1.1.0";
public static final String NS_1_2 = "http://www.osgi.org/xmlns/scr/v1.2.0";
private LogService log;
public SCRAnalyzer(LogService log) {
this.log = log;
}
public void analyzeResource(Resource resource, List<Capability> caps, List<Requirement> reqs) throws Exception {
String header = resource.getManifest().getMainAttributes().getValue(ComponentConstants.SERVICE_COMPONENT);
if (header == null)
return;
StringTokenizer tokenizer = new StringTokenizer(header, ",");
Version highest = null;
while (tokenizer.hasMoreTokens()) {
String pattern = tokenizer.nextToken().trim();
List<String> paths = Util.findMatchingPaths(resource, pattern);
if (paths != null) for (String path : paths) {
Version version = processScrXml(resource, path);
if (highest == null || (version.compareTo(highest) > 0))
highest = version;
}
}
if (highest!= null) {
Requirement requirement = createRequirement(new VersionRange("[" + highest + ",2.0)"));
reqs.add(requirement);
}
}
private Version processScrXml(Resource resource, String path) throws IOException {
Resource childResource = resource.getChild(path);
if (childResource == null) {
if (log != null) log.log(LogService.LOG_WARNING, MessageFormat.format("Cannot analyse SCR requirement version: resource {0} does not contain path {1} referred from Service-Component header.", resource.getLocation(), path));
return null;
}
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
try {
SAXParser parser = spf.newSAXParser();
SCRContentHandler handler = new SCRContentHandler();
parser.parse(childResource.getStream(), handler);
return handler.highest;
} catch (Exception e) {
if (log != null)
log.log(LogService.LOG_ERROR, MessageFormat.format("Processing error: failed to parse child resource {0} in resource {1}.", path, resource.getLocation()), e);
return null;
}
}
private static Requirement createRequirement(VersionRange range) {
Builder builder = new Builder().setNamespace(Namespaces.NS_EXTENDER);
StringBuilder filter = new StringBuilder();
filter.append('(').append(Namespaces.NS_EXTENDER).append('=').append(Namespaces.EXTENDER_SCR).append(')');
filter.insert(0, "(&");
Util.addVersionFilter(filter, range, VersionKey.PackageVersion);
filter.append(')');
builder.addDirective(Namespaces.DIRECTIVE_FILTER, filter.toString())
.addDirective(Namespaces.DIRECTIVE_EFFECTIVE, Namespaces.EFFECTIVE_ACTIVE);
Requirement requirement = builder.buildRequirement();
return requirement;
}
private static class SCRContentHandler extends DefaultHandler {
private Version highest = null;
private boolean beforeRoot = true;
@Override
public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
if (uri == null || "".equals(uri)) {
if (beforeRoot) {
beforeRoot = false;
setVersion(new Version(1,0,0));
}
} else {
if (NS_1_2.equals(uri))
setVersion(new Version(1,2,0));
else if (NS_1_1.equals(uri))
setVersion(new Version(1,1,0));
else if (NS_1_0.equals(uri))
setVersion(new Version(1,2,0));
}
}
private void setVersion(Version version) {
if (highest == null || (version.compareTo(highest) > 0))
highest = version;
}
}
}