blob: b0905216a004bfa1acda795c1cbed6b75b194b72 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.cauldron.bld.obr;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import org.cauldron.sigil.model.ModelElementFactory;
import org.cauldron.sigil.model.common.LDAPExpr;
import org.cauldron.sigil.model.common.LDAPParseException;
import org.cauldron.sigil.model.common.LDAPParser;
import org.cauldron.sigil.model.common.SimpleTerm;
import org.cauldron.sigil.model.common.VersionRange;
import org.cauldron.sigil.model.eclipse.ISigilBundle;
import org.cauldron.sigil.model.osgi.IBundleModelElement;
import org.cauldron.sigil.model.osgi.IPackageExport;
import org.cauldron.sigil.model.osgi.IPackageImport;
import org.cauldron.sigil.model.osgi.IRequiredBundle;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.osgi.framework.Version;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
final class OBRHandler extends DefaultHandler {
private static final String PACKAGE = "package";
private static final String URI = "uri";
private static final String PRESENTATION_NAME = "presentationname";
private static final String VERSION = "version";
private static final String SYMBOLIC_NAME = "symbolicname";
private final File cacheDir;
private final URL obrURL;
private final OBRListener listener;
private HashSet<String> sanity = new HashSet<String>();
private Locator locator;
private ISigilBundle bundle;
private IPackageExport export;
public OBRHandler(URL obrURL, File bundleCache, OBRListener listener) {
this.obrURL = obrURL;
this.cacheDir = bundleCache;
this.listener = listener;
}
public void setDocumentLocator (Locator locator) {
this.locator = locator;
}
public void startElement (String uri, String localName,
String qName, Attributes attributes) throws SAXException {
if ( "resource".equals( qName ) ) {
startResource(attributes);
}
else if ( "capability".equals( qName ) ) {
startCapability(attributes);
}
else if( "require".equals( qName ) ) {
startRequire(attributes);
}
else if ( "p".equals( qName ) ) {
startProperty(attributes);
}
}
public void endElement (String uri, String localName, String qName)
throws SAXException {
if ( "resource".equals( qName ) ) {
endResource();
}
else if ( "capability".equals( qName ) ) {
endCapability();
}
else if( "require".equals( qName ) ) {
endRequire();
}
else if ( "p".equals( qName ) ) {
endProperty();
}
}
private void startResource(Attributes attributes) throws SAXException {
try {
String uri = attributes.getValue("", URI);
if ( uri.endsWith( ".jar" ) ) {
if ( !sanity.add(uri) ) {
throw new RuntimeException(uri);
}
ISigilBundle b = ModelElementFactory.getInstance().newModelElement(ISigilBundle.class);
IBundleModelElement info = ModelElementFactory.getInstance().newModelElement(IBundleModelElement.class);
info.setSymbolicName(attributes.getValue("", SYMBOLIC_NAME));
info.setVersion(new Version(attributes.getValue("", VERSION)));
info.setName(attributes.getValue("", PRESENTATION_NAME));
URI l = makeAbsolute(uri);
info.setUpdateLocation(l);
b.setLocation(cachePath(info));
b.setBundleInfo(info);
bundle = b;
}
}
catch (Exception e) {
throw new SAXParseException("Failed to build bundle info", locator, e);
}
}
private URI makeAbsolute(String uri) throws URISyntaxException {
URI l = new URI(uri);
if ( !l.isAbsolute() ) {
String base = obrURL.toExternalForm();
int i = base.lastIndexOf("/");
if ( i != -1 ) {
base = base.substring(0, i);
l = new URI( base + (uri.startsWith("/") ? "" : "/") + uri );
}
}
return l;
}
private IPath cachePath(IBundleModelElement info) {
return new Path(cacheDir.getAbsolutePath()).append( info.getSymbolicName() + "_" + info.getVersion() + ".jar" );
}
private void startCapability(Attributes attributes) {
if ( bundle != null ) {
if ( PACKAGE.equals( attributes.getValue("", "name") ) ) {
export = ModelElementFactory.getInstance().newModelElement(IPackageExport.class);
}
}
}
private void startRequire(Attributes attributes) throws SAXParseException {
if ( bundle != null ) {
String name = attributes.getValue("name");
if ( PACKAGE.equals( name ) ) {
IPackageImport pi = ModelElementFactory.getInstance().newModelElement(IPackageImport.class);
try {
LDAPExpr expr = LDAPParser.parseExpression(attributes.getValue("filter") );
pi.setPackageName(decodePackage(expr, locator));
pi.setVersions(decodeVersions(expr, locator));
pi.setOptional(Boolean.valueOf(attributes.getValue("optional")));
bundle.getBundleInfo().addImport(pi);
} catch (LDAPParseException e) {
throw new SAXParseException("Failed to parse filter", locator, e);
}
}
else if ( "bundle".equals( name ) ) {
IRequiredBundle b = ModelElementFactory.getInstance().newModelElement(IRequiredBundle.class);
try {
LDAPExpr expr = LDAPParser.parseExpression(attributes.getValue("filter") );
b.setSymbolicName(decodeSymbolicName(expr, locator));
b.setVersions(decodeVersions(expr, locator));
b.setOptional(Boolean.valueOf(attributes.getValue("optional")));
bundle.getBundleInfo().addRequiredBundle(b);
} catch (Exception e) {
System.err.println( "Failed to parse filter in bundle " + bundle.getBundleInfo().getSymbolicName() );
throw new SAXParseException("Failed to parse filter in bundle " + bundle.getBundleInfo().getSymbolicName(), locator, e);
}
}
//else if ( "ee".equals( name ) ) {
// TODO ignore for now...
//}
//else if ( "service".equals( name ) ) {
// TODO ignore for now...
//}
//else {
// for ( int i = 0; i < attributes.getLength(); i++ ) {
// System.out.println( "Found requirement " + attributes.getValue(i) );
// }
//}
}
}
private static VersionRange decodeVersions(LDAPExpr expr, Locator locator) throws SAXParseException {
try {
return VersionRangeHelper.decodeVersions(expr);
}
catch (NumberFormatException e) {
throw new SAXParseException(e.getMessage(), locator);
}
}
private void startProperty(Attributes attributes) {
if ( export != null ) {
String name = attributes.getValue("", "n");
String value = attributes.getValue("", "v");
if ( PACKAGE.equals( name ) ) {
export.setPackageName(value);
}
else if ( "uses".equals( name ) ) {
String[] split = value.split(",");
export.setUses( Arrays.asList(split) );
}
else if ( "version".equals( name ) ) {
export.setVersion( new Version(value) );
}
}
}
private void endResource() {
if ( bundle != null ) {
listener.handleBundle(bundle);
bundle = null;
}
}
private void endCapability() {
if ( bundle != null ) {
if ( export != null ) {
bundle.getBundleInfo().addExport(export);
export = null;
}
}
}
private void endRequire() {
// TODO Auto-generated method stub
}
private void endProperty() {
// TODO Auto-generated method stub
}
private static String decodePackage(LDAPExpr expr, Locator locator) throws SAXParseException {
ArrayList<SimpleTerm> terms = new ArrayList<SimpleTerm>(1);
findTerms("package", expr, terms);
if ( terms.isEmpty() ) {
throw new SAXParseException("Missing name filter in " + expr, locator);
}
return terms.get(0).getRval();
}
private static String decodeSymbolicName(LDAPExpr expr, Locator locator) throws SAXParseException {
ArrayList<SimpleTerm> terms = new ArrayList<SimpleTerm>(1);
findTerms("symbolicname", expr, terms);
if ( terms.isEmpty() ) {
throw new SAXParseException("Missing name filter in " + expr, locator);
}
return terms.get(0).getRval();
}
private static void findTerms(String string, LDAPExpr expr, List<SimpleTerm> terms) throws SAXParseException {
if ( expr instanceof SimpleTerm ) {
SimpleTerm term = (SimpleTerm) expr;
if ( term.getName().equals(string) ) {
terms.add(term);
}
}
else {
for ( LDAPExpr c : expr.getChildren() ) {
findTerms(string, c, terms);
}
}
}
}