diff --git a/maven-repository-webapp/pom.xml b/maven-repository-webapp/pom.xml
index d3d80f162..f275853b0 100644
--- a/maven-repository-webapp/pom.xml
+++ b/maven-repository-webapp/pom.xml
@@ -59,6 +59,10 @@
org.apache.maven.repository
maven-repository-configuration
+
+ org.apache.maven.repository
+ maven-repository-proxy
+
org.apache.maven.repository
maven-repository-artifact-applet
diff --git a/maven-repository-webapp/src/main/java/org/apache/maven/repository/proxy/web/action/RepositoryProxyAction.java b/maven-repository-webapp/src/main/java/org/apache/maven/repository/proxy/web/action/RepositoryProxyAction.java
new file mode 100644
index 000000000..fa4f64393
--- /dev/null
+++ b/maven-repository-webapp/src/main/java/org/apache/maven/repository/proxy/web/action/RepositoryProxyAction.java
@@ -0,0 +1,154 @@
+package org.apache.maven.repository.proxy.web.action;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+import com.opensymphony.xwork.Action;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.maven.repository.proxy.ProxyException;
+import org.apache.maven.repository.proxy.ProxyManager;
+import org.apache.maven.repository.proxy.configuration.MavenProxyPropertyLoader;
+import org.apache.maven.repository.proxy.configuration.ProxyConfiguration;
+import org.apache.maven.repository.proxy.configuration.ValidationException;
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+/**
+ * This is the Action class responsible for processing artifact request,
+ * relies on the RestfulActionMapper to map the artifact request to this action.
+ *
+ * @plexus.component role="com.opensymphony.xwork.Action" role-hint="org.apache.maven.repository.manager.web.action.RepositoryProxyAction"
+ */
+public class RepositoryProxyAction
+ implements Action
+{
+ /**
+ * logger instance
+ */
+ protected static final Log log = LogFactory.getLog( RepositoryProxyAction.class );
+
+ public static final String NOTFOUND = "notFound";
+
+ public static final String PROXYERROR = "proxyError";
+
+ /**
+ * file requested by the client,
+ * TODO: validate the requestd file using na interceptor
+ */
+ private String requestedFile;
+
+ /**
+ * main proxy logic
+ *
+ * @plexus.requirement role="org.apache.maven.repository.proxy.ProxyManager"
+ */
+ private ProxyManager repositoryProxyManager;
+
+ /**
+ * configuration for the ProxyManager
+ *
+ * @plexus.requirement
+ */
+ private ProxyConfiguration proxyConfig;
+
+ /**
+ * the inputstream for the artifact file
+ */
+ private FileInputStream artifactStream;
+
+ /**
+ * the cached artifact file
+ */
+ private File cachedFile;
+
+ /**
+ * proxy configuration file
+ * TODO: recode the configuration part when Configuration is finalized
+ * TODO: this is only temporary
+ */
+ private String configFile;
+
+ // setters and getters
+
+ public void setProxyManager( ProxyManager manager )
+ {
+ repositoryProxyManager = manager;
+ }
+
+ public void setRequestedFile( String reqFile )
+ {
+ requestedFile = reqFile;
+ }
+
+ public String getRequestedFile()
+ {
+ return requestedFile;
+ }
+
+ public FileInputStream getArtifactStream()
+ {
+ return artifactStream;
+ }
+
+ public File getCachedFile()
+ {
+ return cachedFile;
+ }
+
+ public void setConfigFile( String fileName )
+ {
+ configFile = fileName;
+ }
+
+ /**
+ * entry-point
+ */
+ public String execute()
+ throws MalformedURLException, IOException, ValidationException
+ {
+ try
+ {
+ MavenProxyPropertyLoader loader = new MavenProxyPropertyLoader();
+ proxyConfig = loader.load( new FileInputStream( configFile ) );
+ repositoryProxyManager.setConfiguration( proxyConfig );
+ cachedFile = repositoryProxyManager.get( requestedFile );
+ artifactStream = new FileInputStream( cachedFile );
+ }
+ catch ( ResourceDoesNotExistException ex )
+ {
+ log.info( "[not found] " + ex.getMessage() );
+ return NOTFOUND;
+ }
+ catch ( ProxyException ex )
+ {
+ log.info( "[proxy error] " + ex.getMessage() );
+ return PROXYERROR;
+ }
+ catch ( FileNotFoundException ex )
+ {
+ log.info( "[not found] " + ex.getMessage() );
+ return NOTFOUND;
+ }
+
+ return SUCCESS;
+ }
+}
diff --git a/maven-repository-webapp/src/main/java/org/apache/maven/repository/proxy/web/actionmapper/RepositoryProxyActionMapper.java b/maven-repository-webapp/src/main/java/org/apache/maven/repository/proxy/web/actionmapper/RepositoryProxyActionMapper.java
new file mode 100644
index 000000000..33fe1bc0e
--- /dev/null
+++ b/maven-repository-webapp/src/main/java/org/apache/maven/repository/proxy/web/actionmapper/RepositoryProxyActionMapper.java
@@ -0,0 +1,133 @@
+package org.apache.maven.repository.proxy.web.actionmapper;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+import com.opensymphony.webwork.dispatcher.mapper.ActionMapping;
+import com.opensymphony.webwork.dispatcher.mapper.DefaultActionMapper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Properties;
+
+public class RepositoryProxyActionMapper
+ extends DefaultActionMapper
+{
+ /**
+ * logger instance
+ */
+ protected static final Log log = LogFactory.getLog( RepositoryProxyActionMapper.class );
+
+ private static final String configFileName = "maven-proxy-complete.conf";
+
+ private static final String defaultProxyAction = "proxy";
+
+ /**
+ * the keyword that will be checked on the http request to determine if proxy
+ * is requested
+ *
+ * the default prefix is "/proxy/"
+ */
+ private String prefix = "/proxy/";
+
+ private String requestedArtifact;
+
+ String configFile = null;
+
+ public String getPrefix()
+ {
+ return prefix;
+ }
+
+ public String getRequestedArtifact()
+ {
+ return requestedArtifact;
+ }
+
+ public ActionMapping getDefaultActionMapping( HttpServletRequest request )
+ {
+ ActionMapping mapping = super.getMapping( request );
+
+ return mapping;
+ }
+
+ public void setConfigfile( String fileName )
+ {
+ configFile = fileName;
+ }
+
+ /**
+ * only process the request that matches the prefix all other request
+ * will be hand over to the default action mapper
+ *
+ * if the configuration file is missing the request will also be channeled
+ * to the default action mapper
+ */
+ public ActionMapping getMapping( HttpServletRequest request )
+ {
+ Properties config = new Properties();
+ String uri = request.getServletPath();
+ URL configURL = getClass().getClassLoader().getResource( configFileName );
+
+ if ( ( configURL != null ) && ( configFile == null ) )
+ {
+ configFile = configURL.getFile();
+ log.info( configFile );
+ }
+
+ try
+ {
+ config.load( new FileInputStream( configFile ) );
+ }
+ catch ( IOException ex )
+ {
+ log.info( "[config error] " + ex.getMessage() );
+ return getDefaultActionMapping( request );
+ }
+
+ if ( config.getProperty( "prefix" ) != null )
+ {
+ prefix = "/" + config.getProperty( "prefix" ) + "/";
+ }
+
+ log.info( "prefix : " + prefix );
+
+ if ( uri.startsWith( prefix ) )
+ {
+ requestedArtifact = uri.substring( prefix.length() );
+
+ if ( ( requestedArtifact == null ) || ( requestedArtifact.length() < 0 ) )
+ {
+ return getDefaultActionMapping( request );
+ }
+
+ HashMap parameterMap = new HashMap();
+
+ parameterMap.put( "requestedFile", requestedArtifact );
+ parameterMap.put( "configFile", configFile );
+
+ return new ActionMapping( defaultProxyAction, "/", "", parameterMap );
+ }
+
+ return getDefaultActionMapping( request );
+ }
+
+}
diff --git a/maven-repository-webapp/src/main/resources/maven-proxy-complete.conf b/maven-repository-webapp/src/main/resources/maven-proxy-complete.conf
new file mode 100644
index 000000000..cfa847144
--- /dev/null
+++ b/maven-repository-webapp/src/main/resources/maven-proxy-complete.conf
@@ -0,0 +1,145 @@
+################ GLOBAL SETTINGS
+# This is where maven-proxy stores files it has downloaded
+repo.local.store=/tmp/proxy-cache
+
+#The port to listen on - not used if loaded as a webapp
+port=9999
+
+#This is the base area that all files are loaded from. While it is possible to leave this blank, this behaviour
+#is deprecated and will be disabled in version 2.0. There are too many namespace conflicts caused by not using
+#a prefix.
+#The repository will be shown at http://localhost:9999/repository/
+#for the .war loaded into a webapp server, the default prefix is "repository" (edit the web.xml to change)
+# As maven doesn't like a trailing slash, this address shouldn't have one either.
+prefix=repository
+
+#This is the simple date format used to display the last modified date while browsing the repository.
+lastModifiedDateFormat=yyyy/MM/dd HH:mm:ss
+
+################ SNAPSHOT HANDLING
+#If you want the proxy to look for newer snapshots, set to true
+snapshot.update=true
+
+################ M2 METADATA HANDLING
+#If you want the proxy to prevent looking for newer metadata, set to false (default is true)
+#metadata.update=false
+
+################ M2 POM HANDLING
+#If you want the proxy to look for newer POMs, set to true (default is false)
+pom.update=true
+
+################ PROMOTION HANDLING
+# ***** NOT CURRENTLY IMPLEMENTED *****
+#Promotion describes the process by which new artifacts are loaded to global maven-proxy repository. It
+# is designed to be used by "higher security installations" that do not want to acquire artifacts from
+# remote repositories without approval.
+#
+#If promotion handling is enabled, then the proxy will not download remote artifacts without permission
+# (local repositories with copy=false are considered to be local)
+#
+#Permission to download is granted via the Promotion menu which will be enabled
+# when promotion handling is enabled.
+#
+#If promotion is false, artifacts are sourced from any repository as per normal.
+#
+#Promotion and snapshots: If promotion is enabled, snapshots are not downloadable. The concept of using
+# a snapshot in a production build (which is primarily what promotion is for) is counterintuitive.
+##
+promotion=false
+
+################ WEB INTERFACE
+# This defines the absolute URL the server should use to identify itself.
+# This can often be determined automatically, but we recommend you specify
+# it explicitly to prevent problems during startup.
+# The prefix will be added to this for the actual repository
+# i.e. proxy available at http://localhost:9999/, repository at http://localhost:9999/repository
+serverName=http://localhost:9999
+
+#If true, the repository can be browsed
+browsable=true
+
+#If true, the repository can be searched
+searchable=true
+
+#Not currently implemented. Will allow webdav access to the repository at some point.
+webdav=true
+
+#Stylesheet - if configured, will override the default stylesheet shipped with maven-proxy - absolute URLs only
+#eg. /maven-proxy/style.css, http://www.example.com/style.css
+stylesheet=/maven-proxy/style.css
+
+#bgColor / bgColorHighlight are replaced in the built in stylesheet to produce a simple color scheme.
+#If a stylesheet is set, these are not used.
+bgColor=#14B
+bgColorHighlight=#94B
+
+#rowColor / rowColorHighlight are replaced in the built in stylesheet to produce a simple color scheme.
+#If a stylesheet is set, these are not used.
+rowColor=#CCF
+rowColorHighlight=#DDF
+
+
+################ PROXIES
+#This is just a hack, it should auto discover them
+#proxy.list=one,two,three
+proxy.list=
+
+#Unauthenticated proxy
+#proxy.one.host=proxy1.example.com
+#proxy.one.port=3128
+
+#Authenticated proxy
+#proxy.two.host=proxy2.example.org
+#proxy.two.port=80
+#proxy.two.username=username2
+#proxy.two.password=password2
+
+#Authenticated proxy
+#proxy.three.host=proxy3.example.net
+#proxy.three.port=3129
+#proxy.three.username=username3
+#proxy.three.password=password3
+
+
+################# REPOSITORIES
+#This is not just a hack, it specifies the order repositories should be checked
+#Note that the proxy adds a "/" which is why the urls aren't suffixed with a "/"
+repo.list=www-ibiblio-org
+
+#local-store
+# The local store represents a location that local jars you host can be located.
+# This could also be achieved by having a local http repository, but this is less cumbersome
+repo.local-repo.url=file://target
+repo.local-repo.description=Super Secret Custom Repository
+#If copy is true, jars are copied from the store to the proxy-repo. Only configurable for file:/// repos
+repo.local-repo.copy=false
+#If hardfail is true, any unexpected errors from the repository will cause
+#the client download to fail (typically with a 500 error)
+repo.local-repo.hardfail=true
+#Don't cache a file repository
+repo.local-repo.cache.period=0
+
+
+#www.ibiblio.org
+repo.www-ibiblio-org.url=http://www.ibiblio.org/maven2
+repo.www-ibiblio-org.description=www.ibiblio.org
+repo.www-ibiblio-org.proxy=
+repo.www-ibiblio-org.hardfail=true
+#Cache this repository for 1 hour
+repo.www-ibiblio-org.cache.period=3600
+repo.www-ibiblio-org.cache.failures=true
+
+#dist.codehaus.org
+repo.dist-codehaus-org.url=http://dist.codehaus.org
+repo.dist-codehaus-org.proxy=two
+repo.dist-codehaus-org.hardfail=false
+repo.dist-codehaus-org.cache.period=3600
+repo.dist-codehaus-org.cache.failures=true
+
+#private.example.com
+repo.private-example-com.url=http://private.example.com/internal
+repo.private-example-com.description=Commercial In Confidence Repository
+repo.private-example-com.username=username1
+repo.private-example-com.password=password1
+repo.private-example-com.proxy=three
+repo.private-example-com.cache.period=3600
diff --git a/maven-repository-webapp/src/main/resources/webwork.properties b/maven-repository-webapp/src/main/resources/webwork.properties
new file mode 100644
index 000000000..138e918d1
--- /dev/null
+++ b/maven-repository-webapp/src/main/resources/webwork.properties
@@ -0,0 +1,3 @@
+# define our own action mapper here
+webwork.mapper.class=org.apache.maven.repository.proxy.web.actionmapper.RepositoryProxyActionMapper
+webwork.objectFactory = org.codehaus.plexus.xwork.PlexusObjectFactory
diff --git a/maven-repository-webapp/src/main/resources/xwork.xml b/maven-repository-webapp/src/main/resources/xwork.xml
index 24e2876e2..357f08abe 100644
--- a/maven-repository-webapp/src/main/resources/xwork.xml
+++ b/maven-repository-webapp/src/main/resources/xwork.xml
@@ -43,6 +43,16 @@
-->
+
+
+ application/octet-stream
+ artifactStream
+ 1024
+
+ notFoundError
+ proxyError
+
+
/WEB-INF/jsp/generalresults.jsp
/WEB-INF/jsp/index.jsp
diff --git a/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/RepositoryProxyActionTest.java b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/RepositoryProxyActionTest.java
new file mode 100644
index 000000000..a136d1d79
--- /dev/null
+++ b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/RepositoryProxyActionTest.java
@@ -0,0 +1,77 @@
+package org.apache.maven.repository.proxy.web.action.test;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+import org.apache.maven.repository.proxy.web.action.RepositoryProxyAction;
+import org.apache.maven.repository.proxy.web.action.test.stub.ProxyManagerStub;
+import org.codehaus.plexus.PlexusTestCase;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.Properties;
+
+public class RepositoryProxyActionTest
+ extends PlexusTestCase
+{
+
+ /**
+ * test basic proxy operation
+ *
+ * @throws Exception
+ */
+ public void testProxy()
+ throws Exception
+ {
+ String testDir = getBasedir() + "/target/test-classes/unit/proxy-test";
+ RepositoryProxyAction action = new RepositoryProxyAction();
+ ProxyManagerStub proxyManager = new ProxyManagerStub( testDir );
+ File cachedFile = proxyManager.get( "dummyFile" );
+
+ if ( !cachedFile.getParentFile().exists() )
+ {
+ assertTrue( "can not create test file", cachedFile.getParentFile().mkdirs() );
+ }
+
+ if ( !cachedFile.exists() )
+ {
+ assertTrue( "can not create test file", cachedFile.createNewFile() );
+ }
+
+ File tmpDir = getTestFile( "target/tmp-repo" );
+ tmpDir.mkdirs();
+
+ // TODO: configure manually, test the property loader elsewhere
+ Properties properties = new Properties();
+ properties.load( getClass().getResourceAsStream( "/unit/proxy-test/maven-proxy-complete.conf" ) );
+ properties.setProperty( "repo.local.store", tmpDir.getAbsolutePath() );
+ File tempFile = File.createTempFile( "test", "tmp" );
+ tempFile.deleteOnExit();
+ properties.store( new FileOutputStream( tempFile ), "" );
+
+ action.setConfigFile( tempFile.getAbsolutePath() );
+ action.setProxyManager( proxyManager );
+
+ String result = action.execute();
+ FileInputStream fileStream = action.getArtifactStream();
+
+ assertEquals( "proxy error", action.SUCCESS, result );
+ assertNotNull( "inputstream not set", fileStream );
+ assertNotNull( "cached file not set", action.getCachedFile() );
+ assertTrue( "proxy error", cachedFile.getPath().equals( action.getCachedFile().getPath() ) );
+ }
+}
diff --git a/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/HttpServletRequestStub.java b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/HttpServletRequestStub.java
new file mode 100644
index 000000000..02c8fe5a7
--- /dev/null
+++ b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/HttpServletRequestStub.java
@@ -0,0 +1,154 @@
+package org.apache.maven.repository.proxy.web.action.test.stub;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.security.Principal;
+import java.util.Enumeration;
+
+public class HttpServletRequestStub
+ extends ServletRequestStub
+ implements HttpServletRequest
+{
+
+ public String getAuthType()
+ {
+ return null;
+ }
+
+ public String getContextPath()
+ {
+ return "/location1/location2/location3";
+ }
+
+ public Cookie[] getCookies()
+ {
+ return null;
+ }
+
+ public long getDateHeader( String name )
+ {
+ return -1;
+ }
+
+ public String getHeader( String name )
+ {
+ return null;
+ }
+
+ public Enumeration getHeaderNames()
+ {
+ return null;
+ }
+
+ public Enumeration getHeaders( String name )
+ {
+ return null;
+ }
+
+ public int getIntHeader( String name )
+ {
+ return -1;
+ }
+
+ public String getMethod()
+ {
+ return null;
+ }
+
+ public String getPathInfo()
+ {
+ return null;
+ }
+
+ public String getPathTranslated()
+ {
+ return null;
+ }
+
+ public String getQueryString()
+ {
+ return null;
+ }
+
+ public String getRemoteUser()
+ {
+ return null;
+ }
+
+ public String getRequestedSessionId()
+ {
+ return null;
+ }
+
+ public String getRequestURI()
+ {
+ return "/projectname/repository/org/sometest/artifact-0.0.jar";
+ }
+
+ public StringBuffer getRequestURL()
+ {
+ return null;
+ }
+
+ public String getServletPath()
+ {
+ return "/repository/org/sometest/artifact-0.0.jar";
+ }
+
+ public HttpSession getSession()
+ {
+ return null;
+ }
+
+ public HttpSession getSession( boolean create )
+ {
+ return null;
+ }
+
+ public Principal getUserPrincipal()
+ {
+ return null;
+ }
+
+ public boolean isRequestedSessionIdFromCookie()
+ {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromUrl()
+ {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromURL()
+ {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdValid()
+ {
+ return false;
+ }
+
+ public boolean isUserInRole( String role )
+ {
+ return false;
+ }
+}
diff --git a/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/ProxyManagerStub.java b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/ProxyManagerStub.java
new file mode 100644
index 000000000..e7d3b21a5
--- /dev/null
+++ b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/ProxyManagerStub.java
@@ -0,0 +1,58 @@
+package org.apache.maven.repository.proxy.web.action.test.stub;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+import org.apache.maven.repository.proxy.ProxyManager;
+import org.apache.maven.repository.proxy.configuration.ProxyConfiguration;
+
+import java.io.File;
+
+public class ProxyManagerStub
+ implements ProxyManager
+{
+ String baseDir;
+
+ public ProxyManagerStub( String base )
+ {
+ baseDir = base;
+ }
+
+ public File get( String requestFile )
+ {
+ return new File( baseDir, "proxy-cache/test-0.0.jar" );
+ }
+
+ public File getRemoteFile( String reqFile )
+ {
+ return new File( baseDir, "proxy-chache/test-0.0.jar" );
+ }
+
+ public void setConfiguration( ProxyConfiguration config )
+ {
+ // do nothing
+ }
+
+ public ProxyConfiguration getConfiguration()
+ {
+ return null;
+ }
+
+ public File getAlways( String name )
+ {
+ return null;
+ }
+}
diff --git a/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/ServletRequestStub.java b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/ServletRequestStub.java
new file mode 100644
index 000000000..e5919d19b
--- /dev/null
+++ b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/action/test/stub/ServletRequestStub.java
@@ -0,0 +1,181 @@
+package org.apache.maven.repository.proxy.web.action.test.stub;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import java.io.BufferedReader;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class ServletRequestStub
+ implements ServletRequest
+{
+
+ public Object getAttribute( String key )
+ {
+ return null;
+ }
+
+ public Enumeration getAttributeNames()
+ {
+ return null;
+ }
+
+ public String getCharacterEncoding()
+ {
+ return null;
+ }
+
+ public int getContentLength()
+ {
+ return -1;
+ }
+
+ public int getRemotePort()
+ {
+ return -1;
+ }
+
+ public int getLocalPort()
+ {
+ return -1;
+ }
+
+ public String getLocalAddr()
+ {
+ return null;
+ }
+
+ public String getLocalName()
+ {
+ return null;
+ }
+
+ public String getContentType()
+ {
+ return null;
+ }
+
+ public ServletInputStream getInputStream()
+ {
+ return null;
+ }
+
+ public Locale getLocale()
+ {
+ return null;
+ }
+
+ public Enumeration getLocales()
+ {
+ return null;
+ }
+
+ public String getParameter( String name )
+ {
+ return null;
+ }
+
+ public Map getParameterMap()
+ {
+ HashMap parameterMap = new HashMap();
+
+ parameterMap.put( "key1", "value1" );
+ parameterMap.put( "key2", "value2" );
+
+ return parameterMap;
+ }
+
+ public Enumeration getParameterNames()
+ {
+ return null;
+ }
+
+ public String[] getParameterValues( String name )
+ {
+ return null;
+ }
+
+ public String getProtocol()
+ {
+ return null;
+ }
+
+ public BufferedReader getReader()
+ {
+ return null;
+ }
+
+ public String getRealPath( String path )
+ {
+ return null;
+ }
+
+ public String getRemoteAddr()
+ {
+ return null;
+ }
+
+ public String getRemoteHost()
+ {
+ return null;
+ }
+
+ public RequestDispatcher getRequestDispatcher( String path )
+ {
+ return null;
+ }
+
+ public String getScheme()
+ {
+ return null;
+ }
+
+ public String getServerName()
+ {
+ return null;
+ }
+
+ public int getServerPort()
+ {
+ return -1;
+ }
+
+ public boolean isSecure()
+ {
+ return false;
+ }
+
+ public void removeAttribute( String name )
+ {
+
+ }
+
+ public void setAttribute( String name, Object value )
+ {
+
+ }
+
+ public void setCharacterEncoding( String env )
+ {
+
+ }
+}
diff --git a/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/actionmapper/test/RepositoryProxyActionMapperTest.java b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/actionmapper/test/RepositoryProxyActionMapperTest.java
new file mode 100644
index 000000000..4288a90fb
--- /dev/null
+++ b/maven-repository-webapp/src/test/java/org/apache/maven/repository/proxy/web/actionmapper/test/RepositoryProxyActionMapperTest.java
@@ -0,0 +1,77 @@
+package org.apache.maven.repository.proxy.web.actionmapper.test;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+import com.opensymphony.webwork.dispatcher.mapper.ActionMapping;
+import org.apache.maven.repository.proxy.web.action.test.stub.HttpServletRequestStub;
+import org.apache.maven.repository.proxy.web.actionmapper.RepositoryProxyActionMapper;
+import org.codehaus.plexus.PlexusTestCase;
+
+public class RepositoryProxyActionMapperTest
+ extends PlexusTestCase
+{
+ RepositoryProxyActionMapper actionMapper;
+
+ public void setUp()
+ throws Exception
+ {
+ actionMapper = new RepositoryProxyActionMapper();
+ }
+
+ // TODO: uncomment once we know how to make the default action mapper work using stubs
+ // public void testDefaultActionMapping()
+ // throws Exception
+ // {
+ // ActionMapping mapping = actionMapper.getMapping( new DefaultActionMapperRequestStub() );
+ //
+ // String expectedNamespace = "test";
+ // String expectedName = "test";
+ //
+ // assertNotNull( "ActionMapping is null", mapping );
+ // assertNotNull( "namespace is null", mapping.getNamespace() );
+ // assertNotNull( "name is null", mapping.getName() );
+ // assertTrue( "invalid namespace: " + mapping.getNamespace(), mapping.getNamespace().equals( expectedNamespace ) );
+ // assertTrue( "invalid name: " + mapping.getName(), mapping.getName().equals( expectedName ) );
+ // }
+
+ public void testRepositoryProxyActionMapping()
+ throws Exception
+ {
+ String testDir = getBasedir() + "/target/test-classes/unit/proxy-test";
+
+ actionMapper.setConfigfile( testDir + "/maven-proxy-complete.conf" );
+
+ ActionMapping mapping = actionMapper.getMapping( new HttpServletRequestStub() );
+ String expectedName = "proxy";
+ String expectedFile = "org/sometest/artifact-0.0.jar";
+
+ assertNotNull( "ActionMapping is null", mapping );
+ assertNotNull( "name is null", mapping.getName() );
+
+ String mappingName = mapping.getName();
+ String requestedFile = (String) mapping.getParams().get( "requestedFile" );
+
+ assertTrue( "invalid name: " + mappingName, mappingName.equals( expectedName ) );
+ assertTrue( "invalid parameter: " + requestedFile, requestedFile.equals( expectedFile ) );
+ }
+
+ public void tearDown()
+ throws Exception
+ {
+ // do nothing
+ }
+}
diff --git a/maven-repository-webapp/src/test/resources/unit/proxy-test/maven-proxy-complete.conf b/maven-repository-webapp/src/test/resources/unit/proxy-test/maven-proxy-complete.conf
new file mode 100644
index 000000000..95f01bb30
--- /dev/null
+++ b/maven-repository-webapp/src/test/resources/unit/proxy-test/maven-proxy-complete.conf
@@ -0,0 +1,145 @@
+################ GLOBAL SETTINGS
+# This is where maven-proxy stores files it has downloaded
+#repo.local.store=/tmp/proxy-cache
+
+#The port to listen on - not used if loaded as a webapp
+port=9999
+
+#This is the base area that all files are loaded from. While it is possible to leave this blank, this behaviour
+#is deprecated and will be disabled in version 2.0. There are too many namespace conflicts caused by not using
+#a prefix.
+#The repository will be shown at http://localhost:9999/repository/
+#for the .war loaded into a webapp server, the default prefix is "repository" (edit the web.xml to change)
+# As maven doesn't like a trailing slash, this address shouldn't have one either.
+prefix=repository
+
+#This is the simple date format used to display the last modified date while browsing the repository.
+lastModifiedDateFormat=yyyy/MM/dd HH:mm:ss
+
+################ SNAPSHOT HANDLING
+#If you want the proxy to look for newer snapshots, set to true
+snapshot.update=true
+
+################ M2 METADATA HANDLING
+#If you want the proxy to prevent looking for newer metadata, set to false (default is true)
+#metadata.update=false
+
+################ M2 POM HANDLING
+#If you want the proxy to look for newer POMs, set to true (default is false)
+pom.update=true
+
+################ PROMOTION HANDLING
+# ***** NOT CURRENTLY IMPLEMENTED *****
+#Promotion describes the process by which new artifacts are loaded to global maven-proxy repository. It
+# is designed to be used by "higher security installations" that do not want to acquire artifacts from
+# remote repositories without approval.
+#
+#If promotion handling is enabled, then the proxy will not download remote artifacts without permission
+# (local repositories with copy=false are considered to be local)
+#
+#Permission to download is granted via the Promotion menu which will be enabled
+# when promotion handling is enabled.
+#
+#If promotion is false, artifacts are sourced from any repository as per normal.
+#
+#Promotion and snapshots: If promotion is enabled, snapshots are not downloadable. The concept of using
+# a snapshot in a production build (which is primarily what promotion is for) is counterintuitive.
+##
+promotion=false
+
+################ WEB INTERFACE
+# This defines the absolute URL the server should use to identify itself.
+# This can often be determined automatically, but we recommend you specify
+# it explicitly to prevent problems during startup.
+# The prefix will be added to this for the actual repository
+# i.e. proxy available at http://localhost:9999/, repository at http://localhost:9999/repository
+serverName=http://localhost:9999
+
+#If true, the repository can be browsed
+browsable=true
+
+#If true, the repository can be searched
+searchable=true
+
+#Not currently implemented. Will allow webdav access to the repository at some point.
+webdav=true
+
+#Stylesheet - if configured, will override the default stylesheet shipped with maven-proxy - absolute URLs only
+#eg. /maven-proxy/style.css, http://www.example.com/style.css
+stylesheet=/maven-proxy/style.css
+
+#bgColor / bgColorHighlight are replaced in the built in stylesheet to produce a simple color scheme.
+#If a stylesheet is set, these are not used.
+bgColor=#14B
+bgColorHighlight=#94B
+
+#rowColor / rowColorHighlight are replaced in the built in stylesheet to produce a simple color scheme.
+#If a stylesheet is set, these are not used.
+rowColor=#CCF
+rowColorHighlight=#DDF
+
+
+################ PROXIES
+#This is just a hack, it should auto discover them
+#proxy.list=one,two,three
+proxy.list=
+
+#Unauthenticated proxy
+#proxy.one.host=proxy1.example.com
+#proxy.one.port=3128
+
+#Authenticated proxy
+#proxy.two.host=proxy2.example.org
+#proxy.two.port=80
+#proxy.two.username=username2
+#proxy.two.password=password2
+
+#Authenticated proxy
+#proxy.three.host=proxy3.example.net
+#proxy.three.port=3129
+#proxy.three.username=username3
+#proxy.three.password=password3
+
+
+################# REPOSITORIES
+#This is not just a hack, it specifies the order repositories should be checked
+#Note that the proxy adds a "/" which is why the urls aren't suffixed with a "/"
+repo.list=www-ibiblio-org
+
+#local-store
+# The local store represents a location that local jars you host can be located.
+# This could also be achieved by having a local http repository, but this is less cumbersome
+repo.local-repo.url=file://target
+repo.local-repo.description=Super Secret Custom Repository
+#If copy is true, jars are copied from the store to the proxy-repo. Only configurable for file:/// repos
+repo.local-repo.copy=false
+#If hardfail is true, any unexpected errors from the repository will cause
+#the client download to fail (typically with a 500 error)
+repo.local-repo.hardfail=true
+#Don't cache a file repository
+repo.local-repo.cache.period=0
+
+
+#www.ibiblio.org
+repo.www-ibiblio-org.url=http://www.ibiblio.org/maven2
+repo.www-ibiblio-org.description=www.ibiblio.org
+repo.www-ibiblio-org.proxy=
+repo.www-ibiblio-org.hardfail=true
+#Cache this repository for 1 hour
+repo.www-ibiblio-org.cache.period=3600
+repo.www-ibiblio-org.cache.failures=true
+
+#dist.codehaus.org
+repo.dist-codehaus-org.url=http://dist.codehaus.org
+repo.dist-codehaus-org.proxy=two
+repo.dist-codehaus-org.hardfail=false
+repo.dist-codehaus-org.cache.period=3600
+repo.dist-codehaus-org.cache.failures=true
+
+#private.example.com
+repo.private-example-com.url=http://private.example.com/internal
+repo.private-example-com.description=Commercial In Confidence Repository
+repo.private-example-com.username=username1
+repo.private-example-com.password=password1
+repo.private-example-com.proxy=three
+repo.private-example-com.cache.period=3600
diff --git a/pom.xml b/pom.xml
index abdc15c25..d5263e3c2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -209,6 +209,11 @@
maven-repository-indexer
${pom.version}
+
+ org.apache.maven.repository
+ maven-repository-proxy
+ ${pom.version}
+
org.apache.maven.repository
maven-repository-utils