/* * 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.obrplugin; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.lang.reflect.Method; import java.net.URI; import java.util.regex.Pattern; import org.apache.felix.bundlerepository.Resource; import org.apache.felix.bundlerepository.impl.DataModelHelperImpl; import org.apache.felix.bundlerepository.impl.PullParser; import org.apache.felix.bundlerepository.impl.RepositoryImpl; import org.apache.felix.bundlerepository.impl.RepositoryParser; import org.apache.felix.bundlerepository.impl.ResourceImpl; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.logging.Log; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.FileUtils; import org.kxml2.io.KXmlParser; import org.xmlpull.v1.XmlPullParser; /** * this class parse the old repository.xml file build the bundle resource description and update the repository. * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class ObrUpdate { private static Pattern TIMESTAMP = Pattern.compile( "-[0-9]{8}\\.[0-9]{6}-[0-9]+" ); private static Method setURI; static { try { setURI = RepositoryImpl.class.getDeclaredMethod( "setURI", String.class ); setURI.setAccessible( true ); } catch ( Exception e ) { setURI = null; } } /** * logger for this plugin. */ private Log m_logger; /** * name and path to the repository descriptor file. */ private URI m_repositoryXml; /** * name and path to the obr.xml file. */ private URI m_obrXml; /** * maven project description. */ private MavenProject m_project; /** * user configuration information. */ private Config m_userConfig; /** * root on parent document. */ private RepositoryImpl m_repository; /** * used to store bundle information. */ private ResourceImpl m_resourceBundle; /** * base URI used to relativize bundle URIs. */ private URI m_baseURI; /** * initialize information. * @param repositoryXml path to the repository descriptor file * @param obrXml path and filename to the obr.xml file * @param project maven project description * @param mavenRepositoryPath path to the local maven repository * @param userConfig user information * @param logger plugin logger */ public ObrUpdate( URI repositoryXml, URI obrXml, MavenProject project, String mavenRepositoryPath, Config userConfig, Log logger ) { m_repositoryXml = repositoryXml; m_obrXml = obrXml; m_project = project; m_logger = logger; m_userConfig = userConfig; if ( userConfig.isRemoteFile() ) { m_baseURI = ObrUtils.toFileURI( mavenRepositoryPath ); } else { m_baseURI = m_repositoryXml; } } /** * update the repository descriptor file. parse the old repository descriptor file, * get the old reference of the bundle or determine the id for a new bundle, extract * information from bindex set the new information in descriptor file and save it. * * @param bundleJar path to the bundle jar file * @param sourceJar path to the source jar file * @param docJar path to the docs jar file * * @throws MojoExecutionException if the plugin failed */ public void updateRepository( URI bundleJar, URI sourceJar, URI docJar ) throws MojoExecutionException { m_logger.debug( " (f) repositoryXml = " + m_repositoryXml ); m_logger.debug( " (f) bundleJar = " + bundleJar ); m_logger.debug( " (f) sourceJar = " + sourceJar ); m_logger.debug( " (f) docJar = " + docJar ); m_logger.debug( " (f) obrXml = " + m_obrXml ); if ( m_repository == null ) { return; } // get the file size File bundleFile = new File( bundleJar ); if ( !bundleFile.exists() ) { String snapshot = TIMESTAMP.matcher( bundleFile.getName() ).replaceFirst( "-SNAPSHOT" ); bundleFile = new File( bundleFile.getParentFile(), snapshot ); } if ( bundleFile.exists() ) { URI resourceURI = m_userConfig.getRemoteBundle(); if ( null == resourceURI ) { resourceURI = bundleJar; if ( m_userConfig.isPathRelative() ) { resourceURI = ObrUtils.getRelativeURI( m_baseURI, resourceURI ); } } if ( m_userConfig.isRemoteFile() ) { m_logger.info( "Deploying " + resourceURI ); } else { m_logger.info( "Installing " + resourceURI ); } try { m_resourceBundle = ( ResourceImpl ) new DataModelHelperImpl().createResource( bundleFile.toURI().toURL() ); if ( m_resourceBundle == null ) { return; } } catch ( IOException e ) { throw new MojoExecutionException( "Unable to load resource information", e ); } m_resourceBundle.put( Resource.SIZE, String.valueOf( bundleFile.length() ) ); m_resourceBundle.put( Resource.URI, resourceURI.toASCIIString() ); } else { m_logger.error( "file doesn't exist: " + bundleJar ); return; } // parse the obr.xml file if ( m_obrXml != null ) { m_logger.info( "Adding " + m_obrXml ); // URL url = getClass().getResource("/SchemaObr.xsd"); // TODO validate obr.xml file // add contents to resource bundle parseObrXml(); } String sourcePath = relativisePath( sourceJar ); String docPath = relativisePath( docJar ); // m_resourceBundle.construct( m_project, bindexExtractor, sourcePath, docPath ); // TODO: rebuild wrt m_project m_repository.addResource( m_resourceBundle ); m_repository.setLastModified( System.currentTimeMillis() ); } private String relativisePath( URI uri ) { if ( null != uri ) { if ( m_userConfig.isPathRelative() ) { return ObrUtils.getRelativeURI( m_baseURI, uri ).toASCIIString(); } return uri.toASCIIString(); } return null; } public void writeRepositoryXml() throws MojoExecutionException { m_logger.info( "Writing OBR metadata" ); File file = null; Writer writer; try { file = File.createTempFile( "repository", ".xml" ); writer = new OutputStreamWriter( new FileOutputStream( file ) ); } catch ( IOException e ) { m_logger.error( "Unable to write to file: " + file.getName() ); e.printStackTrace(); throw new MojoExecutionException( "Unable to write to file: " + file.getName() + " : " + e.getMessage() ); } try { new DataModelHelperImpl().writeRepository( m_repository, writer ); } catch ( IOException e ) { throw new MojoExecutionException( "Unable to write repository xml", e ); } try { writer.flush(); writer.close(); File outputFile = new File( m_repositoryXml ); outputFile.getParentFile().mkdirs(); FileUtils.rename( file, outputFile ); } catch ( IOException e ) { e.printStackTrace(); throw new MojoExecutionException( "IOException" ); } } /** * Parse the repository descriptor file. * * @throws MojoExecutionException if the plugin failed */ public void parseRepositoryXml() throws MojoExecutionException { File fout = new File( m_repositoryXml ); if ( !fout.exists() ) { m_repository = new RepositoryImpl(); writeRepositoryXml(); } else { try { m_repository = ( RepositoryImpl ) new DataModelHelperImpl().repository( m_repositoryXml.toURL() ); if ( setURI != null ) { setURI.invoke( m_repository, ( String ) null ); } } catch ( Exception e ) { throw new MojoExecutionException( "Unable to read repository xml: " + m_repositoryXml, e ); } } } /** * put the information from obr.xml into ressourceBundle object. */ private void parseObrXml() throws MojoExecutionException { try { InputStream is = new FileInputStream( new File( m_obrXml ) ); try { KXmlParser kxp = new KXmlParser(); kxp.setInput( is, null ); kxp.nextTag(); // skip top level element kxp.nextTag(); // go to first child element parseObrXml( kxp ); } finally { is.close(); } } catch ( Exception e ) { throw new MojoExecutionException( "Unable to parse obr xml: " + m_obrXml, e ); } } private void parseObrXml( KXmlParser kxp ) throws Exception { PullParser parser = new PullParser(); while ( kxp.getEventType() == XmlPullParser.START_TAG ) { if ( RepositoryParser.CATEGORY.equals( kxp.getName() ) ) { m_resourceBundle.addCategory( parser.parseCategory( kxp ) ); } else if ( RepositoryParser.REQUIRE.equals( kxp.getName() ) ) { m_resourceBundle.addRequire( parser.parseRequire( kxp ) ); } else if ( RepositoryParser.CAPABILITY.equals( kxp.getName() ) ) { m_resourceBundle.addCapability( parser.parseCapability( kxp ) ); } else { kxp.nextTag(); parseObrXml( kxp ); } kxp.nextTag(); } } }