Author: ogusakov Date: Fri Jan 16 21:58:27 2009 New Revision: 735233 URL: http://svn.apache.org/viewvc?rev=735233&view=rev Log: intermediate changes to get rid of jetty server dependency
Added: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HttpServletResponse.java (with props) maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java (with props) maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java (with props) Removed: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/server/ Modified: maven/mercury/trunk/mercury-ant/mercury-ant-tasks/pom.xml maven/mercury/trunk/mercury-ant/pom.xml maven/mercury/trunk/mercury-it/pom.xml maven/mercury/trunk/mercury-transport/mercury-transport-http/pom.xml maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java maven/mercury/trunk/pom.xml Modified: maven/mercury/trunk/mercury-ant/mercury-ant-tasks/pom.xml URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-ant/mercury-ant-tasks/pom.xml?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/mercury-ant/mercury-ant-tasks/pom.xml (original) +++ maven/mercury/trunk/mercury-ant/mercury-ant-tasks/pom.xml Fri Jan 16 21:58:27 2009 @@ -77,6 +77,11 @@ </dependency> <!-- Maven dependencies --> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.apache.maven</groupId> @@ -86,7 +91,7 @@ <dependency> <groupId>org.apache.maven.mercury</groupId> <artifactId>mercury-transport-http</artifactId> - <classifier>tests</classifier> + <type>test-jar</type> <scope>test</scope> </dependency> Modified: maven/mercury/trunk/mercury-ant/pom.xml URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-ant/pom.xml?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/mercury-ant/pom.xml (original) +++ maven/mercury/trunk/mercury-ant/pom.xml Fri Jan 16 21:58:27 2009 @@ -112,6 +112,7 @@ <maven.version>3.0-SNAPSHOT</maven.version> <junit.version>3.8.2</junit.version> + <jetty.version>6.1-SNAPSHOT</jetty.version> <java.version>1.5</java.version> @@ -200,9 +201,16 @@ </dependency> <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty</artifactId> + <version>${jetty.version}</version> + <scope>test</scope> + </dependency> + + <dependency> <groupId>org.apache.maven.mercury</groupId> <artifactId>mercury-transport-http</artifactId> - <classifier>tests</classifier> + <type>test-jar</type> <version>${mercury.version}</version> <scope>test</scope> </dependency> @@ -230,6 +238,14 @@ <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> + + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty</artifactId> + <version>${jetty.version}</version> + <scope>test</scope> + </dependency> + </dependencies> <build> Modified: maven/mercury/trunk/mercury-it/pom.xml URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-it/pom.xml?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/mercury-it/pom.xml (original) +++ maven/mercury/trunk/mercury-it/pom.xml Fri Jan 16 21:58:27 2009 @@ -185,6 +185,7 @@ <dependency> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-client</artifactId> + <classifier>assembly</classifier> </dependency> <dependency> Modified: maven/mercury/trunk/mercury-transport/mercury-transport-http/pom.xml URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-transport/mercury-transport-http/pom.xml?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/mercury-transport/mercury-transport-http/pom.xml (original) +++ maven/mercury/trunk/mercury-transport/mercury-transport-http/pom.xml Fri Jan 16 21:58:27 2009 @@ -32,16 +32,44 @@ <description /> <dependencies> + <dependency> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-client</artifactId> + <classifier>assembly</classifier> + <exclusions> + <exclusion> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty</artifactId> + </exclusion> + <exclusion> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-sslengine</artifactId> + </exclusion> + <exclusion> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-util</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>org.mortbay.jetty</groupId> - <artifactId>servlet-api-2.5</artifactId> + <artifactId>jetty-util5</artifactId> + </dependency> + + +<!-- + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-client</artifactId> </dependency> + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>servlet-api-2.5</artifactId> + </dependency> +--> <!-- Test Dependencies --> <dependency> <groupId>org.mortbay.jetty</groupId> Modified: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java (original) +++ maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HandshakeExchange.java Fri Jan 16 21:58:27 2009 @@ -21,7 +21,7 @@ import java.util.Map; -import javax.servlet.http.HttpServletResponse; +import org.apache.maven.mercury.spi.http.client.HttpServletResponse; import org.mortbay.io.Buffer; import org.mortbay.jetty.client.HttpClient; Added: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HttpServletResponse.java URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HttpServletResponse.java?rev=735233&view=auto ============================================================================== --- maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HttpServletResponse.java (added) +++ maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HttpServletResponse.java Fri Jan 16 21:58:27 2009 @@ -0,0 +1,344 @@ +/* +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.client; + +/** + * + * + * @author Oleg Gusakov + * @version $Id$ + * + */ +public interface HttpServletResponse +{ + + /* + * Server status codes; see RFC 2068. + */ + + /** + * Status code (100) indicating the client can continue. + */ + + public static final int SC_CONTINUE = 100; + + + /** + * Status code (101) indicating the server is switching protocols + * according to Upgrade header. + */ + + public static final int SC_SWITCHING_PROTOCOLS = 101; + + /** + * Status code (200) indicating the request succeeded normally. + */ + + public static final int SC_OK = 200; + + /** + * Status code (201) indicating the request succeeded and created + * a new resource on the server. + */ + + public static final int SC_CREATED = 201; + + /** + * Status code (202) indicating that a request was accepted for + * processing, but was not completed. + */ + + public static final int SC_ACCEPTED = 202; + + /** + * Status code (203) indicating that the meta information presented + * by the client did not originate from the server. + */ + + public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; + + /** + * Status code (204) indicating that the request succeeded but that + * there was no new information to return. + */ + + public static final int SC_NO_CONTENT = 204; + + /** + * Status code (205) indicating that the agent <em>SHOULD</em> reset + * the document view which caused the request to be sent. + */ + + public static final int SC_RESET_CONTENT = 205; + + /** + * Status code (206) indicating that the server has fulfilled + * the partial GET request for the resource. + */ + + public static final int SC_PARTIAL_CONTENT = 206; + + /** + * Status code (300) indicating that the requested resource + * corresponds to any one of a set of representations, each with + * its own specific location. + */ + + public static final int SC_MULTIPLE_CHOICES = 300; + + /** + * Status code (301) indicating that the resource has permanently + * moved to a new location, and that future references should use a + * new URI with their requests. + */ + + public static final int SC_MOVED_PERMANENTLY = 301; + + /** + * Status code (302) indicating that the resource has temporarily + * moved to another location, but that future references should + * still use the original URI to access the resource. + * + * This definition is being retained for backwards compatibility. + * SC_FOUND is now the preferred definition. + */ + + public static final int SC_MOVED_TEMPORARILY = 302; + + /** + * Status code (302) indicating that the resource reside + * temporarily under a different URI. Since the redirection might + * be altered on occasion, the client should continue to use the + * Request-URI for future requests.(HTTP/1.1) To represent the + * status code (302), it is recommended to use this variable. + */ + + public static final int SC_FOUND = 302; + + /** + * Status code (303) indicating that the response to the request + * can be found under a different URI. + */ + + public static final int SC_SEE_OTHER = 303; + + /** + * Status code (304) indicating that a conditional GET operation + * found that the resource was available and not modified. + */ + + public static final int SC_NOT_MODIFIED = 304; + + /** + * Status code (305) indicating that the requested resource + * <em>MUST</em> be accessed through the proxy given by the + * <code><em>Location</em></code> field. + */ + + public static final int SC_USE_PROXY = 305; + + /** + * Status code (307) indicating that the requested resource + * resides temporarily under a different URI. The temporary URI + * <em>SHOULD</em> be given by the <code><em>Location</em></code> + * field in the response. + */ + + public static final int SC_TEMPORARY_REDIRECT = 307; + + /** + * Status code (400) indicating the request sent by the client was + * syntactically incorrect. + */ + + public static final int SC_BAD_REQUEST = 400; + + /** + * Status code (401) indicating that the request requires HTTP + * authentication. + */ + + public static final int SC_UNAUTHORIZED = 401; + + /** + * Status code (402) reserved for future use. + */ + + public static final int SC_PAYMENT_REQUIRED = 402; + + /** + * Status code (403) indicating the server understood the request + * but refused to fulfill it. + */ + + public static final int SC_FORBIDDEN = 403; + + /** + * Status code (404) indicating that the requested resource is not + * available. + */ + + public static final int SC_NOT_FOUND = 404; + + /** + * Status code (405) indicating that the method specified in the + * <code><em>Request-Line</em></code> is not allowed for the resource + * identified by the <code><em>Request-URI</em></code>. + */ + + public static final int SC_METHOD_NOT_ALLOWED = 405; + + /** + * Status code (406) indicating that the resource identified by the + * request is only capable of generating response entities which have + * content characteristics not acceptable according to the accept + * headers sent in the request. + */ + + public static final int SC_NOT_ACCEPTABLE = 406; + + /** + * Status code (407) indicating that the client <em>MUST</em> first + * authenticate itself with the proxy. + */ + + public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; + + /** + * Status code (408) indicating that the client did not produce a + * request within the time that the server was prepared to wait. + */ + + public static final int SC_REQUEST_TIMEOUT = 408; + + /** + * Status code (409) indicating that the request could not be + * completed due to a conflict with the current state of the + * resource. + */ + + public static final int SC_CONFLICT = 409; + + /** + * Status code (410) indicating that the resource is no longer + * available at the server and no forwarding address is known. + * This condition <em>SHOULD</em> be considered permanent. + */ + + public static final int SC_GONE = 410; + + /** + * Status code (411) indicating that the request cannot be handled + * without a defined <code><em>Content-Length</em></code>. + */ + + public static final int SC_LENGTH_REQUIRED = 411; + + /** + * Status code (412) indicating that the precondition given in one + * or more of the request-header fields evaluated to false when it + * was tested on the server. + */ + + public static final int SC_PRECONDITION_FAILED = 412; + + /** + * Status code (413) indicating that the server is refusing to process + * the request because the request entity is larger than the server is + * willing or able to process. + */ + + public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413; + + /** + * Status code (414) indicating that the server is refusing to service + * the request because the <code><em>Request-URI</em></code> is longer + * than the server is willing to interpret. + */ + + public static final int SC_REQUEST_URI_TOO_LONG = 414; + + /** + * Status code (415) indicating that the server is refusing to service + * the request because the entity of the request is in a format not + * supported by the requested resource for the requested method. + */ + + public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; + + /** + * Status code (416) indicating that the server cannot serve the + * requested byte range. + */ + + public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; + + /** + * Status code (417) indicating that the server could not meet the + * expectation given in the Expect request header. + */ + + public static final int SC_EXPECTATION_FAILED = 417; + + /** + * Status code (500) indicating an error inside the HTTP server + * which prevented it from fulfilling the request. + */ + + public static final int SC_INTERNAL_SERVER_ERROR = 500; + + /** + * Status code (501) indicating the HTTP server does not support + * the functionality needed to fulfill the request. + */ + + public static final int SC_NOT_IMPLEMENTED = 501; + + /** + * Status code (502) indicating that the HTTP server received an + * invalid response from a server it consulted when acting as a + * proxy or gateway. + */ + + public static final int SC_BAD_GATEWAY = 502; + + /** + * Status code (503) indicating that the HTTP server is + * temporarily overloaded, and unable to handle the request. + */ + + public static final int SC_SERVICE_UNAVAILABLE = 503; + + /** + * Status code (504) indicating that the server did not receive + * a timely response from the upstream server while acting as + * a gateway or proxy. + */ + + public static final int SC_GATEWAY_TIMEOUT = 504; + + /** + * Status code (505) indicating that the server does not support + * or refuses to support the HTTP protocol version that was used + * in the request message. + */ + + public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; +} Propchange: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HttpServletResponse.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/HttpServletResponse.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java (original) +++ maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java Fri Jan 16 21:58:27 2009 @@ -27,7 +27,7 @@ import java.util.HashSet; import java.util.Set; -import javax.servlet.http.HttpServletResponse; +import org.apache.maven.mercury.spi.http.client.HttpServletResponse; import org.apache.maven.mercury.crypto.api.StreamObserver; import org.apache.maven.mercury.logging.IMercuryLogger; Modified: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java (original) +++ maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java Fri Jan 16 21:58:27 2009 @@ -28,7 +28,7 @@ import java.util.HashSet; import java.util.Set; -import javax.servlet.http.HttpServletResponse; +import org.apache.maven.mercury.spi.http.client.HttpServletResponse; import org.apache.maven.mercury.crypto.api.StreamObserver; import org.apache.maven.mercury.logging.IMercuryLogger; Modified: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java (original) +++ maven/mercury/trunk/mercury-transport/mercury-transport-http/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java Fri Jan 16 21:58:27 2009 @@ -30,7 +30,7 @@ import java.util.Map; import java.util.Set; -import javax.servlet.http.HttpServletResponse; +import org.apache.maven.mercury.spi.http.client.HttpServletResponse; import org.apache.maven.mercury.crypto.api.StreamObserver; import org.apache.maven.mercury.crypto.api.StreamVerifier; Added: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java?rev=735233&view=auto ============================================================================== --- maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java (added) +++ maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java Fri Jan 16 21:58:27 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-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/BatchFilter.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Added: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java URL: http://svn.apache.org/viewvc/maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java?rev=735233&view=auto ============================================================================== --- maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java (added) +++ maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java Fri Jan 16 21:58:27 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-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: maven/mercury/trunk/mercury-transport/mercury-transport-http/src/test/java/org/apache/maven/mercury/spi/http/server/StagingBatchFilter.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: maven/mercury/trunk/pom.xml URL: http://svn.apache.org/viewvc/maven/mercury/trunk/pom.xml?rev=735233&r1=735232&r2=735233&view=diff ============================================================================== --- maven/mercury/trunk/pom.xml (original) +++ maven/mercury/trunk/pom.xml Fri Jan 16 21:58:27 2009 @@ -66,8 +66,38 @@ <module>mercury-plexus</module> <module>mercury-wagon</module> </modules> + + <properties> + <plexus.appbooter.version>1.4</plexus.appbooter.version> + <plexus.container.version>1.0-beta-3.0.1</plexus.container.version> + <plexus.component.annotations.version>1.0-beta-3.0.1</plexus.component.annotations.version> + <classworlds.version>1.3</classworlds.version> + <plexus.utils.version>1.5.5</plexus.utils.version> + <plexus.lang.version>1.1</plexus.lang.version> + <plexus.component.metadata.version>1.0-beta-3.0.1</plexus.component.metadata.version> + + <commons.digester.version>1.8</commons.digester.version> + <commons.cli.version>1.1</commons.cli.version> + + <jetty.version>6.1-SNAPSHOT</jetty.version> + <junit.version>3.8.1</junit.version> + <bouncy.castle.version>140</bouncy.castle.version> + <sat4j.version>2.0.4</sat4j.version> + + <!-- mercury-wagon --> + <wagon.provider.api.version>1.0-beta-4</wagon.provider.api.version> + + <distMgmtReleasesId>apache.releases</distMgmtReleasesId> + <distMgmtReleasesName>Apache Releases</distMgmtReleasesName> + <distMgmtReleasesUrl>scp://people.apache.org/www/people.apache.org/repo/m2-release-repository</distMgmtReleasesUrl> - <scm> + <distMgmtSnapshotsId>apache.snapshots</distMgmtSnapshotsId> + <distMgmtSnapshotsName>Apache Snapshots</distMgmtSnapshotsName> + <distMgmtSnapshotsUrl>scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository</distMgmtSnapshotsUrl> + </properties> + + + <scm> <connection>scm:svn:http://svn.apache.org/repos/asf/maven/mercury/trunk/</connection> <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/mercury/trunk/</developerConnection> <url>http://svn.apache.org/viewvc/maven/mercury/trunk/</url> @@ -138,7 +168,7 @@ <artifactId>plexus-forked-app-booter</artifactId> <version>${plexus.appbooter.version}</version> </dependency> - +<!-- <dependency> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-client</artifactId> @@ -156,6 +186,52 @@ <artifactId>jetty-servlet-tester</artifactId> <version>${jetty.version}</version> </dependency> +--> + + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-client</artifactId> + <classifier>assembly</classifier> + <version>6.1-SNAPSHOT</version> + <exclusions> + <exclusion> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty</artifactId> + </exclusion> + <exclusion> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-sslengine</artifactId> + </exclusion> + <exclusion> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-util</artifactId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty</artifactId> + <version>${jetty.version}</version> + </dependency> + + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>servlet-api-2.5</artifactId> + <version>${jetty.version}</version> + </dependency> + + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-util5</artifactId> + <version>${jetty.version}</version> + </dependency> + + <dependency> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-servlet-tester</artifactId> + <version>${jetty.version}</version> + </dependency> <dependency> <groupId>org.codehaus.plexus</groupId> @@ -332,8 +408,18 @@ <version>${junit.version}</version> <scope>test</scope> </dependency> + + <dependency> + <groupId>org.apache.maven.mercury</groupId> + <artifactId>mercury-transport-http</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + </dependencies> </dependencyManagement> + <dependencies> <dependency> <groupId>org.codehaus.plexus</groupId> @@ -353,35 +439,6 @@ </dependency> </dependencies> - <properties> - <plexus.appbooter.version>1.4</plexus.appbooter.version> - <plexus.container.version>1.0-beta-3.0.1</plexus.container.version> - <plexus.component.annotations.version>1.0-beta-3.0.1</plexus.component.annotations.version> - <classworlds.version>1.3</classworlds.version> - <plexus.utils.version>1.5.5</plexus.utils.version> - <plexus.lang.version>1.1</plexus.lang.version> - <plexus.component.metadata.version>1.0-beta-3.0.1</plexus.component.metadata.version> - - <commons.digester.version>1.8</commons.digester.version> - <commons.cli.version>1.1</commons.cli.version> - - <jetty.version>6.1.12</jetty.version> - <junit.version>3.8.1</junit.version> - <bouncy.castle.version>140</bouncy.castle.version> - <sat4j.version>2.0.4</sat4j.version> - - <!-- mercury-wagon --> - <wagon.provider.api.version>1.0-beta-4</wagon.provider.api.version> - - <distMgmtReleasesId>apache.releases</distMgmtReleasesId> - <distMgmtReleasesName>Apache Releases</distMgmtReleasesName> - <distMgmtReleasesUrl>scp://people.apache.org/www/people.apache.org/repo/m2-release-repository</distMgmtReleasesUrl> - - <distMgmtSnapshotsId>apache.snapshots</distMgmtSnapshotsId> - <distMgmtSnapshotsName>Apache Snapshots</distMgmtSnapshotsName> - <distMgmtSnapshotsUrl>scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository</distMgmtSnapshotsUrl> - </properties> - <build> <defaultGoal>install</defaultGoal> <resources>