From 28e54029c0e02d69ed56c6f97d0c4c301b706802 Mon Sep 17 00:00:00 2001 From: Brett Porter Date: Thu, 3 Apr 2008 12:03:54 +0000 Subject: [PATCH] [MRM-159] should not respond with a 404 if proxying a file results in a remote error Merged from: r644205, 644275 git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@644276 13f79535-47bb-0310-9956-ffa450edef68 --- .../site/apt/adminguide/proxy-connectors.apt | 12 +- .../DefaultArchivaConfiguration.java | 8 +- .../src/main/mdo/configuration.mdo | 14 + .../policies/CachedFailuresPolicy.java | 5 + .../archiva/policies/ChecksumPolicy.java | 5 + .../archiva/policies/DownloadErrorPolicy.java | 50 ++ .../archiva/policies/DownloadPolicy.java | 22 +- .../apache/maven/archiva/policies/Policy.java | 55 ++ .../archiva/policies/PostDownloadPolicy.java | 17 - .../archiva/policies/PreDownloadPolicy.java | 17 - .../PropagateErrorsDownloadPolicy.java | 118 ++++ ...PropagateErrorsOnUpdateDownloadPolicy.java | 105 +++ .../policies/ProxyDownloadException.java | 66 ++ .../archiva/policies/ReleasesPolicy.java | 5 + .../archiva/policies/SnapshotsPolicy.java | 5 + .../DefaultRepositoryProxyConnectors.java | 144 ++-- .../proxy/RepositoryProxyConnectors.java | 17 +- .../archiva/proxy/AbstractProxyTestCase.java | 27 +- .../archiva/proxy/ErrorHandlingTest.java | 627 ++++++++++++++++++ .../maven/archiva/proxy/ErrorHandlingTest.xml | 118 ++++ .../AbstractProxyConnectorFormAction.java | 25 +- .../web/repository/ProxiedDavServer.java | 14 +- .../jsp/admin/include/proxyConnectorForm.jspf | 2 +- .../proxy/AddProxyConnectorActionTest.java | 14 +- .../proxy/EditProxyConnectorActionTest.java | 14 +- 25 files changed, 1365 insertions(+), 141 deletions(-) create mode 100644 archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/DownloadErrorPolicy.java create mode 100644 archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/Policy.java create mode 100644 archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PropagateErrorsDownloadPolicy.java create mode 100644 archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PropagateErrorsOnUpdateDownloadPolicy.java create mode 100644 archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ProxyDownloadException.java create mode 100644 archiva-modules/archiva-base/archiva-proxy/src/test/java/org/apache/maven/archiva/proxy/ErrorHandlingTest.java create mode 100644 archiva-modules/archiva-base/archiva-proxy/src/test/resources/org/apache/maven/archiva/proxy/ErrorHandlingTest.xml diff --git a/archiva-docs/src/site/apt/adminguide/proxy-connectors.apt b/archiva-docs/src/site/apt/adminguide/proxy-connectors.apt index cf4dd72a3..5737091be 100644 --- a/archiva-docs/src/site/apt/adminguide/proxy-connectors.apt +++ b/archiva-docs/src/site/apt/adminguide/proxy-connectors.apt @@ -29,14 +29,18 @@ Understanding Proxy Connector Configuration of Apache Archiva By default, Archiva comes with the following policies: - * <<>> - how to behave for released artifact metadata (those not carrying a <<>> version). This can be set to <<>> (default), <<>>, <<>>, <<>> and <<>>. + * <<>> - how to behave for released artifact metadata (those not carrying a <<>> version). This can be set to <<>> (default), <<>>, <<>>, <<>> and <<>>. - * <<>> - how to behave for snapshot artifact metadata (those carrying a <<>> version). This can be set to <<>> (default), <<>>, <<>>, <<>> and <<>>. + * <<>> - how to behave for snapshot artifact metadata (those carrying a <<>> version). This can be set to <<>> (default), <<>>, <<>>, <<>> and <<>>. - * <<>> - how to handle incorrect checksums when downloading an artifact from the remote repository (ie, the checksum of the artifact does not match the corresponding detached checksum file). + * <<>> - how to handle incorrect checksums when downloading an artifact from the remote repository (ie, the checksum of the artifact does not match the corresponding detached checksum file). The options are to fail the request for the remote artifact, fix the checksum on the fly (default), or simply ignore the incorrect checksum - * <<>> - whether failures retrieving the remote artifact should be cached (to save network bandwidth for missing or bad artifacts), or uncached (default). + * <<>> - whether failures retrieving the remote artifact should be cached (to save network bandwidth for missing or bad artifacts), or uncached (default). + + * <<>> - if a remote proxy causes an error, this option determines whether an existing artifact should be returned (error when <<>>), or the error passed on regardless (<<>>). + + * <<>> - if a remote error is encountered, <<>> causes the error to be returned immediately, <<>> will return all errors after checking for other successful remote repositories first, and <<>> will disregard ay errors. [] diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/maven/archiva/configuration/DefaultArchivaConfiguration.java b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/maven/archiva/configuration/DefaultArchivaConfiguration.java index ea0f57ac0..cc8636531 100644 --- a/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/maven/archiva/configuration/DefaultArchivaConfiguration.java +++ b/archiva-modules/archiva-base/archiva-configuration/src/main/java/org/apache/maven/archiva/configuration/DefaultArchivaConfiguration.java @@ -29,7 +29,7 @@ import org.apache.maven.archiva.configuration.io.registry.ConfigurationRegistryW import org.apache.maven.archiva.policies.AbstractUpdatePolicy; import org.apache.maven.archiva.policies.CachedFailuresPolicy; import org.apache.maven.archiva.policies.ChecksumPolicy; -import org.apache.maven.archiva.policies.DownloadPolicy; +import org.apache.maven.archiva.policies.Policy; import org.apache.maven.archiva.policies.PostDownloadPolicy; import org.apache.maven.archiva.policies.PreDownloadPolicy; import org.codehaus.plexus.evaluator.DefaultExpressionEvaluator; @@ -280,7 +280,7 @@ public class DefaultArchivaConfiguration // Validate existance of policy key. if ( policyExists( policyId ) ) { - DownloadPolicy policy = findPolicy( policyId ); + Policy policy = findPolicy( policyId ); // Does option exist? if ( !policy.getOptions().contains( setting ) ) { @@ -323,7 +323,7 @@ public class DefaultArchivaConfiguration return config; } - private DownloadPolicy findPolicy( String policyId ) + private Policy findPolicy( String policyId ) { if ( MapUtils.isEmpty( prePolicies ) ) { @@ -337,7 +337,7 @@ public class DefaultArchivaConfiguration return null; } - DownloadPolicy policy; + Policy policy; policy = prePolicies.get( policyId ); if ( policy != null ) diff --git a/archiva-modules/archiva-base/archiva-configuration/src/main/mdo/configuration.mdo b/archiva-modules/archiva-base/archiva-configuration/src/main/mdo/configuration.mdo index babc602a3..773674384 100644 --- a/archiva-modules/archiva-base/archiva-configuration/src/main/mdo/configuration.mdo +++ b/archiva-modules/archiva-base/archiva-configuration/src/main/mdo/configuration.mdo @@ -651,6 +651,20 @@ */ public static final int UNORDERED = 0; + /** + * The policy key {@link #getPolicies()} for error handling. + * See {@link org.apache.maven.archiva.policies.DownloadErrorPolicy} + * for details on potential values to this policy key. + */ + public static final String POLICY_PROPAGATE_ERRORS = "propagate-errors"; + + /** + * The policy key {@link #getPolicies()} for error handling when an artifact is present. + * See {@link org.apache.maven.archiva.policies.DownloadErrorPolicy} + * for details on potential values to this policy key. + */ + public static final String POLICY_PROPAGATE_ERRORS_ON_UPDATE = "propagate-errors-on-update"; + /** * The policy key {@link #getPolicies()} for snapshot handling. * See {@link org.apache.maven.archiva.policies.SnapshotsPolicy} diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/CachedFailuresPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/CachedFailuresPolicy.java index 77bd3b0ba..a69227ce9 100644 --- a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/CachedFailuresPolicy.java +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/CachedFailuresPolicy.java @@ -108,6 +108,11 @@ public class CachedFailuresPolicy return "cache-failures"; } + public String getName() + { + return "Cache failures"; + } + public List getOptions() { return options; diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ChecksumPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ChecksumPolicy.java index 9b91c42d1..99e741e0c 100644 --- a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ChecksumPolicy.java +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ChecksumPolicy.java @@ -157,6 +157,11 @@ public class ChecksumPolicy return "checksum"; } + public String getName() + { + return "Checksum"; + } + public List getOptions() { return options; diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/DownloadErrorPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/DownloadErrorPolicy.java new file mode 100644 index 000000000..b5c209c6c --- /dev/null +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/DownloadErrorPolicy.java @@ -0,0 +1,50 @@ +package org.apache.maven.archiva.policies; + +/* + * 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. + */ + +import java.io.File; +import java.util.Map; +import java.util.Properties; + +/** + * Policy to apply after the download has completed, but before the + * resource is made available to the calling client. + * + * @author Brett Porter + * @version $Id$ + */ +public interface DownloadErrorPolicy + extends Policy +{ + /** + * Apply the download error policy. + * + * @param policySetting the policy setting. + * @param request the list of request properties that the policy might use. + * @param localFile + * @param exception the exception that triggered the error + * @param previousExceptions any previously triggered exceptions + * @return whether to process the exception or not + * @throws PolicyConfigurationException if the policy is improperly configured + */ + public boolean applyPolicy( String policySetting, Properties request, File localFile, Exception exception, + Map previousExceptions ) + throws PolicyConfigurationException; +} \ No newline at end of file diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/DownloadPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/DownloadPolicy.java index 6d506308d..68036d9e8 100644 --- a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/DownloadPolicy.java +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/DownloadPolicy.java @@ -20,7 +20,6 @@ package org.apache.maven.archiva.policies; */ import java.io.File; -import java.util.List; import java.util.Properties; /** @@ -30,27 +29,8 @@ import java.util.Properties; * @version $Id$ */ public interface DownloadPolicy + extends Policy { - /** - * Get the list of options for this policy. - * - * @return the list of options for this policy. - */ - public List getOptions(); - - /** - * Get the default option for this policy. - * - * @return the default policy for this policy. - */ - public String getDefaultOption(); - - /** - * Get the id for this policy. - * - * @return the id for this policy. - */ - public String getId(); /** * Apply the download policy. diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/Policy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/Policy.java new file mode 100644 index 000000000..f7add1b73 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/Policy.java @@ -0,0 +1,55 @@ +package org.apache.maven.archiva.policies; + +/* + * 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. + */ + +import java.util.List; + +public interface Policy +{ + /** + * Get the list of options for this policy. + * + * @return the list of options for this policy. + */ + List getOptions(); + + /** + * Get the default option for this policy. + * + * @return the default policy for this policy. + */ + String getDefaultOption(); + + /** + * Get the id for this policy. + * + * @return the id for this policy. + */ + String getId(); + + /** + * Get the display name for this policy. + * + * @todo i18n + * + * @return the name for this policy + */ + String getName(); +} diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PostDownloadPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PostDownloadPolicy.java index d1f6d216e..12bb6b416 100644 --- a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PostDownloadPolicy.java +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PostDownloadPolicy.java @@ -19,9 +19,6 @@ package org.apache.maven.archiva.policies; * under the License. */ -import java.io.File; -import java.util.Properties; - /** * Policy to apply after the download has completed, but before the * resource is made available to the calling client. @@ -32,18 +29,4 @@ import java.util.Properties; public interface PostDownloadPolicy extends DownloadPolicy { - /** - * Apply the download policy. - * - * A true result allows the download to succeed. false indicates that the - * download is a failure. - * - * @param policySetting the policy setting. - * @param request the list of request properties that the policy might use. - * @param localFile the local file that this policy affects - * - * @throws PolicyViolationException if the policy has been violated. - */ - public void applyPolicy( String policySetting, Properties request, File localFile ) - throws PolicyViolationException, PolicyConfigurationException; } diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PreDownloadPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PreDownloadPolicy.java index f88eb938f..1faf52025 100644 --- a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PreDownloadPolicy.java +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PreDownloadPolicy.java @@ -20,9 +20,6 @@ package org.apache.maven.archiva.policies; */ -import java.io.File; -import java.util.Properties; - /** * Policy to apply before the download is attempted. * @@ -31,18 +28,4 @@ import java.util.Properties; */ public interface PreDownloadPolicy extends DownloadPolicy { - /** - * Apply the download policy. - * - * A true result lets the download occur. A false result prevents the download - * from occuring. - * - * @param policySetting the policy setting. - * @param request the list of request properties that the policy might use. - * @param localFile the local file that this policy affects - * - * @throws PolicyViolationException if the policy has been violated. - */ - public void applyPolicy( String policySetting, Properties request, File localFile ) - throws PolicyViolationException, PolicyConfigurationException; } diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PropagateErrorsDownloadPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PropagateErrorsDownloadPolicy.java new file mode 100644 index 000000000..cca1c6750 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PropagateErrorsDownloadPolicy.java @@ -0,0 +1,118 @@ +package org.apache.maven.archiva.policies; + +/* + * 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. + */ + +import org.apache.commons.lang.StringUtils; +import org.codehaus.plexus.logging.AbstractLogEnabled; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * PropagateErrorsPolicy - a policy applied on error to determine how to treat the error. + * + * @plexus.component role="org.apache.maven.archiva.policies.DownloadErrorPolicy" + * role-hint="propagate-errors" + */ +public class PropagateErrorsDownloadPolicy + extends AbstractLogEnabled + implements DownloadErrorPolicy +{ + /** + * Signifies any error should stop searching for other proxies. + */ + public static final String STOP = "stop"; + + /** + * Propagate errors at the end after all are gathered, if there was no successful download from other proxies. + */ + public static final String QUEUE = "queue error"; + + /** + * Ignore errors and treat as if it were not found. + */ + public static final String IGNORE = "ignore"; + + private List options = new ArrayList(); + + public PropagateErrorsDownloadPolicy() + { + options.add( STOP ); + options.add( QUEUE ); + options.add( IGNORE ); + } + + public boolean applyPolicy( String policySetting, Properties request, File localFile, Exception exception, + Map previousExceptions ) + throws PolicyConfigurationException + { + if ( !options.contains( policySetting ) ) + { + // Not a valid code. + throw new PolicyConfigurationException( "Unknown error policy setting [" + policySetting + + "], valid settings are [" + StringUtils.join( options.iterator(), "," ) + "]" ); + } + + if ( IGNORE.equals( policySetting ) ) + { + // Ignore. + getLogger().debug( "Error policy set to IGNORE." ); + return false; + } + + String repositoryId = request.getProperty( "remoteRepositoryId" ); + if ( STOP.equals( policySetting ) ) + { + return true; + } + + if ( QUEUE.equals( policySetting ) ) + { + previousExceptions.put( repositoryId, exception ); + return true; + } + + throw new PolicyConfigurationException( + "Unable to process checksum policy of [" + policySetting + "], please file a bug report." ); + } + + public String getDefaultOption() + { + return QUEUE; + } + + public String getId() + { + return "propagate-errors"; + } + + public String getName() + { + return "On remote error"; + } + + public List getOptions() + { + return options; + } +} \ No newline at end of file diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PropagateErrorsOnUpdateDownloadPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PropagateErrorsOnUpdateDownloadPolicy.java new file mode 100644 index 000000000..d2b471af3 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/PropagateErrorsOnUpdateDownloadPolicy.java @@ -0,0 +1,105 @@ +package org.apache.maven.archiva.policies; + +/* + * 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. + */ + +import org.apache.commons.lang.StringUtils; +import org.codehaus.plexus.logging.AbstractLogEnabled; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * PropagateErrorsPolicy - a policy applied on error to determine how to treat the error. + * + * @plexus.component role="org.apache.maven.archiva.policies.DownloadErrorPolicy" + * role-hint="propagate-errors-on-update" + */ +public class PropagateErrorsOnUpdateDownloadPolicy + extends AbstractLogEnabled + implements DownloadErrorPolicy +{ + /** + * Signifies any error should cause a failure whether the artifact is already present or not. + */ + public static final String ALWAYS = "always"; + + /** + * Signifies any error should cause a failure only if the artifact is not already present. + */ + public static final String NOT_PRESENT = "artifact not already present"; + + private List options = new ArrayList(); + + public PropagateErrorsOnUpdateDownloadPolicy() + { + options.add( ALWAYS ); + options.add( NOT_PRESENT ); + } + + public boolean applyPolicy( String policySetting, Properties request, File localFile, Exception exception, + Map previousExceptions ) + throws PolicyConfigurationException + { + if ( !options.contains( policySetting ) ) + { + // Not a valid code. + throw new PolicyConfigurationException( "Unknown error policy setting [" + policySetting + + "], valid settings are [" + StringUtils.join( options.iterator(), "," ) + "]" ); + } + + if ( ALWAYS.equals( policySetting ) ) + { + // throw ther exception regardless + return true; + } + + if ( NOT_PRESENT.equals( policySetting ) ) + { + // cancel the exception if the file exists + return !localFile.exists(); + } + + throw new PolicyConfigurationException( "Unable to process checksum policy of [" + policySetting + + "], please file a bug report." ); + } + + public String getDefaultOption() + { + return NOT_PRESENT; + } + + public String getId() + { + return "propagate-errors-on-update"; + } + + public String getName() + { + return "Return error when"; + } + + public List getOptions() + { + return options; + } +} \ No newline at end of file diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ProxyDownloadException.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ProxyDownloadException.java new file mode 100644 index 000000000..9d328c6b7 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ProxyDownloadException.java @@ -0,0 +1,66 @@ +package org.apache.maven.archiva.policies; + +/* + * 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. + */ + +import org.apache.maven.archiva.common.ArchivaException; + +import java.util.Collections; +import java.util.Map; + +/** + * One or more exceptions occurred downloading from a remote repository during the proxy phase. + */ +public class ProxyDownloadException + extends ArchivaException +{ + /** + * A list of failures keyed by repository ID. + */ + private final Map failures; + + public ProxyDownloadException( String message, String repositoryId, Exception cause ) + { + super( constructMessage( message, Collections.singletonMap( repositoryId, cause ) ), cause ); + + failures = Collections.singletonMap( repositoryId, cause ); + } + + public ProxyDownloadException( String message, Map failures ) + { + super( constructMessage( message, failures ) ); + + this.failures = failures; + } + + private static String constructMessage( String message, Map failures ) + { + String msg = message + ":"; + for ( Map.Entry entry : failures.entrySet() ) + { + msg += "\n\t" + entry.getKey() + ": " + entry.getValue().getMessage(); + } + return msg; + } + + public Map getFailures() + { + return failures; + } +} diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ReleasesPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ReleasesPolicy.java index 8b53461a8..86ad7c3fc 100644 --- a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ReleasesPolicy.java +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/ReleasesPolicy.java @@ -55,4 +55,9 @@ public class ReleasesPolicy { return "releases"; } + + public String getName() + { + return "Releases"; + } } diff --git a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/SnapshotsPolicy.java b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/SnapshotsPolicy.java index ffa903262..ea10023c3 100644 --- a/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/SnapshotsPolicy.java +++ b/archiva-modules/archiva-base/archiva-policies/src/main/java/org/apache/maven/archiva/policies/SnapshotsPolicy.java @@ -55,4 +55,9 @@ public class SnapshotsPolicy { return "snapshots"; } + + public String getName() + { + return "Snapshots"; + } } diff --git a/archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/maven/archiva/proxy/DefaultRepositoryProxyConnectors.java b/archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/maven/archiva/proxy/DefaultRepositoryProxyConnectors.java index f0b867481..1954f827d 100644 --- a/archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/maven/archiva/proxy/DefaultRepositoryProxyConnectors.java +++ b/archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/maven/archiva/proxy/DefaultRepositoryProxyConnectors.java @@ -19,16 +19,6 @@ package org.apache.maven.archiva.proxy; * under the License. */ -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Map.Entry; - import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; @@ -41,11 +31,13 @@ import org.apache.maven.archiva.model.Keys; import org.apache.maven.archiva.model.ProjectReference; import org.apache.maven.archiva.model.RepositoryURL; import org.apache.maven.archiva.model.VersionedReference; +import org.apache.maven.archiva.policies.DownloadErrorPolicy; import org.apache.maven.archiva.policies.DownloadPolicy; import org.apache.maven.archiva.policies.PolicyConfigurationException; import org.apache.maven.archiva.policies.PolicyViolationException; import org.apache.maven.archiva.policies.PostDownloadPolicy; import org.apache.maven.archiva.policies.PreDownloadPolicy; +import org.apache.maven.archiva.policies.ProxyDownloadException; import org.apache.maven.archiva.policies.urlcache.UrlFailureCache; import org.apache.maven.archiva.repository.ContentNotFoundException; import org.apache.maven.archiva.repository.ManagedRepositoryContent; @@ -73,11 +65,23 @@ import org.codehaus.plexus.util.SelectorUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + /** * DefaultRepositoryProxyConnectors * * @author Joakim Erdfelt * @version $Id$ + * @todo exception handling needs work - "not modified" is not really an exceptional case, and it has more layers than your average brown onion * @plexus.component role-hint="default" */ public class DefaultRepositoryProxyConnectors @@ -116,7 +120,12 @@ public class DefaultRepositoryProxyConnectors private Map postDownloadPolicies; /** - * @plexus.requirement + * @plexus.requirement role="org.apache.maven.archiva.policies.DownloadErrorPolicy" + */ + private Map downloadErrorPolicies; + + /** + * @plexus.requirement role-hint="default" */ private UrlFailureCache urlFailureCache; @@ -136,26 +145,31 @@ public class DefaultRepositoryProxyConnectors * @param artifact the artifact reference to fetch. * @return the local file in the managed repository that was fetched, or null if the artifact was not (or * could not be) fetched. - * @throws ProxyException if there was a problem fetching the artifact. + * @throws PolicyViolationException if there was a problem fetching the artifact. */ public File fetchFromProxies( ManagedRepositoryContent repository, ArtifactReference artifact ) + throws ProxyDownloadException { File localFile = toLocalFile( repository, artifact ); Properties requestProperties = new Properties(); requestProperties.setProperty( "filetype", "artifact" ); requestProperties.setProperty( "version", artifact.getVersion() ); + requestProperties.setProperty( "managedRepositoryId", repository.getId() ); List connectors = getProxyConnectors( repository ); + Map previousExceptions = new LinkedHashMap(); for ( ProxyConnector connector : connectors ) { RemoteRepositoryContent targetRepository = connector.getTargetRepository(); + requestProperties.setProperty( "remoteRepositoryId", targetRepository.getId() ); + String targetPath = targetRepository.toPath( artifact ); try { - File downloadedFile = transferFile( connector, targetRepository, targetPath, localFile, - requestProperties ); + File downloadedFile = + transferFile( connector, targetRepository, targetPath, localFile, requestProperties ); if ( fileExists( downloadedFile ) ) { @@ -175,12 +189,17 @@ public class DefaultRepositoryProxyConnectors } catch ( ProxyException e ) { - log.warn( "Transfer error from repository \"" + targetRepository.getRepository().getId() + - "\" for artifact " + Keys.toKey( artifact ) + ", continuing to next repository. Error message: " + - e.getMessage() ); - log.debug( "Full stack trace", e ); + validatePolicies( this.downloadErrorPolicies, connector.getPolicies(), requestProperties, artifact, + targetRepository, localFile, e, previousExceptions ); } } + + if ( !previousExceptions.isEmpty() ) + { + throw new ProxyDownloadException( "Failures occurred downloading from some remote repositories", + previousExceptions ); + } + log.debug( "Exhausted all target repositories, artifact " + Keys.toKey( artifact ) + " not found." ); return null; @@ -471,10 +490,10 @@ public class DefaultRepositoryProxyConnectors * @param localFile the local file to place the downloaded resource into * @param requestProperties the request properties to utilize for policy handling. * @return the local file that was downloaded, or null if not downloaded. - * @throws NotFoundException if the file was not found on the remote repository. + * @throws NotFoundException if the file was not found on the remote repository. * @throws NotModifiedException if the localFile was present, and the resource was present on remote repository, * but the remote resource is not newer than the local File. - * @throws ProxyException if transfer was unsuccessful. + * @throws ProxyException if transfer was unsuccessful. */ private File transferFile( ProxyConnector connector, RemoteRepositoryContent remoteRepository, String remotePath, File localFile, Properties requestProperties ) @@ -696,8 +715,8 @@ public class DefaultRepositoryProxyConnectors success = wagon.getIfNewer( remotePath, temp, localFile.lastModified() ); if ( !success ) { - throw new NotModifiedException( "Not downloaded, as local file is newer than remote side: " - + localFile.getAbsolutePath() ); + throw new NotModifiedException( + "Not downloaded, as local file is newer than remote side: " + localFile.getAbsolutePath() ); } if ( temp.exists() ) @@ -711,13 +730,15 @@ public class DefaultRepositoryProxyConnectors } catch ( ResourceDoesNotExistException e ) { - throw new NotFoundException( "Resource [" + remoteRepository.getURL() + "/" + remotePath - + "] does not exist: " + e.getMessage(), e ); + throw new NotFoundException( + "Resource [" + remoteRepository.getURL() + "/" + remotePath + "] does not exist: " + e.getMessage(), + e ); } catch ( WagonException e ) { - throw new ProxyException( "Download failure on resource [" + remoteRepository.getURL() + "/" + remotePath + "]:" - + e.getMessage(), e ); + throw new ProxyException( + "Download failure on resource [" + remoteRepository.getURL() + "/" + remotePath + "]:" + e.getMessage(), + e ); } finally { @@ -742,10 +763,10 @@ public class DefaultRepositoryProxyConnectors { for ( Entry entry : policies.entrySet() ) { - String key = (String) entry.getKey(); + String key = entry.getKey(); DownloadPolicy policy = entry.getValue(); String defaultSetting = policy.getDefaultOption(); - String setting = StringUtils.defaultString( (String) settings.get( key ), defaultSetting ); + String setting = StringUtils.defaultString( settings.get( key ), defaultSetting ); log.debug( "Applying [" + key + "] policy with [" + setting + "]" ); try @@ -759,6 +780,56 @@ public class DefaultRepositoryProxyConnectors } } + private void validatePolicies( Map policies, Map settings, + Properties request, ArtifactReference artifact, RemoteRepositoryContent content, + File localFile, ProxyException exception, Map previousExceptions ) + throws ProxyDownloadException + { + boolean process = true; + for ( Entry entry : policies.entrySet() ) + { + String key = entry.getKey(); + DownloadErrorPolicy policy = entry.getValue(); + String defaultSetting = policy.getDefaultOption(); + String setting = StringUtils.defaultString( settings.get( key ), defaultSetting ); + + log.debug( "Applying [" + key + "] policy with [" + setting + "]" ); + try + { + // all policies must approve the exception, any can cancel + process = policy.applyPolicy( setting, request, localFile, exception, previousExceptions ); + if ( !process ) + { + break; + } + } + catch ( PolicyConfigurationException e ) + { + log.error( e.getMessage(), e ); + } + } + + if ( process ) + { + // if the exception was queued, don't throw it + if ( !previousExceptions.containsKey( content.getId() ) ) + { + throw new ProxyDownloadException( + "An error occurred in downloading from the remote repository, and the policy is to fail immediately", + content.getId(), exception ); + } + } + else + { + // if the exception was queued, but cancelled, remove it + previousExceptions.remove( content.getId() ); + } + + log.warn( "Transfer error from repository \"" + content.getRepository().getId() + "\" for artifact " + + Keys.toKey( artifact ) + ", continuing to next repository. Error message: " + exception.getMessage() ); + log.debug( "Full stack trace", exception ); + } + /** * Used to move the temporary file to its real destination. This is patterned from the way WagonManager handles * its downloaded files. @@ -802,7 +873,8 @@ public class DefaultRepositoryProxyConnectors * @param remoteRepository the remote repository to connect to. * @return true if the connection was successful. false if not connected. */ - private boolean connectToRepository( ProxyConnector connector, Wagon wagon, RemoteRepositoryContent remoteRepository ) + private boolean connectToRepository( ProxyConnector connector, Wagon wagon, + RemoteRepositoryContent remoteRepository ) { boolean connected = false; @@ -851,15 +923,13 @@ public class DefaultRepositoryProxyConnectors catch ( ConnectionException e ) { log.warn( - "Could not connect to " + remoteRepository.getRepository().getName() + ": " - + e.getMessage() ); + "Could not connect to " + remoteRepository.getRepository().getName() + ": " + e.getMessage() ); connected = false; } catch ( AuthenticationException e ) { log.warn( - "Could not connect to " + remoteRepository.getRepository().getName() + ": " - + e.getMessage() ); + "Could not connect to " + remoteRepository.getRepository().getName() + ": " + e.getMessage() ); connected = false; } @@ -911,10 +981,10 @@ public class DefaultRepositoryProxyConnectors public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue ) { - if ( ConfigurationNames.isNetworkProxy( propertyName ) - || ConfigurationNames.isManagedRepositories( propertyName ) - || ConfigurationNames.isRemoteRepositories( propertyName ) - || ConfigurationNames.isProxyConnector( propertyName ) ) + if ( ConfigurationNames.isNetworkProxy( propertyName ) || + ConfigurationNames.isManagedRepositories( propertyName ) || + ConfigurationNames.isRemoteRepositories( propertyName ) || + ConfigurationNames.isProxyConnector( propertyName ) ) { initConnectorsAndNetworkProxies(); } diff --git a/archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/maven/archiva/proxy/RepositoryProxyConnectors.java b/archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/maven/archiva/proxy/RepositoryProxyConnectors.java index 6d832bfbb..c27c5b8ab 100644 --- a/archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/maven/archiva/proxy/RepositoryProxyConnectors.java +++ b/archiva-modules/archiva-base/archiva-proxy/src/main/java/org/apache/maven/archiva/proxy/RepositoryProxyConnectors.java @@ -22,6 +22,7 @@ package org.apache.maven.archiva.proxy; import org.apache.maven.archiva.model.ArtifactReference; import org.apache.maven.archiva.model.ProjectReference; import org.apache.maven.archiva.model.VersionedReference; +import org.apache.maven.archiva.policies.ProxyDownloadException; import org.apache.maven.archiva.repository.ManagedRepositoryContent; import java.io.File; @@ -45,11 +46,11 @@ public interface RepositoryProxyConnectors * @param repository the source repository to use. (must be a managed repository) * @param artifact the artifact to fetch. * @return true if the fetch operation succeeded in obtaining content, false if no content was obtained. - * @throws ProxyException if there was a problem fetching the content from the target repositories. + * @throws ProxyDownloadException if there was a problem fetching the content from the target repositories. */ public File fetchFromProxies( ManagedRepositoryContent repository, ArtifactReference artifact ) - throws ProxyException; - + throws ProxyDownloadException; + /** * Performs the metadata fetch operation against the target repositories * of the provided source repository. @@ -60,11 +61,9 @@ public interface RepositoryProxyConnectors * @param repository the source repository to use. (must be a managed repository) * @param metadata the metadata to fetch. * @return true if the fetch operation succeeded in obtaining content, false if no content was obtained. - * @throws ProxyException if there was a problem fetching the content from the target repositories. */ - public File fetchFromProxies( ManagedRepositoryContent repository, VersionedReference metadata ) - throws ProxyException; - + public File fetchFromProxies( ManagedRepositoryContent repository, VersionedReference metadata ); + /** * Performs the metadata fetch operation against the target repositories * of the provided source repository. @@ -75,10 +74,8 @@ public interface RepositoryProxyConnectors * @param repository the source repository to use. (must be a managed repository) * @param metadata the metadata to fetch. * @return true if the fetch operation succeeded in obtaining content, false if no content was obtained. - * @throws ProxyException if there was a problem fetching the content from the target repositories. */ - public File fetchFromProxies( ManagedRepositoryContent repository, ProjectReference metadata ) - throws ProxyException; + public File fetchFromProxies( ManagedRepositoryContent repository, ProjectReference metadata ); /** * Get the List of {@link ProxyConnector} objects of the source repository. diff --git a/archiva-modules/archiva-base/archiva-proxy/src/test/java/org/apache/maven/archiva/proxy/AbstractProxyTestCase.java b/archiva-modules/archiva-base/archiva-proxy/src/test/java/org/apache/maven/archiva/proxy/AbstractProxyTestCase.java index c6a5f3e7f..88518a078 100644 --- a/archiva-modules/archiva-base/archiva-proxy/src/test/java/org/apache/maven/archiva/proxy/AbstractProxyTestCase.java +++ b/archiva-modules/archiva-base/archiva-proxy/src/test/java/org/apache/maven/archiva/proxy/AbstractProxyTestCase.java @@ -37,6 +37,8 @@ import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration; import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration; import org.apache.maven.archiva.policies.CachedFailuresPolicy; import org.apache.maven.archiva.policies.ChecksumPolicy; +import org.apache.maven.archiva.policies.PropagateErrorsDownloadPolicy; +import org.apache.maven.archiva.policies.PropagateErrorsOnUpdateDownloadPolicy; import org.apache.maven.archiva.policies.ReleasesPolicy; import org.apache.maven.archiva.policies.SnapshotsPolicy; import org.apache.maven.archiva.repository.ManagedRepositoryContent; @@ -295,8 +297,23 @@ public abstract class AbstractProxyTestCase SnapshotsPolicy.ALWAYS, CachedFailuresPolicy.NO ); } - protected void saveConnector( String sourceRepoId, String targetRepoId, String checksumPolicy, - String releasePolicy, String snapshotPolicy, String cacheFailuresPolicy ) + protected void saveConnector( String sourceRepoId, String targetRepoId, String checksumPolicy, String releasePolicy, + String snapshotPolicy, String cacheFailuresPolicy ) + { + saveConnector( sourceRepoId, targetRepoId, checksumPolicy, releasePolicy, snapshotPolicy, cacheFailuresPolicy, + PropagateErrorsDownloadPolicy.QUEUE ); + } + + protected void saveConnector( String sourceRepoId, String targetRepoId, String checksumPolicy, String releasePolicy, + String snapshotPolicy, String cacheFailuresPolicy, String errorPolicy ) + { + saveConnector( sourceRepoId, targetRepoId, checksumPolicy, releasePolicy, snapshotPolicy, cacheFailuresPolicy, + errorPolicy, PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + } + + protected void saveConnector( String sourceRepoId, String targetRepoId, String checksumPolicy, String releasePolicy, + String snapshotPolicy, String cacheFailuresPolicy, String errorPolicy, + String errorOnUpdatePolicy ) { ProxyConnectorConfiguration connectorConfig = new ProxyConnectorConfiguration(); connectorConfig.setSourceRepoId( sourceRepoId ); @@ -305,6 +322,8 @@ public abstract class AbstractProxyTestCase connectorConfig.addPolicy( ProxyConnectorConfiguration.POLICY_RELEASES, releasePolicy ); connectorConfig.addPolicy( ProxyConnectorConfiguration.POLICY_SNAPSHOTS, snapshotPolicy ); connectorConfig.addPolicy( ProxyConnectorConfiguration.POLICY_CACHE_FAILURES, cacheFailuresPolicy ); + connectorConfig.addPolicy( ProxyConnectorConfiguration.POLICY_PROPAGATE_ERRORS, errorPolicy ); + connectorConfig.addPolicy( ProxyConnectorConfiguration.POLICY_PROPAGATE_ERRORS_ON_UPDATE, errorOnUpdatePolicy ); int count = config.getConfiguration().getProxyConnectors().size(); config.getConfiguration().addProxyConnector( connectorConfig ); @@ -318,6 +337,10 @@ public abstract class AbstractProxyTestCase config.triggerChange( prefix + ".policies.checksum", connectorConfig.getPolicy( "checksum", "" ) ); config.triggerChange( prefix + ".policies.snapshots", connectorConfig.getPolicy( "snapshots", "" ) ); config.triggerChange( prefix + ".policies.cache-failures", connectorConfig.getPolicy( "cache-failures", "" ) ); + config.triggerChange( prefix + ".policies.propagate-errors", + connectorConfig.getPolicy( "propagate-errors", "" ) ); + config.triggerChange( prefix + ".policies.propagate-errors-on-update", + connectorConfig.getPolicy( "propagate-errors-on-update", "" ) ); } protected void saveManagedRepositoryConfig( String id, String name, String path, String layout ) diff --git a/archiva-modules/archiva-base/archiva-proxy/src/test/java/org/apache/maven/archiva/proxy/ErrorHandlingTest.java b/archiva-modules/archiva-base/archiva-proxy/src/test/java/org/apache/maven/archiva/proxy/ErrorHandlingTest.java new file mode 100644 index 000000000..0e62f8273 --- /dev/null +++ b/archiva-modules/archiva-base/archiva-proxy/src/test/java/org/apache/maven/archiva/proxy/ErrorHandlingTest.java @@ -0,0 +1,627 @@ +package org.apache.maven.archiva.proxy; + +/* + * 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. + */ + +import org.apache.maven.archiva.policies.CachedFailuresPolicy; +import org.apache.maven.archiva.policies.ChecksumPolicy; +import org.apache.maven.archiva.policies.PropagateErrorsDownloadPolicy; +import org.apache.maven.archiva.policies.PropagateErrorsOnUpdateDownloadPolicy; +import org.apache.maven.archiva.policies.ProxyDownloadException; +import org.apache.maven.archiva.policies.ReleasesPolicy; +import org.apache.maven.archiva.policies.SnapshotsPolicy; +import org.apache.maven.archiva.repository.layout.LayoutException; +import org.apache.maven.wagon.ResourceDoesNotExistException; +import org.apache.maven.wagon.TransferFailedException; +import org.apache.maven.wagon.authorization.AuthorizationException; + +import java.io.File; + +/** + * ErrorHandlingTest + * + * @author Brett Porter + * @version $Id$ + */ +public class ErrorHandlingTest + extends AbstractProxyTestCase +{ + private static final String PATH_IN_BOTH_REMOTES_NOT_LOCAL = + "org/apache/maven/test/get-in-both-proxies/1.0/get-in-both-proxies-1.0.jar"; + + private static final String PATH_IN_BOTH_REMOTES_AND_LOCAL = + "org/apache/maven/test/get-on-multiple-repos/1.0/get-on-multiple-repos-1.0.pom"; + + private static final String ID_MOCKED_PROXIED1 = "badproxied1"; + + private static final String NAME_MOCKED_PROXIED1 = "Bad Proxied 1"; + + private static final String ID_MOCKED_PROXIED2 = "badproxied2"; + + private static final String NAME_MOCKED_PROXIED2 = "Bad Proxied 2"; + + public void testPropagateErrorImmediatelyWithErrorThenSuccess() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.STOP ); + saveConnector( ID_DEFAULT_MANAGED, ID_PROXIED2 ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmSingleFailure( path, ID_MOCKED_PROXIED1 ); + } + + public void testPropagateErrorImmediatelyWithNotFoundThenError() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.STOP ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.STOP ); + + simulateGetError( path, expectedFile, createResourceNotFoundException() ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmSingleFailure( path, ID_MOCKED_PROXIED2 ); + } + + public void testPropagateErrorImmediatelyWithSuccessThenError() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + saveConnector( ID_DEFAULT_MANAGED, ID_PROXIED1 ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.STOP ); + + confirmSuccess( path, expectedFile, REPOPATH_PROXIED1 ); + } + + public void testPropagateErrorImmediatelyWithNotFoundThenSuccess() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.STOP ); + + saveConnector( ID_DEFAULT_MANAGED, ID_PROXIED2 ); + + simulateGetError( path, expectedFile, createResourceNotFoundException() ); + + confirmSuccess( path, expectedFile, REPOPATH_PROXIED2 ); + } + + public void testPropagateErrorAtEndWithErrorThenSuccess() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.STOP ); + + saveConnector( ID_DEFAULT_MANAGED, ID_PROXIED2 ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmSingleFailure( path, ID_MOCKED_PROXIED1 ); + } + + public void testPropagateErrorAtEndWithSuccessThenError() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + saveConnector( ID_DEFAULT_MANAGED, ID_PROXIED1 ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.QUEUE ); + + confirmSuccess( path, expectedFile, REPOPATH_PROXIED1 ); + } + + public void testPropagateErrorAtEndWithNotFoundThenError() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.QUEUE ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.QUEUE ); + + simulateGetError( path, expectedFile, createResourceNotFoundException() ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmSingleFailure( path, ID_MOCKED_PROXIED2 ); + } + + public void testPropagateErrorAtEndWithErrorThenNotFound() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.QUEUE ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.QUEUE ); + + simulateGetError( path, expectedFile, createTransferException() ); + + simulateGetError( path, expectedFile, createResourceNotFoundException() ); + + confirmSingleFailure( path, ID_MOCKED_PROXIED1 ); + } + + public void testPropagateErrorAtEndWithErrorThenError() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.QUEUE ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.QUEUE ); + + simulateGetError( path, expectedFile, createTransferException() ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmFailures( path, new String[]{ID_MOCKED_PROXIED1, ID_MOCKED_PROXIED2} ); + } + + public void testPropagateErrorAtEndWithNotFoundThenSuccess() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.QUEUE ); + + saveConnector( ID_DEFAULT_MANAGED, ID_PROXIED2 ); + + simulateGetError( path, expectedFile, createResourceNotFoundException() ); + + confirmSuccess( path, expectedFile, REPOPATH_PROXIED2 ); + } + + public void testIgnoreErrorWithErrorThenSuccess() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.IGNORE ); + + saveConnector( ID_DEFAULT_MANAGED, ID_PROXIED2 ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmSuccess( path, expectedFile, REPOPATH_PROXIED2 ); + } + + public void testIgnoreErrorWithSuccessThenError() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + saveConnector( ID_DEFAULT_MANAGED, ID_PROXIED1 ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.IGNORE ); + + confirmSuccess( path, expectedFile, REPOPATH_PROXIED1 ); + } + + public void testIgnoreErrorWithNotFoundThenError() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.IGNORE ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.IGNORE ); + + simulateGetError( path, expectedFile, createResourceNotFoundException() ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmNotDownloadedNoError( path ); + } + + public void testIgnoreErrorWithErrorThenNotFound() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.IGNORE ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.IGNORE ); + + simulateGetError( path, expectedFile, createTransferException() ); + + simulateGetError( path, expectedFile, createResourceNotFoundException() ); + + confirmNotDownloadedNoError( path ); + } + + public void testIgnoreErrorWithErrorThenError() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.IGNORE ); + + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.IGNORE ); + + simulateGetError( path, expectedFile, createTransferException() ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmNotDownloadedNoError( path ); + } + + public void testPropagateOnUpdateAlwaysArtifactNotPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.STOP, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.STOP, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmSingleFailure( path, ID_MOCKED_PROXIED1 ); + } + + public void testPropagateOnUpdateAlwaysArtifactPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_AND_LOCAL; + File expectedFile = setupRepositoriesWithLocalFilePresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.STOP, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.STOP, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + + confirmSingleFailure( path, ID_MOCKED_PROXIED1 ); + } + + public void testPropagateOnUpdateAlwaysQueueArtifactNotPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.QUEUE, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.QUEUE, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + + simulateGetError( path, expectedFile, createTransferException() ); + simulateGetError( path, expectedFile, createTransferException() ); + + confirmFailures( path, new String[] { ID_MOCKED_PROXIED1, ID_MOCKED_PROXIED2 } ); + } + + public void testPropagateOnUpdateAlwaysQueueArtifactPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_AND_LOCAL; + File expectedFile = setupRepositoriesWithLocalFilePresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.QUEUE, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.QUEUE, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + + confirmFailures( path, new String[] { ID_MOCKED_PROXIED1, ID_MOCKED_PROXIED2 } ); + } + + public void testPropagateOnUpdateAlwaysIgnoreArtifactNotPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.IGNORE, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.IGNORE, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + + simulateGetError( path, expectedFile, createTransferException() ); + simulateGetError( path, expectedFile, createTransferException() ); + + confirmNotDownloadedNoError( path ); + } + + public void testPropagateOnUpdateAlwaysIgnoreArtifactPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_AND_LOCAL; + File expectedFile = setupRepositoriesWithLocalFilePresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.IGNORE, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.IGNORE, + PropagateErrorsOnUpdateDownloadPolicy.ALWAYS ); + + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + + confirmNotDownloadedNoError( path ); + assertTrue( expectedFile.exists() ); + } + + public void testPropagateOnUpdateNotPresentArtifactNotPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.STOP, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.STOP, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + + simulateGetError( path, expectedFile, createTransferException() ); + + confirmSingleFailure( path, ID_MOCKED_PROXIED1 ); + } + + public void testPropagateOnUpdateNotPresentArtifactPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_AND_LOCAL; + File expectedFile = setupRepositoriesWithLocalFilePresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.STOP, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.STOP, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + + confirmNotDownloadedNoError( path ); + assertTrue( expectedFile.exists() ); + } + + public void testPropagateOnUpdateNotPresentQueueArtifactNotPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.QUEUE, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.QUEUE, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + + simulateGetError( path, expectedFile, createTransferException() ); + simulateGetError( path, expectedFile, createTransferException() ); + + confirmFailures( path, new String[] { ID_MOCKED_PROXIED1, ID_MOCKED_PROXIED2 } ); + } + + public void testPropagateOnUpdateNotPresentQueueArtifactPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_AND_LOCAL; + File expectedFile = setupRepositoriesWithLocalFilePresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.QUEUE, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.QUEUE, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + + confirmNotDownloadedNoError( path ); + assertTrue( expectedFile.exists() ); + } + + public void testPropagateOnUpdateNotPresentIgnoreArtifactNotPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_NOT_LOCAL; + File expectedFile = setupRepositoriesWithLocalFileNotPresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.IGNORE, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.IGNORE, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + + simulateGetError( path, expectedFile, createTransferException() ); + simulateGetError( path, expectedFile, createTransferException() ); + + confirmNotDownloadedNoError( path ); + } + + public void testPropagateOnUpdateNotPresentIgnoreArtifactPresent() + throws Exception + { + String path = PATH_IN_BOTH_REMOTES_AND_LOCAL; + File expectedFile = setupRepositoriesWithLocalFilePresent( path ); + + createMockedProxyConnector( ID_MOCKED_PROXIED1, NAME_MOCKED_PROXIED1, PropagateErrorsDownloadPolicy.IGNORE, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + createMockedProxyConnector( ID_MOCKED_PROXIED2, NAME_MOCKED_PROXIED2, PropagateErrorsDownloadPolicy.IGNORE, + PropagateErrorsOnUpdateDownloadPolicy.NOT_PRESENT ); + + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + simulateGetIfNewerError( path, expectedFile, createTransferException() ); + + confirmNotDownloadedNoError( path ); + assertTrue( expectedFile.exists() ); + } + + // ------------------------------------------ + // HELPER METHODS + // ------------------------------------------ + + private void createMockedProxyConnector( String id, String name, String errorPolicy ) + { + saveRemoteRepositoryConfig( id, name, "test://bad.machine.com/repo/", "default" ); + saveConnector( ID_DEFAULT_MANAGED, id, ChecksumPolicy.FIX, ReleasesPolicy.ALWAYS, SnapshotsPolicy.ALWAYS, + CachedFailuresPolicy.NO, errorPolicy ); + } + + private void createMockedProxyConnector( String id, String name, String errorPolicy, String errorOnUpdatePolicy ) + { + saveRemoteRepositoryConfig( id, name, "test://bad.machine.com/repo/", "default" ); + saveConnector( ID_DEFAULT_MANAGED, id, ChecksumPolicy.FIX, ReleasesPolicy.ALWAYS, SnapshotsPolicy.ALWAYS, + CachedFailuresPolicy.NO, errorPolicy, errorOnUpdatePolicy ); + } + + private File setupRepositoriesWithLocalFileNotPresent( String path ) + throws Exception + { + setupTestableManagedRepository( path ); + + File file = new File( managedDefaultDir, path ); + + assertNotExistsInManagedDefaultRepo( file ); + + return file; + } + + private File setupRepositoriesWithLocalFilePresent( String path ) + throws Exception + { + setupTestableManagedRepository( path ); + + File file = new File( managedDefaultDir, path ); + + assertTrue( file.exists() ); + + return file; + } + + private void simulateGetError( String path, File expectedFile, Exception throwable ) + throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException + { + wagonMock.get( path, createExpectedTempFile( expectedFile ) ); + wagonMockControl.setThrowable( throwable, 1 ); + } + + private void simulateGetIfNewerError( String path, File expectedFile, TransferFailedException exception ) + throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException + { + wagonMock.getIfNewer( path, createExpectedTempFile( expectedFile ), expectedFile.lastModified() ); + wagonMockControl.setThrowable( exception, 1 ); + } + + private File createExpectedTempFile( File expectedFile ) + { + return new File( expectedFile.getParentFile(), expectedFile.getName() + ".tmp" ).getAbsoluteFile(); + } + + private void confirmSingleFailure( String path, String id ) + throws LayoutException + { + confirmFailures( path, new String[]{id} ); + } + + private void confirmFailures( String path, String[] ids ) + throws LayoutException + { + wagonMockControl.replay(); + + // Attempt the proxy fetch. + File downloadedFile = null; + try + { + downloadedFile = proxyHandler.fetchFromProxies( managedDefaultRepository, + managedDefaultRepository.toArtifactReference( path ) ); + fail( "Proxy should not have succeeded" ); + } + catch ( ProxyDownloadException e ) + { + assertEquals( ids.length, e.getFailures().size() ); + for ( String id : ids ) + { + assertTrue( e.getFailures().keySet().contains( id ) ); + } + } + + wagonMockControl.verify(); + + assertNotDownloaded( downloadedFile ); + } + + private void confirmSuccess( String path, File expectedFile, String basedir ) + throws Exception + { + File downloadedFile = performDownload( path ); + + File proxied1File = new File( basedir, path ); + assertFileEquals( expectedFile, downloadedFile, proxied1File ); + } + + private void confirmNotDownloadedNoError( String path ) + throws Exception + { + File downloadedFile = performDownload( path ); + + assertNotDownloaded( downloadedFile ); + } + + private File performDownload( String path ) + throws ProxyDownloadException, LayoutException + { + wagonMockControl.replay(); + + // Attempt the proxy fetch. + File downloadedFile = proxyHandler.fetchFromProxies( managedDefaultRepository, + managedDefaultRepository.toArtifactReference( path ) ); + + wagonMockControl.verify(); + return downloadedFile; + } + + private static TransferFailedException createTransferException() + { + return new TransferFailedException( "test download exception" ); + } + + private static ResourceDoesNotExistException createResourceNotFoundException() + { + return new ResourceDoesNotExistException( "test download not found" ); + } +} \ No newline at end of file diff --git a/archiva-modules/archiva-base/archiva-proxy/src/test/resources/org/apache/maven/archiva/proxy/ErrorHandlingTest.xml b/archiva-modules/archiva-base/archiva-proxy/src/test/resources/org/apache/maven/archiva/proxy/ErrorHandlingTest.xml new file mode 100644 index 000000000..508b58bfc --- /dev/null +++ b/archiva-modules/archiva-base/archiva-proxy/src/test/resources/org/apache/maven/archiva/proxy/ErrorHandlingTest.xml @@ -0,0 +1,118 @@ + + + + + + org.apache.maven.wagon.Wagon + test + org.apache.maven.archiva.proxy.WagonDelegate + + + org.apache.maven.archiva.configuration.ArchivaConfiguration + mock + org.apache.maven.archiva.proxy.MockConfiguration + + + org.apache.maven.archiva.repository.RepositoryContentFactory + mocked + org.apache.maven.archiva.repository.RepositoryContentFactory + RepositoryContentRequest + + + org.apache.maven.archiva.configuration.ArchivaConfiguration + mock + archivaConfiguration + + + + + org.apache.maven.archiva.proxy.RepositoryProxyConnectors + default + org.apache.maven.archiva.proxy.DefaultRepositoryProxyConnectors + DefaultRepositoryProxyConnectors + + + org.apache.maven.archiva.configuration.ArchivaConfiguration + mock + archivaConfiguration + + + org.apache.maven.wagon.Wagon + wagons + + + org.apache.maven.archiva.repository.RepositoryContentFactory + mocked + + + org.apache.maven.archiva.repository.metadata.MetadataTools + + + org.apache.maven.archiva.policies.PreDownloadPolicy + preDownloadPolicies + + + org.apache.maven.archiva.policies.PostDownloadPolicy + postDownloadPolicies + + + org.apache.maven.archiva.policies.DownloadErrorPolicy + downloadErrorPolicies + + + org.apache.maven.archiva.policies.urlcache.UrlFailureCache + default + urlFailureCache + + + org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers + consumers + + + + + + org.codehaus.plexus.cache.Cache + url-failures-cache + org.codehaus.plexus.cache.ehcache.EhcacheCache + URL Failure Cache + + 600 + false + ${java.io.tmpdir}/archiva/urlcache + false + 1000 + LRU + url-failures-cache + false + + 2700 + + 1800 + + + + + org.codehaus.plexus.logging.LoggerManager + org.codehaus.plexus.logging.slf4j.Slf4jLoggerManager + basic + + + \ No newline at end of file diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/AbstractProxyConnectorFormAction.java b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/AbstractProxyConnectorFormAction.java index 68adb6c57..1318f5765 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/AbstractProxyConnectorFormAction.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/AbstractProxyConnectorFormAction.java @@ -22,7 +22,8 @@ package org.apache.maven.archiva.web.action.admin.connectors.proxy; import com.opensymphony.xwork.Preparable; import org.apache.commons.lang.StringUtils; import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration; -import org.apache.maven.archiva.policies.DownloadPolicy; +import org.apache.maven.archiva.policies.DownloadErrorPolicy; +import org.apache.maven.archiva.policies.Policy; import org.apache.maven.archiva.policies.PostDownloadPolicy; import org.apache.maven.archiva.policies.PreDownloadPolicy; @@ -54,6 +55,11 @@ public abstract class AbstractProxyConnectorFormAction */ private Map postDownloadPolicyMap; + /** + * @plexus.requirement role="org.apache.maven.archiva.policies.DownloadErrorPolicy" + */ + private Map downloadErrorPolicyMap; + /** * The list of network proxy ids that are available. */ @@ -72,7 +78,7 @@ public abstract class AbstractProxyConnectorFormAction /** * The map of policies that are available to be set. */ - private Map policyMap; + private Map policyMap; /** * The property key to add or remove. @@ -185,7 +191,7 @@ public abstract class AbstractProxyConnectorFormAction return pattern; } - public Map getPolicyMap() + public Map getPolicyMap() { return policyMap; } @@ -318,7 +324,7 @@ public abstract class AbstractProxyConnectorFormAction this.pattern = pattern; } - public void setPolicyMap( Map policyMap ) + public void setPolicyMap( Map policyMap ) { this.policyMap = policyMap; } @@ -363,12 +369,13 @@ public abstract class AbstractProxyConnectorFormAction return options; } - protected Map createPolicyMap() + protected Map createPolicyMap() { - Map policyMap = new HashMap(); + Map policyMap = new HashMap(); policyMap.putAll( preDownloadPolicyMap ); policyMap.putAll( postDownloadPolicyMap ); + policyMap.putAll( downloadErrorPolicyMap ); return policyMap; } @@ -387,10 +394,10 @@ public abstract class AbstractProxyConnectorFormAction else { // Validate / Fix policy settings arriving from browser. - for ( Map.Entry entry : getPolicyMap().entrySet() ) + for ( Map.Entry entry : getPolicyMap().entrySet() ) { - String policyId = (String) entry.getKey(); - DownloadPolicy policy = (DownloadPolicy) entry.getValue(); + String policyId = entry.getKey(); + Policy policy = entry.getValue(); List options = policy.getOptions(); if ( !connector.getPolicies().containsKey( policyId ) ) diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java index bafea90af..da8b31f5c 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java @@ -23,7 +23,7 @@ import org.apache.maven.archiva.common.utils.PathUtil; import org.apache.maven.archiva.model.ArtifactReference; import org.apache.maven.archiva.model.ProjectReference; import org.apache.maven.archiva.model.VersionedReference; -import org.apache.maven.archiva.proxy.ProxyException; +import org.apache.maven.archiva.policies.ProxyDownloadException; import org.apache.maven.archiva.proxy.RepositoryProxyConnectors; import org.apache.maven.archiva.repository.ManagedRepositoryContent; import org.apache.maven.archiva.repository.RepositoryContentFactory; @@ -364,7 +364,7 @@ public class ProxiedDavServer { /* eat it */ } - catch ( ProxyException e ) + catch ( ProxyDownloadException e ) { throw new ServletException( "Unable to fetch artifact resource.", e ); } @@ -391,10 +391,6 @@ public class ProxiedDavServer { /* eat it */ } - catch ( ProxyException e ) - { - throw new ServletException( "Unable to fetch versioned metadata resource.", e ); - } try { @@ -409,10 +405,6 @@ public class ProxiedDavServer { /* eat it */ } - catch ( ProxyException e ) - { - throw new ServletException( "Unable to fetch project metadata resource.", e ); - } return false; } @@ -428,7 +420,7 @@ public class ProxiedDavServer * artifact. */ protected void applyServerSideRelocation( ArtifactReference artifact ) - throws ProxyException + throws ProxyDownloadException { if ( "pom".equals( artifact.getType() ) ) { diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf index 52acf5881..6e04cee2d 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf +++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/jsp/admin/include/proxyConnectorForm.jspf @@ -42,7 +42,7 @@ ${policy.key}: + theme="simple">${policy.value.name}: diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/AddProxyConnectorActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/AddProxyConnectorActionTest.java index b4747e393..213ce9fbb 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/AddProxyConnectorActionTest.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/AddProxyConnectorActionTest.java @@ -28,6 +28,8 @@ import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration; import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration; import org.apache.maven.archiva.policies.CachedFailuresPolicy; import org.apache.maven.archiva.policies.ChecksumPolicy; +import org.apache.maven.archiva.policies.PropagateErrorsDownloadPolicy; +import org.apache.maven.archiva.policies.PropagateErrorsOnUpdateDownloadPolicy; import org.apache.maven.archiva.policies.ReleasesPolicy; import org.apache.maven.archiva.policies.SnapshotsPolicy; import org.apache.maven.archiva.web.action.AbstractWebworkTestCase; @@ -36,6 +38,7 @@ import org.codehaus.plexus.registry.RegistryException; import org.easymock.MockControl; import java.util.List; +import java.util.Map; /** * AddProxyConnectorActionTest @@ -390,10 +393,13 @@ public class AddProxyConnectorActionTest connector.setTargetRepoId( "central" ); // TODO: Set these options programatically via list of available policies. - connector.getPolicies().put( "releases", new ReleasesPolicy().getDefaultOption() ); - connector.getPolicies().put( "snapshots", new SnapshotsPolicy().getDefaultOption() ); - connector.getPolicies().put( "checksum", new ChecksumPolicy().getDefaultOption() ); - connector.getPolicies().put( "cache-failures", new CachedFailuresPolicy().getDefaultOption() ); + Map policies = connector.getPolicies(); + policies.put( "releases", new ReleasesPolicy().getDefaultOption() ); + policies.put( "snapshots", new SnapshotsPolicy().getDefaultOption() ); + policies.put( "checksum", new ChecksumPolicy().getDefaultOption() ); + policies.put( "cache-failures", new CachedFailuresPolicy().getDefaultOption() ); + policies.put( "propagate-errors", new PropagateErrorsDownloadPolicy().getDefaultOption() ); + policies.put( "propagate-errors-on-update", new PropagateErrorsOnUpdateDownloadPolicy().getDefaultOption() ); } @Override diff --git a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/EditProxyConnectorActionTest.java b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/EditProxyConnectorActionTest.java index 626cf5654..31364f4b8 100644 --- a/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/EditProxyConnectorActionTest.java +++ b/archiva-modules/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/action/admin/connectors/proxy/EditProxyConnectorActionTest.java @@ -28,6 +28,8 @@ import org.apache.maven.archiva.configuration.ProxyConnectorConfiguration; import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration; import org.apache.maven.archiva.policies.CachedFailuresPolicy; import org.apache.maven.archiva.policies.ChecksumPolicy; +import org.apache.maven.archiva.policies.PropagateErrorsDownloadPolicy; +import org.apache.maven.archiva.policies.PropagateErrorsOnUpdateDownloadPolicy; import org.apache.maven.archiva.policies.ReleasesPolicy; import org.apache.maven.archiva.policies.SnapshotsPolicy; import org.apache.maven.archiva.web.action.AbstractWebworkTestCase; @@ -36,6 +38,7 @@ import org.codehaus.plexus.registry.RegistryException; import org.easymock.MockControl; import java.util.List; +import java.util.Map; /** * EditProxyConnectorActionTest @@ -395,10 +398,13 @@ public class EditProxyConnectorActionTest connector.setTargetRepoId( TEST_TARGET_ID ); // TODO: Set these options programatically via list of available policies. - connector.getPolicies().put( "releases", new ReleasesPolicy().getDefaultOption() ); - connector.getPolicies().put( "snapshots", new SnapshotsPolicy().getDefaultOption() ); - connector.getPolicies().put( "checksum", new ChecksumPolicy().getDefaultOption() ); - connector.getPolicies().put( "cache-failures", new CachedFailuresPolicy().getDefaultOption() ); + Map policies = connector.getPolicies(); + policies.put( "releases", new ReleasesPolicy().getDefaultOption() ); + policies.put( "snapshots", new SnapshotsPolicy().getDefaultOption() ); + policies.put( "checksum", new ChecksumPolicy().getDefaultOption() ); + policies.put( "cache-failures", new CachedFailuresPolicy().getDefaultOption() ); + policies.put( "propagate-errors", new PropagateErrorsDownloadPolicy().getDefaultOption() ); + policies.put( "propagate-errors-on-update", new PropagateErrorsOnUpdateDownloadPolicy().getDefaultOption() ); config.addProxyConnector( connector ); -- 2.39.5