You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by og...@apache.org on 2009/04/23 00:57:04 UTC

svn commit: r767705 [19/31] - in /maven/mercury/trunk/mercury-core: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/maven/ src/main/java/org/apache/maven/mercury/ src/main/java/org/apache/maven/mer...

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java Wed Apr 22 22:56:48 2009
@@ -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.maven.mercury.spi.http.server;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.mortbay.jetty.HttpMethods;
+import org.mortbay.servlet.PutFilter;
+import org.mortbay.util.IO;
+import org.mortbay.util.URIUtil;
+
+/**
+ * BatchFilter
+ * <p/>
+ * Base class for handling atomic uploads of batches of files.
+ * Subclasses should implement their own means of making the
+ * uploads atomic. The methods putFile, commitFiles, discardFiles
+ * can be overridden/implemented in order to facilitate this.
+ * For example, the DefaultBatchFilter subclass copies all files
+ * to a staging area before moving them to their final locations
+ * upon receipt of a Jetty-Batch-Commit message.
+ * <p/>
+ * TODO consider having a scavenger thread to remove failed or incomplete uploads?
+ *
+ * @see org.sonatype.mercury.server.jetty.DefaultBatchFilter
+ */
+public abstract class BatchFilter extends PutFilter
+{
+    protected ConcurrentMap<String, Batch> _batches = new ConcurrentHashMap<String, Batch>();
+    protected String _batchIdHeader = "Jetty-Batch-Id";
+    protected String _batchSupportedHeader = "Jetty-Batch-Supported";
+    protected String _batchCommitHeader = "Jetty-Batch-Commit";
+    protected String _batchDiscardHeader = "Jetty-Batch-Discard";
+
+    /**
+     * Batch
+     * <p/>
+     * Retains the status of a mercury. If a mercury succeeds it is removed
+     * from the list. If it fails, then it is retained in the list
+     * but marked as failed. If a mercury is not completed, then the
+     * timestamp can be used by a timer thread to clean up.
+     */
+    protected class Batch
+    {
+        protected String _batchId;
+        protected long _timestamp;
+        protected boolean _ok;
+        protected List<String> _files;
+
+
+        public Batch( String batchId, long timestamp )
+        {
+            _batchId = batchId;
+            _timestamp = timestamp;
+            _files = new ArrayList<String>();
+        }
+
+        public String getBatchId()
+        {
+            return _batchId;
+        }
+
+        public void addFile( String file )
+        {
+            _files.add( file );
+        }
+
+        public List getFiles()
+        {
+            return _files;
+        }
+
+        public void failed()
+        {
+            _ok = false;
+        }
+
+        public boolean isOK()
+        {
+            return _ok;
+        }
+
+        public long getTimestamp()
+        {
+            return _timestamp;
+        }
+
+        public String toString()
+        {
+            return "BatchStatus: id=" + _batchId + " ts=" + _timestamp + " count=" + _files.size() + ", " + _ok;
+        }
+    }
+
+    /**
+     * Implement this method to finish the upload of the files by making them
+     * available for download. When this method returns, all files forming part of
+     * the mercury should be available.
+     *
+     * @param request
+     * @param response
+     * @param batchId
+     * @return
+     * @throws Exception
+     */
+    public abstract boolean commitFiles( HttpServletRequest request, HttpServletResponse response, Batch batch )
+        throws Exception;
+
+    /**
+     * Implement this method to abort the upload of a mercury of files. When this method returns,
+     * none of the files forming part of the upload should be available for download.
+     *
+     * @param request
+     * @param response
+     * @param batchId
+     * @return
+     * @throws Exception
+     */
+    public abstract boolean discardFiles( HttpServletRequest request, HttpServletResponse response, Batch batch )
+        throws Exception;
+
+
+    /**
+     * Initialize the filter. Read all configurable parameters.
+     *
+     * @see org.sonatype.servlet.PutFilter#init(javax.servlet.FilterConfig)
+     */
+    public void init( FilterConfig config )
+        throws ServletException
+    {
+        super.init( config );
+
+        //allow name of headers to be exchanged to be configured
+        String s = config.getInitParameter( "batchIdHeader" );
+        if ( s != null )
+        {
+            _batchIdHeader = s;
+        }
+        s = config.getInitParameter( "batchSupportedHeader" );
+        if ( s != null )
+        {
+            _batchSupportedHeader = s;
+        }
+        s = config.getInitParameter( "batchCommitHeader" );
+        if ( s != null )
+        {
+            _batchCommitHeader = s;
+        }
+        s = config.getInitParameter( "batchDiscardHeader" );
+        if ( s != null )
+        {
+            _batchDiscardHeader = s;
+        }
+    }
+
+
+    /**
+     * Run the filter.
+     *
+     * @see org.sonatype.servlet.PutFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
+     */
+    public void doFilter( ServletRequest req, ServletResponse res, FilterChain chain )
+        throws IOException, ServletException
+    {
+        HttpServletRequest request = (HttpServletRequest) req;
+        HttpServletResponse response = (HttpServletResponse) res;
+
+        //if GET fall through to filter chain
+        if ( request.getMethod().equals( HttpMethods.GET ) )
+        {
+            chain.doFilter( req, res );
+            return;
+        }
+
+
+        String batchId = request.getHeader( _batchIdHeader );
+        String commitId = request.getHeader( _batchCommitHeader );
+        String discardId = request.getHeader( _batchDiscardHeader );
+
+        //System.err.println("method="+request.getMethod()+" batchid="+batchId+" commitId="+commitId+" discardId="+discardId);
+
+        //we can't do  atomic batches, handle as a normal PUT
+        if ( batchId == null && commitId == null && discardId == null )
+        {
+            super.doFilter( req, res, chain );
+            return;
+        }
+
+        /* TODO Is it worth handling this situation? This would mean that a directory was sent as the url 
+         * along with a batchId. The cost is that the pathContext would be calculated twice in this case.
+         
+        if (pathInContext.endsWith("/"))
+        {
+            super.doFilter(req,res,chain); 
+            return;
+        }
+        */
+
+        if ( batchId != null )
+        {
+            handlePut( request, response, batchId );
+            return;
+        }
+
+        if ( discardId != null )
+        {
+            handleDiscard( request, response, discardId );
+            return;
+        }
+
+        if ( commitId != null )
+        {
+            handleCommit( request, response, commitId );
+            return;
+        }
+
+        //otherwise - shouldn't get here
+        chain.doFilter( req, res );
+    }
+
+    /**
+     * Handle a PUT request.
+     * <p/>
+     * The batchId is saved to a list of currently active batchIds so that
+     * all files forming part of the mercury can be committed or discarded as a
+     * whole later on.
+     * <p/>
+     * If a file already exists, then status 200 is returned; if the file
+     * did not previously exist, then status 201 is returned, otherwise
+     * a 403 is returned.
+     *
+     * @param request
+     * @param response
+     * @param batchId
+     * @throws ServletException
+     * @throws IOException
+     */
+    public void handlePut( HttpServletRequest request, HttpServletResponse response, String batchId )
+        throws ServletException, IOException
+    {
+        String servletPath = request.getServletPath();
+        String pathInfo = request.getPathInfo();
+        String pathInContext = URIUtil.addPaths( servletPath, pathInfo );
+        String finalResource = URIUtil.addPaths( _baseURI, pathInContext );
+        File finalFile = null;
+        try
+        {
+            finalFile = new File( new URI( finalResource ) );
+            boolean exists = finalFile.exists();
+
+            putFile( request, response, pathInContext, batchId );
+
+            Batch batch = addBatch( batchId, finalResource );
+
+            String contextPath = _context.getContextPath();
+            if ( contextPath.equals( "" ) )
+            {
+                contextPath = "/";
+            }
+            if ( !contextPath.endsWith( "/" ) )
+            {
+                contextPath += "/";
+            }
+            String commitBatchUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + contextPath;
+            response.setHeader( _batchSupportedHeader, commitBatchUrl );
+            response.setStatus( exists ? HttpServletResponse.SC_OK : HttpServletResponse.SC_CREATED );
+            response.flushBuffer();
+        }
+        catch ( Exception ex )
+        {
+            _context.log( ex.toString(), ex );
+            response.sendError( HttpServletResponse.SC_FORBIDDEN );
+        }
+    }
+
+    /**
+     * Client side wants us to discard all files in mercury.
+     *
+     * @param request
+     * @param response
+     * @param batchId
+     * @throws ServletException
+     * @throws IOException
+     */
+    public void handleDiscard( HttpServletRequest request, HttpServletResponse response, String batchId )
+        throws ServletException, IOException
+    {
+        boolean ok = true;
+        try
+        {
+            ok = discardFiles( request, response, _batches.get( batchId ) );
+            response.setStatus( ( ok ? HttpServletResponse.SC_OK : HttpServletResponse.SC_INTERNAL_SERVER_ERROR ) );
+            response.flushBuffer();
+        }
+        catch ( Exception ex )
+        {
+            _context.log( ex.toString(), ex );
+            response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
+        }
+        finally
+        {
+            updateBatch( batchId, ok );
+        }
+    }
+
+
+    /**
+     * Client side wants us to move files into final position.
+     *
+     * @param request
+     * @param response
+     * @param batchId
+     * @throws ServletException
+     * @throws IOException
+     */
+    public void handleCommit( HttpServletRequest request, HttpServletResponse response, String batchId )
+        throws ServletException, IOException
+    {
+        boolean ok = true;
+        try
+        {
+            ok = commitFiles( request, response, _batches.get( batchId ) );
+            response.setStatus( ( ok ? HttpServletResponse.SC_OK : HttpServletResponse.SC_INTERNAL_SERVER_ERROR ) );
+            response.flushBuffer();
+        }
+        catch ( Exception ex )
+        {
+            ex.printStackTrace();
+            _context.log( ex.toString(), ex );
+            response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
+        }
+        finally
+        {
+            updateBatch( batchId, ok );
+        }
+    }
+
+    /**
+     * Default behaviour is to put the file directly to it's final location.
+     * <p/>
+     * Subclasses can choose to override this method and put the file
+     * into a staging area first.
+     *
+     * @param request
+     * @param response
+     * @param pathInContext
+     * @param batchId
+     * @throws Exception
+     * @see org.sonatype.mercury.server.jetty.DefaultBatchFilter
+     */
+    public void putFile( HttpServletRequest request,
+                         HttpServletResponse response,
+                         String pathInContext,
+                         String batchId )
+        throws Exception
+    {
+        String finalResource = URIUtil.addPaths( _baseURI, pathInContext );
+        File finalFile = null;
+        finalFile = new File( new URI( finalResource ) );
+        File parent = finalFile.getParentFile();
+        parent.mkdirs();
+        int toRead = request.getContentLength();
+        InputStream in = request.getInputStream();
+        OutputStream out = new FileOutputStream( finalFile, false );
+        if ( toRead >= 0 )
+        {
+            IO.copy( in, out, toRead );
+        }
+        else
+        {
+            IO.copy( in, out );
+        }
+
+    }
+
+    /**
+     * Remember a mercury, or update the count of files in the mercury.
+     *
+     * @param batchId
+     */
+    protected Batch addBatch( String batchId, String file )
+    {
+        Batch status = (Batch) _batches.get( batchId );
+        long timestamp = System.currentTimeMillis();
+        if ( status == null )
+        {
+            status = new Batch( batchId, timestamp );
+            _batches.put( batchId, status );
+        }
+        status.addFile( file );
+        return status;
+    }
+
+
+    /**
+     * Update the status of the mercury.
+     *
+     * @param batchId
+     * @param ok      if true, the mercury job is removed from the list; otherwise it is marked as failed
+     */
+    protected void updateBatch( String batchId, boolean ok )
+    {
+        Batch status = (Batch) _batches.get( batchId );
+        if ( status == null )
+        {
+            _context.log( "Unknown mercury id to update: " + batchId );
+        }
+        else
+        {
+            if ( ok )
+            {
+                _batches.remove( batchId );
+            }
+            else
+            {
+                status.failed(); //mark as failed
+            }
+        }
+    }
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilterTest.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilterTest.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilterTest.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilterTest.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,238 @@
+/**
+ * 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.maven.mercury.spi.http.server;
+
+import java.io.File;
+import java.io.FileInputStream;
+
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.mortbay.jetty.servlet.DefaultServlet;
+import org.mortbay.jetty.servlet.FilterHolder;
+import org.mortbay.jetty.testing.HttpTester;
+import org.mortbay.jetty.testing.ServletTester;
+import org.mortbay.util.IO;
+
+public class BatchFilterTest extends TestCase
+{
+    File _baseDir;
+    File _stagingDir;
+    
+    ServletTester tester;
+    
+
+    public void setUp () throws Exception
+    {
+        _baseDir = File.createTempFile("testBatchFilter",null);
+        _baseDir.delete();
+        _baseDir.mkdir();
+        _baseDir.deleteOnExit();
+        assertTrue(_baseDir.isDirectory());
+        
+        _stagingDir = new File(System.getProperty("java.io.tmpdir"));
+
+        super.setUp();
+        tester=new ServletTester();
+        tester.setContextPath("/context");
+        tester.setResourceBase(_baseDir.getCanonicalPath());
+        tester.addServlet( DefaultServlet.class, "/");
+        FilterHolder holder = tester.addFilter( StagingBatchFilter.class,"/*",0);
+        holder.setInitParameter("stagingDirURI", _stagingDir.toURI().toString());
+        tester.start();
+        System.err.println("Set up tester, basedir="+tester.getResourceBase()+" exists?"+_baseDir.exists());
+        System.err.println("Set up tester, stagingdir="+_stagingDir.toURI().toString());
+    }
+    
+    protected void tearDown() throws Exception
+    {
+        super.tearDown();
+        tester.stop();
+        destroy(_baseDir);
+    }
+    
+    public void destroy (File f)
+    {
+        if (f == null)
+            return;
+        if (f.isDirectory())
+        {
+            File[] files = f.listFiles();
+            for (int i=0;files!=null && i<files.length; i++)
+            {
+                destroy (files[i]);
+            }  
+        }
+        f.delete(); 
+        f.deleteOnExit();
+    }
+
+    public void testHandlePutWithoutBatching() throws Exception
+    {
+        // generated and parsed test
+        HttpTester request = new HttpTester();
+        HttpTester response = new HttpTester();
+        
+        request.setMethod("PUT");
+        request.setVersion("HTTP/1.1");
+        request.setHeader("Host","tester");
+        request.setURI("/context/file.txt");
+        request.setHeader("Content-Type","text/plain");
+        String data0="Now is the time for all good men to come to the aid of the party";
+        request.setContent(data0);
+        response.parse(tester.getResponses(request.generate()));
+        assertTrue(response.getMethod()==null);
+        assertEquals(HttpServletResponse.SC_CREATED,response.getStatus());
+        
+        File file=new File(_baseDir,"file.txt");
+        assertTrue(file.exists());
+        assertEquals(data0,IO.toString(new FileInputStream(file)));
+    }
+    
+    public void testBatchingCommit() throws Exception
+    {
+        // generated and parsed test
+        HttpTester request = new HttpTester();
+        HttpTester response = new HttpTester();
+        
+        request.setMethod("PUT");
+        request.setVersion("HTTP/1.1");
+        request.setHeader("Host","tester");
+        request.setURI("/context/file1.txt");
+        request.setHeader("Content-Type","text/plain");
+        request.setHeader("Jetty-Batch-Id", "999999");
+        String data1="How Now BROWN COW!!!!";
+        request.setContent(data1);
+        response.parse(tester.getResponses(request.generate()));
+        assertTrue(response.getMethod()==null);
+        assertEquals(HttpServletResponse.SC_CREATED,response.getStatus());
+        
+        File batchDir = new File (_stagingDir, "999999");
+        File stagedFile = new File (batchDir, "file1.txt");
+        System.err.println("Checking existence of "+stagedFile.getCanonicalPath());
+        assertTrue(stagedFile.exists());
+        FileInputStream fis = new FileInputStream(stagedFile);
+        assertEquals(data1,IO.toString(fis));
+        fis.close();
+
+        request.setMethod("PUT");
+        request.setURI("/context/file2.txt");
+        request.setHeader("Content-Type","text/plain");
+        String data2="Blah blah blah Blah blah";
+        request.setHeader("Jetty-Batch-Id", "999999");
+        request.setContent(data2);
+        response.parse(tester.getResponses(request.generate()));
+        assertEquals(HttpServletResponse.SC_CREATED,response.getStatus());
+        
+        batchDir = new File (_stagingDir, "999999");
+        stagedFile = new File (batchDir, "file2.txt");
+        assertTrue(stagedFile.exists());
+        fis = new FileInputStream(stagedFile);
+        assertEquals(data2,IO.toString(fis));
+        fis.close();
+
+        // test POST commit
+        request = new HttpTester();
+        request.setMethod("POST");
+        request.setVersion("HTTP/1.1");
+        request.setHeader("Content-Type","text/plain");
+        request.setHeader("Host","tester");
+        request.setHeader("Jetty-Batch-Commit", "999999");
+        request.setURI("/context/");
+        response.parse(tester.getResponses(request.generate()));
+        assertTrue(response.getMethod()==null);
+        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+
+        File finalFile1 = new File(_baseDir, "file1.txt");
+        assertTrue(finalFile1.exists());
+        File finalFile2 = new File(_baseDir, "file2.txt");
+        assertTrue(finalFile2.exists());
+    }
+    
+    
+    public void testBatchingDiscard () 
+    throws Exception 
+    {
+        // generated and parsed test
+        HttpTester request = new HttpTester();
+        HttpTester response = new HttpTester();
+   
+        request.setMethod("PUT");
+        request.setVersion("HTTP/1.1");
+        request.setHeader("Host","tester");
+        request.setURI("/context/org/foo/file1.txt");
+        request.setHeader("Content-Type","text/plain");
+        request.setHeader("Jetty-Batch-Id", "999999");
+        String data1="How Now BROWN COW!!!!";
+        request.setContent(data1);
+        response.parse(tester.getResponses(request.generate()));
+        assertTrue(response.getMethod()==null);
+        assertEquals(HttpServletResponse.SC_CREATED,response.getStatus());
+        
+        File batchDir = new File (_stagingDir, "999999");
+        File stagedFile = new File(batchDir, "org");
+        stagedFile = new File(stagedFile, "foo");
+        stagedFile = new File (stagedFile, "file1.txt");
+        System.err.println("Checking existence of "+stagedFile.getCanonicalPath());
+        FileInputStream fis = new FileInputStream(stagedFile);
+        assertTrue(stagedFile.exists());
+        assertEquals(data1,IO.toString(fis));
+        fis.close();
+        
+        request.setMethod("PUT");
+        request.setVersion("HTTP/1.1");
+        request.setHeader("Host","tester");
+        request.setURI("/context/file2.txt");
+        request.setHeader("Content-Type","text/plain");
+        String data2="Blah blah blah Blah blah";
+        request.setHeader("Jetty-Batch-Id", "999999");
+        request.setContent(data2);
+        response.parse(tester.getResponses(request.generate()));
+        assertEquals(HttpServletResponse.SC_CREATED,response.getStatus());
+        
+        batchDir = new File (_stagingDir, "999999");
+        stagedFile = new File (batchDir, "file2.txt");
+        assertTrue(stagedFile.exists());
+        fis = new FileInputStream(stagedFile);
+        assertEquals(data2,IO.toString(fis));
+        fis.close();
+        
+        // test POST discard
+        request = new HttpTester();
+        request.setMethod("POST");
+        request.setVersion("HTTP/1.1");
+        request.setHeader("Content-Type","text/plain");
+        request.setHeader("Host","tester");
+        request.setHeader("Jetty-Batch-Discard", "999999");
+        request.setURI("/context/");
+        response.parse(tester.getResponses(request.generate()));
+        assertTrue(response.getMethod()==null);
+        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+
+        File finalFile1 = new File(_baseDir, "org");
+        finalFile1 = new File(finalFile1, "foo");
+        finalFile1 = new File(finalFile1, "file1.txt");
+        assertFalse(finalFile1.exists());
+        File finalFile2 = new File(_baseDir, "file2.txt");
+        assertFalse(finalFile2.exists());
+    }
+    
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilterTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/HttpTestServer.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/HttpTestServer.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/HttpTestServer.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/HttpTestServer.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,55 @@
+/**
+ * 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.maven.mercury.spi.http.server;
+
+import java.io.File;
+
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.DefaultHandler;
+import org.mortbay.jetty.handler.HandlerCollection;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.DefaultServlet;
+
+public class HttpTestServer
+    extends Server
+{
+    public HttpTestServer( File base, String remotePathFragment )
+        throws Exception
+    {
+        super( 0 );
+
+        System.out.println( base );
+        
+        if ( !base.exists() )
+        {
+            throw new IllegalArgumentException( "Specified base directory does not exist: " + base.getCanonicalPath() );
+        }
+        
+        HandlerCollection handlers = new HandlerCollection();
+        setHandler( handlers );
+
+        Context context = new Context( handlers, remotePathFragment );
+        handlers.addHandler( new DefaultHandler() );
+
+        context.addServlet( DefaultServlet.class, "/" );               
+        context.setResourceBase( base.getCanonicalPath() );
+    }
+
+    public int getPort()
+    {
+        return getConnectors()[0].getLocalPort();
+    }
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/HttpTestServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/HttpTestServer.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SecurePutServer.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SecurePutServer.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SecurePutServer.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SecurePutServer.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,88 @@
+/**
+ * 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.maven.mercury.spi.http.server;
+
+import java.io.File;
+
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.handler.DefaultHandler;
+import org.mortbay.jetty.handler.HandlerCollection;
+import org.mortbay.jetty.security.SslSocketConnector;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.DefaultServlet;
+import org.mortbay.jetty.servlet.FilterHolder;
+import org.mortbay.servlet.PutFilter;
+
+public class SecurePutServer extends SimplePutServer
+{
+    private File _base;
+    
+    public SecurePutServer() throws Exception
+    {       
+        SslSocketConnector connector = new SslSocketConnector();
+        String keystore = System.getProperty("user.dir") + File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator
+        + "secureServer" + File.separator + "keystore";
+
+        connector.setPort(0);
+        connector.setKeystore(keystore);
+        connector.setPassword("storepwd");
+        connector.setKeyPassword("keypwd");
+
+        setConnectors(new Connector[] { connector });        
+        
+        HandlerCollection handlers = new HandlerCollection();
+        setHandler(handlers);
+        
+        Context context = new Context(handlers,"/maven2/repo");
+        handlers.addHandler(new DefaultHandler());
+
+        _base = File.createTempFile("securePutServer",null);
+        _base.delete();
+        _base.mkdir();
+        _base.deleteOnExit();
+        FilterHolder holder = context.addFilter(PutFilter.class, "/*", 0);
+        holder.setInitParameter("delAllowed","true");
+        context.addServlet(DefaultServlet.class,"/");
+        context.setResourceBase(_base.getCanonicalPath());
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.maven.mercury.spi.http.server.PutServer#getPutDir()
+     */
+    public File getPutDir ()
+    {
+        return _base;
+    }
+    
+    public void destroy ()
+    {
+        super.destroy();
+        destroy(_base);
+    }
+    
+    public static void main(String[] args)
+    throws Exception
+    {
+        SecurePutServer server = new SecurePutServer();
+        server.start();
+        server.join();
+    }
+
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SecurePutServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SecurePutServer.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimplePutServer.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimplePutServer.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimplePutServer.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimplePutServer.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,127 @@
+/**
+ * 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.maven.mercury.spi.http.server;
+
+import java.io.File;
+
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.DefaultHandler;
+import org.mortbay.jetty.handler.HandlerCollection;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.DefaultServlet;
+import org.mortbay.jetty.servlet.FilterHolder;
+import org.mortbay.servlet.PutFilter;
+
+public class SimplePutServer extends Server
+{
+    protected File _base;
+    protected Context context;
+    
+    
+    public SimplePutServer()
+    throws Exception
+    {
+      this("/maven2/repo", null );
+    }
+    
+    /**
+     * @param string
+     * @param targetDirectory
+     */
+    public SimplePutServer( String contextPath, File targetDirectory )
+    throws Exception
+    {
+      super(0);
+
+      HandlerCollection handlers = new HandlerCollection();
+      setHandler(handlers);
+
+      context = new Context( handlers, contextPath );
+      handlers.addHandler(new DefaultHandler());
+
+      if( targetDirectory == null )
+      {
+        _base = File.createTempFile("simplePutServer",null);
+        _base.delete();
+        _base.mkdir();
+        _base.deleteOnExit();
+      }
+      else
+      {
+        _base = targetDirectory;
+      }
+      
+      if( _base == null || !_base.exists() || !_base.isDirectory() )
+        throw new Exception("File not appropriate for base directory: "+_base);
+
+      FilterHolder holder = context.addFilter(PutFilter.class, "/*", 0);
+      holder.setInitParameter("delAllowed","true");
+      context.addServlet(DefaultServlet.class,"/");
+      context.setResourceBase(_base.getCanonicalPath());
+    }
+
+    public void destroy ()
+    {
+        super.destroy();
+        destroy(_base);
+    }
+    
+    public void destroy (File f)
+    {
+        if (f == null)
+            return;
+        if (f.isDirectory())
+        {
+            File[] files = f.listFiles();
+            for (int i=0;files!=null && i<files.length; i++)
+            {
+                destroy (files[i]);
+            }  
+        }
+        f.delete(); 
+    }
+    
+  
+    
+    /* (non-Javadoc)
+     * @see org.apache.maven.mercury.spi.http.server.PutServer#getPutDir()
+     */
+    public File getPutDir ()
+    {
+        return _base;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.maven.mercury.spi.http.server.PutServer#getPort()
+     */
+    public int getPort()
+    {
+        return getConnectors()[0].getLocalPort();
+    }
+
+    public static void main(String[] args)
+    throws Exception
+    {
+        SimplePutServer server = new SimplePutServer();
+        server.start();
+        server.join();
+    }
+
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimplePutServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimplePutServer.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimpleTestServer.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimpleTestServer.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimpleTestServer.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimpleTestServer.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,148 @@
+/**
+ * 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.maven.mercury.spi.http.server;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.OutputStream;
+import java.net.URL;
+
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.DefaultHandler;
+import org.mortbay.jetty.handler.HandlerCollection;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.DefaultServlet;
+import org.mortbay.util.IO;
+
+public class SimpleTestServer
+    extends Server
+{
+  
+  final static String LOCAL_PATH = "/testRepo/";
+  final static String REMOTE_SEG = "/maven2/repo";
+  
+  File base;
+  Context context;
+    
+    public SimpleTestServer( int port )
+    throws Exception
+    {
+      this( port, LOCAL_PATH, REMOTE_SEG );
+    }
+    
+    public SimpleTestServer()
+    throws Exception
+    {
+      this( 0, LOCAL_PATH, REMOTE_SEG );
+    }
+
+    public SimpleTestServer( String localPathFragment, String remotePathFragment )
+    throws Exception
+    {
+      this( 0, localPathFragment, remotePathFragment );
+    }
+    
+    public SimpleTestServer( int port, String localPathFragment, String remotePathFragment )
+    throws Exception
+    {
+        super( port );
+
+        HandlerCollection handlers = new HandlerCollection();
+        setHandler( handlers );
+
+        context = new Context( handlers, remotePathFragment );
+        handlers.addHandler( new DefaultHandler() );
+
+        base = File.createTempFile( "simpleTestServer", "jetty" );
+        base.delete();
+        base.mkdir();
+        base.deleteOnExit();
+
+        URL list = SimpleTestServer.class.getResource( localPathFragment );
+        LineNumberReader in = new LineNumberReader( new InputStreamReader( list.openStream() ) );
+        String file = null;
+        while ( ( file = in.readLine() ) != null )
+        {
+            if ( !file.startsWith( "file" ) )
+            {
+                continue;
+            }
+            OutputStream out = new FileOutputStream( new File( base, file ) );
+            IO.copy( SimpleTestServer.class.getResource( localPathFragment + file ).openStream(), out );
+            out.close();
+        }
+        context.addServlet( DefaultServlet.class, "/" );
+        context.setResourceBase( base.getCanonicalPath() );
+    }
+
+    public SimpleTestServer( File localBase, String remotePathFragment )
+    throws Exception
+    {
+      this( 0, localBase, remotePathFragment ); 
+    }
+
+    public SimpleTestServer( int port, File localBase, String remotePathFragment )
+    throws Exception
+    {
+        super( port );
+
+        HandlerCollection handlers = new HandlerCollection();
+        setHandler( handlers );
+
+        context = new Context( handlers, remotePathFragment );
+        handlers.addHandler( new DefaultHandler() );
+
+        context.addServlet( DefaultServlet.class, "/" );
+        context.setResourceBase( localBase.getCanonicalPath() );
+    }
+
+    public int getPort()
+    {
+        return getConnectors()[0].getLocalPort();
+    }
+    
+    public void destroy()
+    {
+        super.destroy();
+        destroy(base);
+    }
+    
+    public void destroy (File f)
+    {
+        if (f == null)
+            return;
+        if (f.isDirectory())
+        {
+            File[] files = f.listFiles();
+            for (int i=0;files!=null && i<files.length; i++)
+            {
+                destroy (files[i]);
+            }  
+        }
+        f.delete(); 
+    }
+    
+
+    public static void main( String[] args )
+        throws Exception
+    {
+        SimpleTestServer server = new SimpleTestServer();
+        server.start();
+        server.join();
+    }
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimpleTestServer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/SimpleTestServer.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,236 @@
+/**
+ * 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.maven.mercury.spi.http.server;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.mortbay.util.IO;
+import org.mortbay.util.URIUtil;
+
+
+/**
+ * DefaultBatchFilter
+ * <p/>
+ * Handles the atomic upload (using PUT messages) of a batch of files. "Atomic" means
+ * that either all file uploads succeed or none do. This transactionality can only be
+ * guaranteed when using the mercury client, as a "commit/discard" message
+ * is sent from the client side to indicate how to terminate the mercury operation. If
+ * a commit is received, then all files that form part of the batch - indicated by a
+ * batch id in the PUT headers - are moved from a staging location to the final
+ * location. If a discard is received, then all files forming part of the mercury will
+ * be deleted. If the client side is not the jetty batcher, then the server side
+ * cannot know when the batch has ended, and therefore will immediately copy files
+ * to their final locations during the PUT.
+ */
+public class StagingBatchFilter extends BatchFilter
+{
+    private String _stagingDirURI;
+
+    public void init( FilterConfig config )
+        throws ServletException
+    {
+        super.init( config );
+
+        //allow tmp dir location to be configured
+        String t = config.getInitParameter( "stagingDirURI" );
+        if ( t != null )
+        {
+            _stagingDirURI = t;
+        }
+        else
+        {
+            //fall back to WEB-INF/lib
+            File f = new File( _context.getRealPath( "/" ) );
+            File w = new File( f, "WEB-INF" );
+            File l = new File( w, "lib" );
+            _stagingDirURI = l.toURI().toString();
+        }
+    }
+
+
+    /**
+     * Put the file to a staging area before doing move to final location
+     * on a commit.
+     *
+     * @see BatchFilter#putFile(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String, java.lang.String)
+     */
+    public void putFile( HttpServletRequest request,
+                         HttpServletResponse response,
+                         String pathInContext,
+                         String batchId )
+        throws Exception
+    {
+        String stagedResource = URIUtil.addPaths( _stagingDirURI,
+            batchId ); //put the file into staging dir under the batchid
+        stagedResource = URIUtil.addPaths( stagedResource, pathInContext );
+        File stagedFile = null;
+
+        try
+        {
+            stagedFile = new File( new URI( stagedResource ) );
+            File parent = stagedFile.getParentFile();
+            parent.mkdirs();
+
+            int toRead = request.getContentLength();
+            InputStream in = request.getInputStream();
+            OutputStream out = new FileOutputStream( stagedFile, false );
+            if ( toRead >= 0 )
+            {
+                IO.copy( in, out, toRead );
+            }
+            else
+            {
+                IO.copy( in, out );
+            }
+            out.close();
+        }
+        catch ( Exception e )
+        {
+            try
+            {
+                if ( stagedFile.exists() )
+                {
+                    stagedFile.delete();
+                }
+                throw e;
+            }
+            catch ( Exception ex )
+            {
+                _context.log( ex.toString(), ex );
+            }
+        }
+    }
+
+
+    /**
+     * Do the move of all files in mercury to a final location
+     *
+     * @see BatchFilter#commitFiles(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
+     */
+    public boolean commitFiles( HttpServletRequest request, HttpServletResponse response, Batch batch )
+        throws Exception
+    {
+        if ( batch == null )
+        {
+            return true; //nothing to do
+        }
+
+        boolean ok = true;
+        String stagedResource = URIUtil.addPaths( _stagingDirURI, batch.getBatchId() );
+        File batchDir = new File( new URI( stagedResource ) );
+        File[] files = batchDir.listFiles();
+        for ( int i = 0; files != null && i < files.length; i++ )
+        {
+            String name = files[i].getName();
+            File dest = new File( new URI( URIUtil.addPaths( _baseURI, name ) ) );
+            if ( !files[i].renameTo( dest ) )
+            {
+                ok = false;
+                _context.log("Unable to rename file "+files[i].getAbsolutePath()+" to "+dest.getAbsolutePath());
+            }
+        }
+        if ( ok )
+        {
+            ok = batchDir.delete();
+            if (!ok)
+                _context.log("Unable to delete batch dir "+batchDir.getAbsolutePath());
+        }
+        return ok;
+    }
+
+
+    /**
+     * Delete all files in the mercury from the staging area.
+     *
+     * @see BatchFilter#discardFiles(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
+     */
+    public boolean discardFiles( HttpServletRequest request, HttpServletResponse response, Batch batch )
+        throws Exception
+    {
+        if ( batch == null )
+        {
+            return true; //nothing to do
+        }
+
+        String stagedResource = URIUtil.addPaths( _stagingDirURI, batch.getBatchId() );
+        File batchDir = new File( new URI( stagedResource ) );
+        boolean ok = true;
+        if ( !deleteFile( batchDir ) )
+        {
+            ok = false;
+        }
+        return ok;
+    }
+
+
+    /**
+     * Recursively descend file hierarchy and delete all files.
+     *
+     * @param f
+     * @return
+     */
+    private boolean deleteFile( File f )
+    {
+        if ( f == null )
+        {
+            return true;
+        }
+        if ( f.isFile() )
+        {
+            boolean ok = f.delete();
+            if (!ok)
+                _context.log("Unable to delete file "+f.getAbsolutePath());
+            return ok;
+        }
+        else if ( f.isDirectory() )
+        {
+            File[] files = f.listFiles();
+            boolean ok = true;
+            for ( int i = 0; files != null && i < files.length; i++ )
+            {
+                if ( !deleteFile( files[i] ) )
+                {
+                    ok = false;
+                }
+            }
+
+            if ( !f.delete() )
+            {
+                ok = false;
+                _context.log("Unable to delete dir "+f.getAbsolutePath());
+            }
+
+            return ok;
+        }
+        else
+        {
+            return true;
+        }
+    }
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/FileUtilTest.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/FileUtilTest.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/FileUtilTest.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/FileUtilTest.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,420 @@
+/**
+ *  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.maven.mercury.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+
+import org.apache.maven.mercury.crypto.api.StreamObserverException;
+import org.apache.maven.mercury.crypto.api.StreamVerifierAttributes;
+import org.apache.maven.mercury.crypto.api.StreamVerifierException;
+import org.apache.maven.mercury.crypto.api.StreamVerifierFactory;
+import org.apache.maven.mercury.crypto.pgp.PgpStreamVerifierFactory;
+import org.apache.maven.mercury.crypto.sha.SHA1VerifierFactory;
+
+/**
+ *
+ *
+ * @author Oleg Gusakov
+ * @version $Id$
+ *
+ */
+public class FileUtilTest
+    extends TestCase
+{
+  public static final String SYSTEM_PARAMETER_SKIP_NIO_TESTS = "maven.mercury.tests.skip.nio";
+  boolean skipNioTests = Boolean.parseBoolean( System.getProperty( SYSTEM_PARAMETER_SKIP_NIO_TESTS, "true" ) );
+  
+  private static final String publicKeyFile = "/pgp/pubring.gpg";
+  private static final String secretKeyFile = "/pgp/secring.gpg";
+  private static final String keyId         = "0EDB5D91141BC4F2";
+  private static final String secretKeyPass = "testKey82";
+
+  private File testDir;
+  private File a;
+  private File b;
+  private File bAsc;
+  private File badAsc;
+
+  HashSet<StreamVerifierFactory> vFacs;
+  //----------------------------------------------------------------------------------------
+  @Override
+  protected void setUp()
+      throws Exception
+  {
+    testDir = new File("./target/test-classes");
+    a = new File( testDir, "a.jar" );
+    b = new File( testDir, "b.jar" );
+    bAsc = new File( testDir, "b.jar.asc" );
+    badAsc = new File( testDir, "bad.asc" );
+    
+    FileUtil.copy( a, b, true );
+    
+    vFacs = new HashSet<StreamVerifierFactory>(2);
+    
+    tearDown();
+  }
+  //----------------------------------------------------------------------------------------
+  @Override
+  protected void tearDown()
+      throws Exception
+  {
+    bAsc.delete();
+  }
+  //----------------------------------------------------------------------------------------
+  private void setPgp( boolean generator )
+  throws StreamVerifierException
+  {
+    if( generator )
+      vFacs.add( 
+          new PgpStreamVerifierFactory(
+              new StreamVerifierAttributes( PgpStreamVerifierFactory.DEFAULT_EXTENSION, false, true )
+              , getClass().getResourceAsStream( secretKeyFile )
+              , keyId
+              , secretKeyPass
+                                      )
+              );
+    else
+      vFacs.add( 
+          new PgpStreamVerifierFactory(
+              new StreamVerifierAttributes( PgpStreamVerifierFactory.DEFAULT_EXTENSION, false, true )
+              , getClass().getResourceAsStream( publicKeyFile )
+                                      )
+              );
+    
+  }
+  //----------------------------------------------------------------------------------------
+  private void setSha1( boolean generator )
+  {
+    vFacs.add( new SHA1VerifierFactory(false,false) );
+  }
+  //----------------------------------------------------------------------------------------
+  public void testVerifyGood()
+  throws IOException, StreamObserverException
+  {
+    setPgp( false );
+    FileUtil.verify( a, vFacs, false, true ); 
+  }
+  //----------------------------------------------------------------------------------------
+  public void testVerifyBad()
+  throws IOException, StreamObserverException
+  {
+    setPgp( false );
+    FileUtil.copy( badAsc, bAsc, true );
+
+    try
+    {
+      FileUtil.verify( b, vFacs, false, false ); 
+    }
+    catch( StreamObserverException e )
+    {
+      System.out.println( "Caught expected exception: "+e.getMessage() );
+      return;
+    }
+    fail( "Expected exception never thrown:"+StreamObserverException.class.getName() );
+  }
+  //----------------------------------------------------------------------------------------
+  public void testVerifyNoSigNoForce()
+  throws IOException, StreamObserverException
+  {
+    setPgp( false );
+    FileUtil.verify( b, vFacs, false, false ); 
+  }
+  //----------------------------------------------------------------------------------------
+  public void testVerifyNoSigForce()
+  throws IOException, StreamVerifierException
+  {
+    setPgp( false );
+    
+    try
+    {
+      FileUtil.verify( b, vFacs, false, true );
+    }
+    catch( StreamObserverException e )
+    {
+      System.out.println( "Caught expected exception: "+e.getMessage() );
+      return;
+    }
+    fail( "Expected exception never thrown:"+StreamObserverException.class.getName() );
+  }
+  //----------------------------------------------------------------------------------------
+  public void testSign()
+  throws IOException, StreamObserverException
+  {
+    setPgp( true );
+    FileUtil.sign( b, vFacs, false, true );
+
+    vFacs.clear();
+    setPgp( false );
+    FileUtil.verify( b, vFacs, false, true );
+  }
+  
+  //----------------------------------------------------------------------------------------
+  private static void say( String msg )
+  {
+    System.out.println(msg);
+    System.out.flush();
+  }
+  //----------------------------------------------------------------------------------------
+  public void testLock()
+  throws Exception
+  {
+    Ok th1ok = new Ok();
+    Ok th2ok = new Ok();
+    
+    class TestThread1
+    extends Thread
+    {
+      FileLockBundle lock;
+      String dir;
+      Ok ok;
+
+      public TestThread1( String dir, Ok ok )
+      {
+        this.dir = dir;
+        this.ok = ok;
+      }
+      @Override
+      public void run()
+      {
+        try
+        {
+          lock = FileUtil.lockDir( dir, 10L, 10L );
+          assertNotNull( lock );
+          say("Thread1: lock "+dir+" obtained");
+          
+          try { sleep( 2000L ); } catch( InterruptedException e ) {}
+          say("Thread1: slept for 2s");
+          
+          lock.release();
+          say("Thread1: lock "+dir+" released");
+          
+          ok.ok();
+        }
+        catch( Exception e )
+        {
+          fail( e.getMessage() );
+        }
+      }
+      
+    }
+    
+    class TestThread2
+    extends Thread
+    {
+      FileLockBundle lock;
+      String dir;
+      Ok ok;
+
+      public TestThread2( String dir, Ok ok )
+      {
+        this.dir = dir;
+        this.ok = ok;
+      }
+      @Override
+      public void run()
+      {
+        try
+        {
+          sleep(10l);
+          lock = FileUtil.lockDir( dir, 10L, 10L );
+          assertNull( lock );
+          say("Thread2: resource "+dir+" locked");
+          
+          lock = FileUtil.lockDir( dir, 5000L, 100L );
+          assertNotNull( lock );
+          
+          lock.release();
+          say("Thread2: lock "+dir+" released");
+          
+          ok.ok();
+        }
+        catch( Exception e )
+        {
+          fail( e.getMessage() );
+        }
+      }
+      
+    }
+    
+    File dir = File.createTempFile( "test-", "-dir" );
+    String dirName = dir.getAbsolutePath();
+    dir.delete();
+    dir = new File( dirName );
+    dir.mkdir();
+    dir.deleteOnExit();
+    
+    TestThread1 th1 = new TestThread1( dirName, th1ok );
+    TestThread2 th2 = new TestThread2( dirName, th2ok );
+    
+    th1.start();
+    th2.start();
+    
+    for(;;)
+      if( th1.isAlive() || th2.isAlive() )
+        Thread.sleep( 1000L );
+      else
+        break;
+    
+    
+    assertTrue( th1ok.isOk() );
+    
+    assertTrue( th2ok.isOk() );
+    
+    say("Multi-threaded test finished successfully");
+  }
+  //----------------------------------------------------------------------------------------
+  // TODO: 2008-10-06 Oleg: enable if switching to NIO locking between processes
+  public void notestLockNio()
+  throws Exception
+  {
+    Ok th1ok = new Ok();
+    Ok th2ok = new Ok();
+    
+    class TestThread1
+    extends Thread
+    {
+      FileLockBundle lock;
+      String dir;
+      Ok ok;
+
+      public TestThread1( String dir, Ok ok )
+      {
+        this.dir = dir;
+        this.ok = ok;
+      }
+      @Override
+      public void run()
+      {
+        try
+        {
+          lock = FileUtil.lockDirNio( dir, 10L, 10L );
+          say("NioThread1: got lock "+lock+" on "+dir+" obtained");
+
+          assertNotNull( lock );
+          say("NioThread1: lock "+dir+" obtained");
+          
+          try { sleep( 2000L ); } catch( InterruptedException e ) {}
+          say("NioThread1: slept for 2s");
+          
+          lock.release();
+          say("NioThread1: lock "+dir+" released");
+          
+          ok.ok();
+        }
+        catch( Exception e )
+        {
+          fail( e.getMessage() );
+        }
+      }
+      
+    }
+    
+    class TestThread2
+    extends Thread
+    {
+      FileLockBundle lock;
+      String dir;
+      Ok ok;
+
+      public TestThread2( String dir, Ok ok )
+      {
+        this.dir = dir;
+        this.ok = ok;
+      }
+      @Override
+      public void run()
+      {
+        try
+        {
+          sleep(10l);
+          lock = FileUtil.lockDirNio( dir, 10L, 10L );
+          say("NioThread2: got lock "+lock+" on "+dir+" obtained");
+
+          assertNull( lock );
+          
+          System.out.println("NioThread2: resource "+dir+" busy");
+          System.out.flush();
+          
+          lock = FileUtil.lockDirNio( dir, 5000L, 100L );
+          assertNotNull( lock );
+          
+          say("NioThread2: lock "+dir+" obtained");
+          
+          lock.release();
+          say("NioThread2: lock "+dir+" released");
+          
+          ok.ok();
+        }
+        catch( Exception e )
+        {
+          fail( e.getMessage() );
+        }
+      }
+      
+    }
+    
+    File dir = File.createTempFile( "test-", "-dir" );
+    String dirName = dir.getAbsolutePath();
+    dir.delete();
+    dir = new File( dirName );
+    dir.mkdir();
+    dir.deleteOnExit();
+    
+    TestThread1 th1 = new TestThread1( dirName, th1ok );
+    TestThread2 th2 = new TestThread2( dirName, th2ok );
+    
+    th1.start();
+    th2.start();
+    
+    for(;;)
+      if( th1.isAlive() || th2.isAlive() )
+        Thread.sleep( 1000L );
+      else
+        break;
+
+if(skipNioTests)
+  return;
+
+    assertTrue( th1ok.isOk() );
+    
+    assertTrue( th2ok.isOk() );
+    
+    say("Multi-threaded NIO test finished successfully");
+  }
+}
+
+
+class Ok
+{
+  boolean ok = false;
+  
+  public void ok()
+  {
+    ok = true;
+  }
+  
+  public boolean isOk()
+  {
+    return ok;
+  }
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/FileUtilTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/FileUtilTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/NioTest.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/NioTest.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/NioTest.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/NioTest.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,89 @@
+/**
+ *  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.maven.mercury.util;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ *
+ * @author Oleg Gusakov
+ * @version $Id$
+ *
+ */
+public class NioTest
+    extends TestCase
+{
+  
+  public void testNio()
+  {
+    boolean ok = false;
+    
+    try
+    {
+      File file = File.createTempFile( "test-nio-", "-file" );
+      file.deleteOnExit();
+      
+      String fn = file.getAbsolutePath();
+      
+      File f1 = new File( fn ); 
+      FileChannel c1 = new RandomAccessFile( f1, "rw").getChannel();
+  
+      FileLock l1 = c1.lock();
+      assertNotNull( "cannot obtain even the first lock", l1 );
+      
+      File f2 = new File( fn ); 
+      FileChannel c2 = new RandomAccessFile( f2, "rw").getChannel();
+      FileLock l2 = null;
+      try
+      {
+          l2 = c2.tryLock();
+          
+          if( l2 == null )
+            throw new OverlappingFileLockException();
+          
+          l2.release();
+      }
+      catch (OverlappingFileLockException e)
+      {
+          ok = true;
+      }
+  
+      l1.release();
+      c1.close();
+      c2.close();
+      
+      file.delete();
+
+if(false)      
+      assertTrue( "java.nio does not work !!", ok );
+    }
+    catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/NioTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/NioTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/TimeUtilTest.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/TimeUtilTest.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/TimeUtilTest.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/TimeUtilTest.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,74 @@
+/*
+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.maven.mercury.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ *
+ * @author Oleg Gusakov
+ * @version $Id$
+ *
+ */
+public class TimeUtilTest
+    extends TestCase
+{
+    long expected = 1234550304000L;
+
+    public void testSnTsWithDash()
+    throws Exception
+    {
+        long ts = TimeUtil.snTstoMillis( "20090213.183824-29" );
+        
+        assertEquals( expected, ts );
+    }
+
+    public void testSnTsWithoutDash()
+    throws Exception
+    {
+        long ts = TimeUtil.snTstoMillis( "20090213.183824" );
+        
+        assertEquals( expected, ts );
+    }
+    
+    public void testNow()
+    throws Exception
+    {
+        long now = System.currentTimeMillis();
+        
+        System.out.println( new Date(now) );
+        System.out.println( TimeUtil.defaultToSnTs( now ) );
+        
+        String name = "a-1.0-20090213.183824-90.jar";
+        
+        int lastDash = name.lastIndexOf( '-' );
+        int firstDash = name.lastIndexOf( '-', lastDash-1 );
+        String fTS = name.substring( firstDash+1, lastDash );
+        
+        System.out.println(fTS);
+
+    }
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/TimeUtilTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/TimeUtilTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/UtilTest.java
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/UtilTest.java?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/UtilTest.java (added)
+++ maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/UtilTest.java Wed Apr 22 22:56:48 2009
@@ -0,0 +1,48 @@
+/*
+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.maven.mercury.util;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ *
+ * @author Oleg Gusakov
+ * @version $Id$
+ *
+ */
+public class UtilTest
+    extends TestCase
+{
+    public void testConvertLength()
+    {
+        String s = Util.convertLength( 25L );
+        assertEquals( "25 bytes", s );
+        
+        s = Util.convertLength( 4999L );
+        assertEquals( "4999 bytes", s );
+        
+        s = Util.convertLength( 5800L );
+        assertEquals( "6 kb", s );
+        
+        s = Util.convertLength( 6400L );
+        assertEquals( "6 kb", s );
+    }
+}

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/UtilTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/java/org/apache/maven/mercury/util/UtilTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/resources/a.jar
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/a.jar?rev=767705&view=auto
==============================================================================
Binary file - no diff available.

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/a.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: maven/mercury/trunk/mercury-core/src/test/resources/a.jar.asc
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/a.jar.asc?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/a.jar.asc (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/a.jar.asc Wed Apr 22 22:56:48 2009
@@ -0,0 +1,7 @@
+-----BEGIN PGP SIGNATURE-----
+Version: BCPG v1.40
+
+iEYEABECAAYFAkivNOcACgkQDttdkRQbxPJuQgCfbLCJldGo59ggjxNyIbRbIqcs
+OrwAnih+uOC4Elw5UJ2Wekdjl37jJbak
+=i1JE
+-----END PGP SIGNATURE-----

Added: maven/mercury/trunk/mercury-core/src/test/resources/a.jar.sha1
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/a.jar.sha1?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/a.jar.sha1 (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/a.jar.sha1 Wed Apr 22 22:56:48 2009
@@ -0,0 +1 @@
+e1003a0a66dae77515259c5e591ea1cfd73c2859
\ No newline at end of file

Added: maven/mercury/trunk/mercury-core/src/test/resources/ant-1.6.5.jar
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/ant-1.6.5.jar?rev=767705&view=auto
==============================================================================
Binary file - no diff available.

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/ant-1.6.5.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: maven/mercury/trunk/mercury-core/src/test/resources/antlr-2.7.7.jar
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/antlr-2.7.7.jar?rev=767705&view=auto
==============================================================================
Binary file - no diff available.

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/antlr-2.7.7.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: maven/mercury/trunk/mercury-core/src/test/resources/bad.asc
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/bad.asc?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/bad.asc (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/bad.asc Wed Apr 22 22:56:48 2009
@@ -0,0 +1,7 @@
+-----BEGIN PGP SIGNATURE-----
+Version: BCPG v1.40
+
+iEYEABECAAYFAkivNOcACgkQDttdkRQbxPI6twCeI7VvcHQG6U3WZzIISSvB5sAY
+kcgAn2jHpt7cn7mYtjdjzusCCoz4N4rP
+=kmbj
+-----END PGP SIGNATURE-----

Added: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoMd/group-maven-metadata.xml
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoMd/group-maven-metadata.xml?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoMd/group-maven-metadata.xml (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoMd/group-maven-metadata.xml Wed Apr 22 22:56:48 2009
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+     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.
+
+-->
+<metadata>
+  <groupId>a</groupId>
+  <artifactId>a</artifactId>
+  <version>4</version>
+  <versioning>
+    <release>4</release>
+    <versions>
+      <version>1</version>
+      <version>2</version>
+      <version>3</version>
+      <version>4</version>
+     </versions>
+    <lastUpdated>20080424212921</lastUpdated>
+  </versioning>
+</metadata>
\ No newline at end of file

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoMd/group-maven-metadata.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoMd/group-maven-metadata.xml
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/1/a-1.pom
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/1/a-1.pom?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/1/a-1.pom (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/1/a-1.pom Wed Apr 22 22:56:48 2009
@@ -0,0 +1,19 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>a</groupId>
+  <artifactId>a</artifactId>
+  <version>1</version>
+
+  <dependencies>
+    <dependency>
+      <groupId>b</groupId>
+      <artifactId>b</artifactId>
+      <version>1</version>
+    </dependency>
+    <dependency>
+      <groupId>c</groupId>
+      <artifactId>c</artifactId>
+      <version>1</version>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/1/a-1.pom
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/1/a-1.pom
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/2/a-2.pom
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/2/a-2.pom?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/2/a-2.pom (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/2/a-2.pom Wed Apr 22 22:56:48 2009
@@ -0,0 +1,23 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>a</groupId>
+  <artifactId>a</artifactId>
+  <version>2</version>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>b</groupId>
+      <artifactId>b</artifactId>
+      <version>[1,2]</version>
+    </dependency>
+
+    <dependency>
+      <groupId>c</groupId>
+      <artifactId>c</artifactId>
+      <version>[2,3)</version>
+    </dependency>
+  </dependencies>
+
+
+</project>
\ No newline at end of file

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/2/a-2.pom
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/2/a-2.pom
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/3/a-3.pom
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/3/a-3.pom?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/3/a-3.pom (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/3/a-3.pom Wed Apr 22 22:56:48 2009
@@ -0,0 +1,19 @@
+<project>
+	<modelVersion>4.0.0</modelVersion>
+  <groupId>a</groupId>
+  <artifactId>a</artifactId>
+  <version>3</version>
+
+  <dependencies>
+    <dependency>
+      <groupId>b</groupId>
+      <artifactId>b</artifactId>
+      <version>2</version>
+    </dependency>
+    <dependency>
+      <groupId>c</groupId>
+      <artifactId>c</artifactId>
+      <version>(1,)</version>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/3/a-3.pom
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/3/a-3.pom
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/4/a-4.pom
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/4/a-4.pom?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/4/a-4.pom (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/4/a-4.pom Wed Apr 22 22:56:48 2009
@@ -0,0 +1,21 @@
+<project>
+	<modelVersion>3</modelVersion>
+  <groupId>a</groupId>
+  <artifactId>a</artifactId>
+  <version>4</version>
+
+  <dependencies>
+    <dependency>
+      <groupId>b</groupId>
+      <artifactId>b</artifactId>
+      <version>2</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>c</groupId>
+      <artifactId>c</artifactId>
+      <version>[2,3]</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/4/a-4.pom
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/4/a-4.pom
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/maven-metadata.xml
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/maven-metadata.xml?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/maven-metadata.xml (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/maven-metadata.xml Wed Apr 22 22:56:48 2009
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?><metadata>
+<!--
+
+     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.
+
+-->
+  <groupId>a</groupId>
+  <artifactId>a</artifactId>
+  <version>4</version>
+  <versioning>
+    <release>4</release>
+    <versions>
+      <version>1</version>
+      <version>2</version>
+      <version>3</version>
+      <version>4</version>
+     </versions>
+    <lastUpdated>20080424212921</lastUpdated>
+  </versioning>
+</metadata>
\ No newline at end of file

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/maven-metadata.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/a/a/maven-metadata.xml
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/1/b-1.pom
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/1/b-1.pom?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/1/b-1.pom (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/1/b-1.pom Wed Apr 22 22:56:48 2009
@@ -0,0 +1,6 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>b</groupId>
+  <artifactId>b</artifactId>
+  <version>1</version>
+</project>
\ No newline at end of file

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/1/b-1.pom
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/1/b-1.pom
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/2/b-2.pom
URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/2/b-2.pom?rev=767705&view=auto
==============================================================================
--- maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/2/b-2.pom (added)
+++ maven/mercury/trunk/mercury-core/src/test/resources/controlledRepoSat/b/b/2/b-2.pom Wed Apr 22 22:56:48 2009
@@ -0,0 +1,6 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>b</groupId>
+  <artifactId>b</artifactId>
+  <version>2</version>
+</project>
\ No newline at end of file