| /* |
| * 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); |
| } |
| } |
| } |
| } |