You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by mc...@apache.org on 2008/08/02 18:52:01 UTC

svn commit: r682012 - /felix/trunk/bundleplugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java

Author: mcculls
Date: Sat Aug  2 09:52:01 2008
New Revision: 682012

URL: http://svn.apache.org/viewvc?rev=682012&view=rev
Log:
FELIX-553: add bundle:remote-clean goal (use -DremoteOBR=http://... to specify repository prefix)

Added:
    felix/trunk/bundleplugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java   (with props)

Added: felix/trunk/bundleplugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java?rev=682012&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java (added)
+++ felix/trunk/bundleplugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java Sat Aug  2 09:52:01 2008
@@ -0,0 +1,453 @@
+/*
+ * 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.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+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.artifact.manager.WagonManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Settings;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Clean a remote repository file.
+ * It just looks for every resources and check that pointed file exists.
+ * 
+ * @requiresProject false
+ * @goal remote-clean
+ * @phase clean
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class ObrRemoteClean extends AbstractMojo
+{
+    /**
+     * When true, ignore remote locking.
+     * 
+     * @parameter expression="${ignoreLock}"
+     */
+    private boolean ignoreLock;
+    
+    /**
+     * Remote OBR Repository.
+     * 
+     * @parameter expression="${remoteOBR}" default-value="NONE"
+     */
+    private String remoteOBR;
+
+    /**
+     * Local OBR Repository.
+     * 
+     * @parameter expression="${obrRepository}"
+     */
+    private String obrRepository;
+
+    /**
+     * Project types which this plugin supports.
+     *
+     * @parameter
+     */
+    private List supportedProjectTypes = Arrays.asList( new String[]
+        { "jar", "bundle" } );
+
+    /**
+     * @parameter expression="${project.distributionManagementArtifactRepository}"
+     * @readonly
+     */
+    private ArtifactRepository deploymentRepository;
+
+    /**
+     * Alternative deployment repository. Format: id::layout::url
+     * 
+     * @parameter expression="${altDeploymentRepository}"
+     */
+    private String altDeploymentRepository;
+
+    /**
+     * The Maven project.
+     * 
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    private MavenProject project;
+
+    /**
+     * Local Maven settings.
+     * 
+     * @parameter expression="${settings}"
+     * @required
+     * @readonly
+     */
+    private Settings settings;
+
+    /**
+     * The Wagon manager.
+     * 
+     * @component
+     */
+    private WagonManager m_wagonManager;
+
+
+    public void execute() throws MojoExecutionException
+    {
+        String projectType = project.getPackaging();
+
+        // ignore unsupported project types, useful when bundleplugin is configured in parent pom
+        if ( !supportedProjectTypes.contains( projectType ) )
+        {
+            getLog().warn( "Ignoring project type " + projectType +
+                           " - supportedProjectTypes = " + supportedProjectTypes );
+            return;
+        }
+        else if ( "NONE".equalsIgnoreCase( remoteOBR ) || "false".equalsIgnoreCase( remoteOBR ) )
+        {
+            getLog().info( "Remote OBR update disabled (enable with -DremoteOBR)" );
+            return;
+        }
+
+        // if the user doesn't supply an explicit name for the remote OBR file, use the local name instead
+        if ( null == remoteOBR || remoteOBR.trim().length() == 0 || "true".equalsIgnoreCase( remoteOBR ) )
+        {
+            remoteOBR = obrRepository;
+        }
+
+        URI tempURI = ObrUtils.findRepositoryXml( "", remoteOBR );
+        String repositoryName = new File( tempURI.getSchemeSpecificPart() ).getName();
+
+        Log log = getLog();
+
+        RemoteFileManager remoteFile = new RemoteFileManager( m_wagonManager, settings, log );
+        openRepositoryConnection( remoteFile );
+
+        // ======== LOCK REMOTE OBR ========
+        log.info( "LOCK " + remoteFile + '/' + repositoryName );
+        remoteFile.lockFile( repositoryName, ignoreLock );
+        File downloadedRepositoryXml = null;
+
+        try
+        {
+            // ======== DOWNLOAD REMOTE OBR ========
+            log.info( "Downloading " + repositoryName );
+            downloadedRepositoryXml = remoteFile.get( repositoryName, ".xml" );
+
+            URI repositoryXml = downloadedRepositoryXml.toURI();
+            
+            Config userConfig = new Config();
+            userConfig.setRemoteFile( true );
+
+            // Clean the downloaded file.
+            Document doc = parseFile(new File(repositoryXml), initConstructor());
+            Node finalDocument = cleanDocument(tempURI, doc.getDocumentElement());
+            
+            if ( finalDocument == null )
+            {
+                getLog().info( "Nothing to clean in " + repositoryName);
+            }
+            else
+            {
+                writeToFile( repositoryXml, finalDocument ); // Write the new file
+                getLog().info( "Repository " + repositoryName + " cleaned" );
+                // ======== UPLOAD MODIFIED OBR ========
+                log.info( "Uploading " + repositoryName );
+                remoteFile.put( downloadedRepositoryXml, repositoryName );
+            }
+        }
+        catch ( Exception e )
+        {
+            log.warn( "Exception while updating remote OBR: " + e.getLocalizedMessage(), e );
+        }
+        finally
+        {
+            // ======== UNLOCK REMOTE OBR ========
+            log.info( "UNLOCK " + remoteFile + '/' + repositoryName );
+            remoteFile.unlockFile( repositoryName );
+            remoteFile.disconnect();
+
+            if ( null != downloadedRepositoryXml )
+            {
+                downloadedRepositoryXml.delete();
+            }
+        }
+    }
+
+    private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" );
+
+
+    private void openRepositoryConnection( RemoteFileManager remoteFile ) throws MojoExecutionException
+    {
+        if ( deploymentRepository == null && altDeploymentRepository == null )
+        {
+            String msg = "Deployment failed: repository element was not specified in the pom inside"
+                + " distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter";
+
+            throw new MojoExecutionException( msg );
+        }
+
+        if ( altDeploymentRepository != null )
+        {
+            getLog().info( "Using alternate deployment repository " + altDeploymentRepository );
+
+            Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepository );
+            if ( !matcher.matches() )
+            {
+                throw new MojoExecutionException( "Invalid syntax for alternative repository \""
+                    + altDeploymentRepository + "\". Use \"id::layout::url\"." );
+            }
+
+            remoteFile.connect( matcher.group( 1 ).trim(), matcher.group( 3 ).trim() );
+        }
+        else
+        {
+            remoteFile.connect( deploymentRepository.getId(), deploymentRepository.getUrl() );
+        }
+    }
+  
+    /**
+     * Analyze the given XML tree (DOM of the repository file) and remove missing resources.
+     * This method ask the user before deleting the resources from the repository.
+     * @param elem : the input XML tree
+     * @return the cleaned XML tree
+     */
+    private Element cleanDocument( URI prefix, Element elem )
+    {
+        NodeList nodes = elem.getElementsByTagName( "resource" );
+        List toRemove = new ArrayList();
+
+        // First, look for missing resources
+        for ( int i = 0; i < nodes.getLength(); i++ )
+        {
+            Element n = ( Element ) nodes.item( i );
+            String value = n.getAttribute( "uri" );
+
+            URL url;
+            try {
+                url = new URL(prefix.toURL(), value);
+            } catch (MalformedURLException e) {
+                getLog().error("Malformed URL when creating the resource absolute URI : " + e.getMessage());
+                return null;
+            }
+            
+            try {
+                url.openConnection().getContent();
+            } catch (IOException e) {
+                getLog().info(
+                              "The bundle " + n.getAttribute( "presentationname" ) + " - " + n.getAttribute( "version" )
+                                  + " will be removed : " + e.getMessage() );
+                          toRemove.add( n );
+            }
+        }
+
+        Date d = new Date();
+        if ( toRemove.size() > 0 )
+        {
+            System.out.println("Do you want to remove these bundles from the repository file [y/N]:");
+            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+            String answer = null;
+
+            try {
+               answer = br.readLine();
+            } catch (IOException ioe) {
+               getLog().error("IO error trying to read the user confirmation");
+               return null;
+            }
+            
+            if (answer != null && answer.trim().equalsIgnoreCase("y")) {
+                // Then remove missing resources.
+                for ( int i = 0; i < toRemove.size(); i++ )
+                {
+                    elem.removeChild( ( Node ) toRemove.get( i ) );
+                }
+
+                // If we have to remove resources, we need to update 'lastmodified' attribute
+                SimpleDateFormat format = new SimpleDateFormat( "yyyyMMddHHmmss.SSS" );
+                d.setTime( System.currentTimeMillis() );
+                elem.setAttribute( "lastmodified", format.format( d ) );
+                return elem;
+            } else {
+                return null;
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Initialize the document builder from Xerces.
+     * 
+     * @return DocumentBuilder ready to create new document
+     * @throws MojoExecutionException : occurs when the instantiation of the document builder fails
+     */
+    private DocumentBuilder initConstructor() throws MojoExecutionException
+    {
+        DocumentBuilder constructor = null;
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        try
+        {
+            constructor = factory.newDocumentBuilder();
+        }
+        catch ( ParserConfigurationException e )
+        {
+            getLog().error( "Unable to create a new xml document" );
+            throw new MojoExecutionException( "Cannot create the Document Builder : " + e.getMessage() );
+        }
+        return constructor;
+    }
+
+
+    /**
+     * Open an XML file.
+     * 
+     * @param filename : XML file path
+     * @param constructor DocumentBuilder get from xerces
+     * @return Document which describes this file
+     * @throws MojoExecutionException occurs when the given file cannot be opened or is a valid XML file.
+     */
+    private Document parseFile( File file, DocumentBuilder constructor ) throws MojoExecutionException
+    {
+        if ( constructor == null )
+        {
+            return null;
+        }
+        // The document is the root of the DOM tree.
+        File targetFile = file.getAbsoluteFile();
+        getLog().info( "Parsing " + targetFile );
+        Document doc = null;
+        try
+        {
+            doc = constructor.parse( targetFile );
+        }
+        catch ( SAXException e )
+        {
+            getLog().error( "Cannot parse " + targetFile + " : " + e.getMessage() );
+            throw new MojoExecutionException( "Cannot parse " + targetFile + " : " + e.getMessage() );
+        }
+        catch ( IOException e )
+        {
+            getLog().error( "Cannot open " + targetFile + " : " + e.getMessage() );
+            throw new MojoExecutionException( "Cannot open " + targetFile + " : " + e.getMessage() );
+        }
+        return doc;
+    }
+
+
+    /**
+     * 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 )
+        {
+            getLog().error( "Unable to write to file: " + outputFilename.toString() );
+            throw new MojoExecutionException( "Unable to write to file: " + outputFilename.toString() + " : "
+                + e.getMessage() );
+        }
+        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 );
+        FileOutputStream flux = null;
+        try
+        {
+            flux = new FileOutputStream( fichier );
+        }
+        catch ( FileNotFoundException e )
+        {
+            getLog().error( "Unable to write to file: " + fichier.getName() );
+            throw new MojoExecutionException( "Unable to write to file: " + fichier.getName() + " : " + e.getMessage() );
+        }
+        Result output = new StreamResult( flux );
+        try
+        {
+            transformer.transform( input, output );
+        }
+        catch ( TransformerException e )
+        {
+            throw new MojoExecutionException( "Unable to write to file: " + outputFilename.toString() + " : "
+                + e.getMessage() );
+        }
+
+        try
+        {
+            flux.flush();
+            flux.close();
+        }
+        catch ( IOException e )
+        {
+            throw new MojoExecutionException( "IOException when closing file : " + e.getMessage() );
+        }
+    }
+}

Propchange: felix/trunk/bundleplugin/src/main/java/org/apache/felix/obrplugin/ObrRemoteClean.java
------------------------------------------------------------------------------
    svn:eol-style = native