View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.transfer;
20  
21  import org.eclipse.aether.RepositoryException;
22  
23  /**
24   * Thrown in case of a checksum failure during an artifact/metadata download. This exception is usually thrown in
25   * following cases:
26   * <ul>
27   *     <li>actual checksum <em>mismatch</em>, see {@link #mismatch(String, String, String)}</li>
28   *     <li>lack of required checksums, see {@link #noneAvailable(String, String)}</li>
29   *     <li>processing problem during checksum checks (ie IO problem), see {@link #processingFailure(String, Throwable)}</li>
30   * </ul>
31   * It is resolver expectation to provide most available information to caller.
32   */
33  public class ChecksumFailureException extends RepositoryException {
34  
35      private final String expected;
36  
37      private final String expectedKind;
38  
39      private final String actual;
40  
41      private final boolean retryWorthy;
42  
43      /**
44       * Use in case of checksum mismatch. Creates a new exception with the specified expected, expected kind and actual
45       * checksum. The resulting exception is {@link #isRetryWorthy() retry-worthy}. The checksum match check should
46       * have already happened, this method does not check for any kind of inequality.
47       *
48       * @param expected The expected checksum as declared by the hosting repository, may be {@code null}.
49       * @param expectedKind The expected checksum kind, may be {@code null}.
50       * @param actual The actual checksum as computed from the local bytes, may be {@code null}.
51       * @since 2.0.19
52       */
53      public static ChecksumFailureException mismatch(String expected, String expectedKind, String actual) {
54          return mismatchDetail(null, expected, expectedKind, actual);
55      }
56  
57      /**
58       * Use in case of checksum mismatch. Creates a new exception with the specified expected, expected kind and actual
59       * checksum. The resulting exception is {@link #isRetryWorthy() retry-worthy}. The checksum match check should
60       * have already happened, this method does not check for any kind of inequality.
61       *
62       * @param detail The extra detail/information regarding mismatch.
63       * @param expected The expected checksum as declared by the hosting repository, may be {@code null}.
64       * @param expectedKind The expected checksum kind, may be {@code null}.
65       * @param actual The actual checksum as computed from the local bytes, may be {@code null}.
66       * @since 2.0.19
67       */
68      public static ChecksumFailureException mismatchDetail(
69              String detail, String expected, String expectedKind, String actual) {
70          String message = "Checksum validation failed, expected '"
71                  + expected + "'" + (expectedKind == null ? "" : " (" + expectedKind + ")")
72                  + " but is actually '" + actual + "'";
73          if (detail != null) {
74              message = message + " (" + detail + ")";
75          }
76          return new ChecksumFailureException(message, null, expected, expectedKind, actual, true);
77      }
78  
79      /**
80       * Use in case of checksum not available. Optionally, one can specify which kind was not available.
81       *
82       * @param message The message.
83       * @param expectedKind The expected checksum kind, may be {@code null}.
84       * @since 2.0.19
85       */
86      public static ChecksumFailureException noneAvailable(String message, String expectedKind) {
87          return new ChecksumFailureException(message, null, "", expectedKind == null ? "" : expectedKind, "", false);
88      }
89  
90      /**
91       * Use in case of error, for example IO problem during checksum processing, calculation and alike. Ideally, one
92       * should specify cause as well.
93       *
94       * @param message The message.
95       * @param cause The cause.
96       * @since 2.0.19
97       */
98      public static ChecksumFailureException processingFailure(String message, Throwable cause) {
99          return new ChecksumFailureException(message, cause, "", "", "", false);
100     }
101 
102     /**
103      * Creates a new exception with the specified expected, expected kind and actual checksum. The resulting exception
104      * is {@link #isRetryWorthy() retry-worthy}.
105      *
106      * @param expected The expected checksum as declared by the hosting repository, may be {@code null}.
107      * @param expectedKind The expected checksum kind, may be {@code null}.
108      * @param actual The actual checksum as computed from the local bytes, may be {@code null}.
109      * @since 1.8.0
110      * @deprecated Use {@link #mismatch(String, String, String)} or other suitable helper method instead.
111      */
112     @Deprecated
113     public ChecksumFailureException(String expected, String expectedKind, String actual) {
114         super("Checksum validation failed, expected '"
115                 + expected + "'" + (expectedKind == null ? "" : " (" + expectedKind + ")")
116                 + " but is actually '" + actual + "'");
117         this.expected = expected;
118         this.expectedKind = expectedKind;
119         this.actual = actual;
120         this.retryWorthy = true;
121     }
122 
123     /**
124      * Creates a new exception with the specified detail message. The resulting exception is not
125      * {@link #isRetryWorthy() retry-worthy}. Use this constructor ONLY in cases like "no data to work with",
126      * like missing checksums. In every other case use some other constructor.
127      *
128      * @param message The detail message, may be {@code null}.
129      * @deprecated Use {@link #noneAvailable(String, String)} or other suitable helper method instead.
130      */
131     @Deprecated
132     public ChecksumFailureException(String message) {
133         this(message, null, "", "", "", false);
134     }
135 
136     /**
137      * Creates a new exception with the specified cause. The resulting exception is not {@link #isRetryWorthy()
138      * retry-worthy}. Use this constructor in case some other error (ie IO problem) prevented checksum calculation.
139      *
140      * @param cause The exception that caused this one, may be {@code null}.
141      * @deprecated Use {@link #processingFailure(String, Throwable)} or other helper method instead.
142      */
143     @Deprecated
144     public ChecksumFailureException(Throwable cause) {
145         this("Checksum validation failed" + getMessage(": ", cause), cause, "", "", "", false);
146     }
147 
148     /**
149      * Creates a new exception with the specified detail message and cause. The resulting exception is not
150      * {@link #isRetryWorthy() retry-worthy}. Use this constructor in case some other error (ie IO problem)
151      * prevented checksum calculation.
152      *
153      * @param message The detail message, may be {@code null}.
154      * @param cause The exception that caused this one, may be {@code null}.
155      * @deprecated Use {@link #processingFailure(String, Throwable)} or other helper method instead.
156      */
157     @Deprecated
158     public ChecksumFailureException(String message, Throwable cause) {
159         this(message, cause, "", "", "", false);
160     }
161 
162     /**
163      * Creates a new exception with the specified retry flag, detail message and cause.
164      *
165      * @param retryWorthy {@code true} if the exception is retry-worthy, {@code false} otherwise.
166      * @param message The detail message, may be {@code null}.
167      * @param cause The exception that caused this one, may be {@code null}.
168      * @deprecated Do not use this constructor, it lacks information.
169      */
170     @Deprecated
171     public ChecksumFailureException(boolean retryWorthy, String message, Throwable cause) {
172         this(message, cause, "", "", "", retryWorthy);
173     }
174 
175     /**
176      * Hidden constructor, use static helper methods instead, suitable for your case.
177      */
178     private ChecksumFailureException(
179             String message, Throwable cause, String expected, String expectedKind, String actual, boolean retryWorthy) {
180         super(message, cause);
181         this.expected = expected;
182         this.expectedKind = expectedKind;
183         this.actual = actual;
184         this.retryWorthy = retryWorthy;
185     }
186 
187     /**
188      * Gets the expected checksum for the downloaded artifact/metadata.
189      *
190      * @return The expected checksum as declared by the hosting repository or {@code null} if unknown.
191      */
192     public String getExpected() {
193         return expected;
194     }
195 
196     /**
197      * Gets the expected checksum kind for the downloaded artifact/metadata.
198      *
199      * @return The expected checksum kind or {@code null} if unknown.
200      * @since 1.8.0
201      */
202     public String getExpectedKind() {
203         return expectedKind;
204     }
205 
206     /**
207      * Gets the actual checksum for the downloaded artifact/metadata.
208      *
209      * @return The actual checksum as computed from the local bytes or {@code null} if unknown.
210      */
211     public String getActual() {
212         return actual;
213     }
214 
215     /**
216      * Indicates whether the corresponding download is retry-worthy.
217      *
218      * @return {@code true} if retrying the download might solve the checksum failure, {@code false} if the checksum
219      *         failure is non-recoverable.
220      */
221     public boolean isRetryWorthy() {
222         return retryWorthy;
223     }
224 }