| /* |
| * 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.obr.plugin; |
| |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.net.URI; |
| import java.text.SimpleDateFormat; |
| import java.util.Date; |
| import java.util.Properties; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerConfigurationException; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.dom.DOMSource; |
| import javax.xml.transform.stream.StreamResult; |
| |
| import org.apache.maven.plugin.MojoExecutionException; |
| import org.apache.maven.plugin.logging.Log; |
| import org.apache.maven.project.MavenProject; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.SAXException; |
| |
| |
| /** |
| * 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 |
| { |
| /** |
| * generate the date format to insert it in repository descriptor file. |
| */ |
| static SimpleDateFormat m_format = new SimpleDateFormat( "yyyyMMddHHmmss.SSS" ); |
| |
| /** |
| * 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; |
| |
| /** |
| * name and path to the bundle jar file. |
| */ |
| private URI m_bundleJar; |
| |
| /** |
| * maven project description. |
| */ |
| private MavenProject m_project; |
| |
| /** |
| * user configuration information. |
| */ |
| private Config m_userConfig; |
| |
| /** |
| * used to build another xml document. |
| */ |
| private DocumentBuilder m_documentBuilder; |
| |
| /** |
| * root on parent document. |
| */ |
| private Document m_repositoryDoc; |
| |
| /** |
| * used to store bundle information. |
| */ |
| private ResourcesBundle 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 bundleJar path to the bundle jar file |
| * @param mavenRepositoryPath path to the local maven repository |
| * @param userConfig user information |
| * @param logger plugin logger |
| */ |
| public ObrUpdate( URI repositoryXml, URI obrXml, MavenProject project, URI bundleJar, String mavenRepositoryPath, |
| Config userConfig, Log logger ) |
| { |
| m_bundleJar = bundleJar; |
| m_repositoryXml = repositoryXml; |
| m_obrXml = obrXml; |
| m_project = project; |
| m_logger = logger; |
| |
| m_userConfig = userConfig; |
| |
| m_resourceBundle = new ResourcesBundle( logger ); |
| |
| 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. |
| * @throws MojoExecutionException if the plugin failed |
| */ |
| public void updateRepository() throws MojoExecutionException |
| { |
| m_logger.debug( " (f) repositoryXml = " + m_repositoryXml ); |
| m_logger.debug( " (f) bundleJar = " + m_bundleJar ); |
| m_logger.debug( " (f) obrXml = " + m_obrXml ); |
| |
| m_documentBuilder = initDocumentBuilder(); |
| |
| if ( m_documentBuilder == null ) |
| { |
| return; |
| } |
| |
| // get the file size |
| File bundleFile = new File( m_bundleJar ); |
| if ( bundleFile.exists() ) |
| { |
| URI resourceURI = m_userConfig.getRemoteBundle(); |
| if ( null == resourceURI ) |
| { |
| resourceURI = m_bundleJar; |
| if ( m_userConfig.isPathRelative() ) |
| { |
| resourceURI = ObrUtils.getRelativeURI( m_baseURI, resourceURI ); |
| } |
| } |
| |
| m_resourceBundle.setSize( String.valueOf( bundleFile.length() ) ); |
| m_resourceBundle.setUri( resourceURI.toASCIIString() ); |
| } |
| else |
| { |
| m_logger.error( "file doesn't exist: " + m_bundleJar ); |
| return; |
| } |
| |
| // parse repository |
| if ( parseRepositoryXml() == -1 ) |
| { |
| 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 |
| |
| Document obrXmlDoc = parseFile( m_obrXml, m_documentBuilder ); |
| if ( obrXmlDoc == null ) |
| { |
| return; |
| } |
| |
| Node obrXmlRoot = obrXmlDoc.getDocumentElement(); |
| |
| // add contents to resource bundle |
| sortObrXml( obrXmlRoot ); |
| } |
| |
| ExtractBindexInfo bindexExtractor; |
| try |
| { |
| // use bindex to extract bundle information |
| bindexExtractor = new ExtractBindexInfo( m_repositoryXml, m_bundleJar.getPath() ); |
| } |
| catch ( MojoExecutionException e ) |
| { |
| m_logger.error( "unable to build Bindex informations" ); |
| e.printStackTrace(); |
| |
| throw new MojoExecutionException( "BindexException" ); |
| } |
| |
| m_resourceBundle.construct( m_project, bindexExtractor ); |
| |
| Element rootElement = m_repositoryDoc.getDocumentElement(); |
| if ( !walkOnTree( rootElement ) ) |
| { |
| // the correct resource node was not found, we must create it |
| // we compute the new id |
| String id = m_resourceBundle.getId(); |
| searchRepository( rootElement, id ); |
| } |
| |
| // the repository.xml file have been modified, so we save it |
| m_logger.info( "Writing OBR metadata" ); |
| writeToFile( m_repositoryXml, rootElement ); |
| } |
| |
| |
| /** |
| * init the document builder from xerces. |
| * @return DocumentBuilder ready to create new document |
| */ |
| private DocumentBuilder initDocumentBuilder() |
| { |
| DocumentBuilder documentBuilder = null; |
| DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
| try |
| { |
| documentBuilder = factory.newDocumentBuilder(); |
| } |
| catch ( ParserConfigurationException e ) |
| { |
| m_logger.error( "unable to create a new xml document" ); |
| e.printStackTrace(); |
| } |
| return documentBuilder; |
| |
| } |
| |
| |
| /** |
| * Parse the repository descriptor file. |
| * |
| * @return 0 if the bundle is already in the descriptor, else -1 |
| * @throws MojoExecutionException if the plugin failed |
| */ |
| private int parseRepositoryXml() throws MojoExecutionException |
| { |
| |
| File fout = new File( m_repositoryXml ); |
| if ( !fout.exists() ) |
| { |
| Document doc = m_documentBuilder.newDocument(); |
| |
| // create xml tree |
| Date d = new Date(); |
| d.setTime( System.currentTimeMillis() ); |
| Element root = doc.createElement( "repository" ); |
| root.setAttribute( "lastmodified", m_format.format( d ) ); |
| root.setAttribute( "name", "MyRepository" ); |
| try |
| { |
| writeToFile( m_repositoryXml, root ); |
| } |
| catch ( MojoExecutionException e ) |
| { |
| e.printStackTrace(); |
| throw new MojoExecutionException( "IOException" ); |
| } |
| } |
| |
| // now we parse the repository.xml file |
| m_repositoryDoc = parseFile( m_repositoryXml, m_documentBuilder ); |
| if ( m_repositoryDoc == null ) |
| { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| /** |
| * transform a xml file to a xerces Document. |
| * @param filename path to the xml file |
| * @param documentBuilder DocumentBuilder get from xerces |
| * @return Document which describe this file |
| */ |
| private Document parseFile( URI filename, DocumentBuilder documentBuilder ) |
| { |
| if ( documentBuilder == null ) |
| { |
| return null; |
| } |
| // The document is the root of the DOM tree. |
| m_logger.info( "Parsing " + filename ); |
| Document doc = null; |
| try |
| { |
| doc = documentBuilder.parse( new File( filename ) ); |
| } |
| catch ( SAXException e ) |
| { |
| e.printStackTrace(); |
| return null; |
| } |
| catch ( IOException e ) |
| { |
| m_logger.error( "cannot open file: " + filename ); |
| e.printStackTrace(); |
| return null; |
| } |
| return doc; |
| } |
| |
| |
| /** |
| * put the information from obr.xml into ressourceBundle object. |
| * @param node Node to the OBR.xml file |
| */ |
| private void sortObrXml( Node node ) |
| { |
| if ( node.getNodeName().compareTo( "require" ) == 0 ) |
| { |
| Require newRequireNode = new Require(); |
| NamedNodeMap list = node.getAttributes(); |
| try |
| { |
| newRequireNode.setExtend( list.getNamedItem( "extend" ).getNodeValue() ); |
| newRequireNode.setMultiple( list.getNamedItem( "multiple" ).getNodeValue() ); |
| newRequireNode.setOptional( list.getNamedItem( "optional" ).getNodeValue() ); |
| newRequireNode.setFilter( list.getNamedItem( "filter" ).getNodeValue() ); |
| newRequireNode.setName( list.getNamedItem( "name" ).getNodeValue() ); |
| } |
| catch ( NullPointerException e ) |
| { |
| m_logger |
| .error( "the obr.xml file seems to be invalid in a \"require\" tag (one or more attributes are missing)" ); |
| // e.printStackTrace(); |
| } |
| newRequireNode.setValue( XmlHelper.getTextContent( node ) ); |
| m_resourceBundle.addRequire( newRequireNode ); |
| } |
| else if ( node.getNodeName().compareTo( "capability" ) == 0 ) |
| { |
| Capability newCapability = new Capability(); |
| try |
| { |
| newCapability.setName( node.getAttributes().getNamedItem( "name" ).getNodeValue() ); |
| } |
| catch ( NullPointerException e ) |
| { |
| m_logger.error( "attribute \"name\" is missing in obr.xml in a \"capability\" tag" ); |
| e.printStackTrace(); |
| } |
| NodeList list = node.getChildNodes(); |
| for ( int i = 0; i < list.getLength(); i++ ) |
| { |
| PElement p = new PElement(); |
| Node n = list.item( i ); |
| Node item = null; |
| // System.err.println(n.getNodeName()); |
| if ( n.getNodeName().compareTo( "p" ) == 0 ) |
| { |
| |
| p.setN( n.getAttributes().getNamedItem( "n" ).getNodeValue() ); |
| item = n.getAttributes().getNamedItem( "t" ); |
| if ( item != null ) |
| { |
| p.setT( item.getNodeValue() ); |
| } |
| item = n.getAttributes().getNamedItem( "v" ); |
| if ( item != null ) |
| { |
| p.setV( item.getNodeValue() ); |
| } |
| |
| newCapability.addP( p ); |
| } |
| } |
| m_resourceBundle.addCapability( newCapability ); |
| } |
| else if ( node.getNodeName().compareTo( "category" ) == 0 ) |
| { |
| Category newCategory = new Category(); |
| newCategory.setId( node.getAttributes().getNamedItem( "id" ).getNodeValue() ); |
| m_resourceBundle.addCategory( newCategory ); |
| } |
| else |
| { |
| NodeList list = node.getChildNodes(); |
| for ( int i = 0; i < list.getLength(); i++ ) |
| { |
| sortObrXml( list.item( i ) ); |
| } |
| } |
| } |
| |
| |
| /** |
| * write a Node in a xml file. |
| * @param outputFilename URI to the output file |
| * @param treeToBeWrite Node root of the tree to be write in file |
| * @throws MojoExecutionException if the plugin failed |
| */ |
| private void writeToFile( URI outputFilename, Node treeToBeWrite ) throws MojoExecutionException |
| { |
| // init the transformer |
| Transformer transformer = null; |
| TransformerFactory tfabrique = TransformerFactory.newInstance(); |
| try |
| { |
| transformer = tfabrique.newTransformer(); |
| } |
| catch ( TransformerConfigurationException e ) |
| { |
| m_logger.error( "Unable to write to file: " + outputFilename.toString() ); |
| e.printStackTrace(); |
| throw new MojoExecutionException( "TransformerConfigurationException" ); |
| } |
| Properties proprietes = new Properties(); |
| proprietes.put( "method", "xml" ); |
| proprietes.put( "version", "1.0" ); |
| proprietes.put( "encoding", "ISO-8859-1" ); |
| proprietes.put( "standalone", "yes" ); |
| proprietes.put( "indent", "yes" ); |
| proprietes.put( "omit-xml-declaration", "no" ); |
| transformer.setOutputProperties( proprietes ); |
| |
| DOMSource input = new DOMSource( treeToBeWrite ); |
| |
| File fichier = new File( outputFilename ); |
| fichier.getParentFile().mkdirs(); |
| FileOutputStream flux = null; |
| try |
| { |
| flux = new FileOutputStream( fichier ); |
| } |
| catch ( FileNotFoundException e ) |
| { |
| m_logger.error( "Unable to write to file: " + fichier.getName() ); |
| e.printStackTrace(); |
| throw new MojoExecutionException( "FileNotFoundException" ); |
| } |
| Result output = new StreamResult( flux ); |
| try |
| { |
| transformer.transform( input, output ); |
| } |
| catch ( TransformerException e ) |
| { |
| e.printStackTrace(); |
| throw new MojoExecutionException( "TransformerException" ); |
| } |
| |
| try |
| { |
| flux.flush(); |
| flux.close(); |
| } |
| catch ( IOException e ) |
| { |
| e.printStackTrace(); |
| throw new MojoExecutionException( "IOException" ); |
| } |
| |
| } |
| |
| |
| /** |
| * walk on the tree until the targeted node was found. |
| * @param node targeted node |
| * @return true if the requiered node was found else false. |
| */ |
| private boolean walkOnTree( Node node ) |
| { |
| |
| if ( node.getNodeName().compareTo( "resource" ) == 0 ) |
| { |
| return resource( node ); |
| } |
| |
| // look at the repository node (first in the file) |
| if ( node.getNodeName().compareTo( "repository" ) == 0 ) |
| { |
| Date d = new Date(); |
| d.setTime( System.currentTimeMillis() ); |
| NamedNodeMap nList = node.getAttributes(); |
| Node n = nList.getNamedItem( "lastmodified" ); |
| n.setNodeValue( m_format.format( d ) ); |
| } |
| |
| NodeList list = node.getChildNodes(); |
| if ( list.getLength() > 0 ) |
| { |
| for ( int i = 0; i < list.getLength(); i++ ) |
| { |
| if ( walkOnTree( list.item( i ) ) ) |
| { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| /** |
| * put the resource bundle in the tree. |
| * @param node Node on the xml file |
| * @param id id of the bundle ressource |
| */ |
| private void searchRepository( Node node, String id ) |
| { |
| if ( node.getNodeName().compareTo( "repository" ) == 0 ) |
| { |
| node.appendChild( m_resourceBundle.getNode( m_repositoryDoc ) ); |
| return; |
| } |
| |
| m_logger.info( "Second branch..." ); |
| NodeList list = node.getChildNodes(); |
| if ( list.getLength() > 0 ) |
| { |
| for ( int i = 0; i < list.getLength(); i++ ) |
| { |
| searchRepository( list.item( i ), id ); |
| } |
| } |
| } |
| |
| |
| /** |
| * compare two node and update the array which compute the smallest free id. |
| * @param node : node |
| * @return true if the node is the same bundle than the ressourceBundle, else false. |
| */ |
| private boolean resource( Node node ) |
| { |
| |
| // this part save all the id free if we need to add resource |
| String id = node.getAttributes().getNamedItem( "id" ).getNodeValue(); |
| NamedNodeMap map = node.getAttributes(); |
| |
| if ( m_resourceBundle.isSameBundleResource( map.getNamedItem( "symbolicname" ).getNodeValue(), map |
| .getNamedItem( "version" ).getNodeValue() ) ) |
| { |
| m_resourceBundle.setId( String.valueOf( id ) ); |
| node.getParentNode().replaceChild( m_resourceBundle.getNode( m_repositoryDoc ), node ); |
| return true; |
| } |
| return false; |
| } |
| } |