| /* |
| * 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.apache.felix.sigil.obr.impl; |
| |
| |
| 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.List; |
| |
| import org.apache.felix.sigil.common.osgi.LDAPExpr; |
| import org.apache.felix.sigil.common.osgi.LDAPParseException; |
| import org.apache.felix.sigil.common.osgi.LDAPParser; |
| import org.apache.felix.sigil.common.osgi.SimpleTerm; |
| import org.apache.felix.sigil.common.osgi.VersionRange; |
| import org.apache.felix.sigil.common.osgi.VersionTable; |
| import org.apache.felix.sigil.model.ModelElementFactory; |
| import org.apache.felix.sigil.model.eclipse.ISigilBundle; |
| import org.apache.felix.sigil.model.osgi.IBundleModelElement; |
| import org.apache.felix.sigil.model.osgi.IPackageExport; |
| import org.apache.felix.sigil.model.osgi.IPackageImport; |
| import org.apache.felix.sigil.model.osgi.IRequiredBundle; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| 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; |
| private int depth; |
| |
| |
| 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 ( depth++ == 0 && !"repository".equals( qName ) ) { |
| throw new SAXParseException("Invalid OBR document, expected repository top level element", locator); |
| } |
| else 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 |
| { |
| depth--; |
| 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( VersionTable.getVersion(attributes.getValue( "", VERSION ) ) ); |
| info.setName( attributes.getValue( "", PRESENTATION_NAME ) ); |
| URI l = makeAbsolute( uri ); |
| info.setUpdateLocation( l ); |
| if ( "file".equals( l.getScheme() ) ) { |
| b.setLocation( new Path( new File( l ).getAbsolutePath() ) ); |
| } |
| else { |
| 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( VersionTable.getVersion( 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 ); |
| } |
| } |
| } |
| } |