diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java index f8823d56..588c32a5 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Authorization.java @@ -25,6 +25,7 @@ import java.util.List; import org.shredzone.acme4j.challenge.Challenge; import org.shredzone.acme4j.connector.Connection; import org.shredzone.acme4j.exception.AcmeException; +import org.shredzone.acme4j.exception.AcmeLazyLoadingException; import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.exception.AcmeRetryAfterException; import org.shredzone.acme4j.util.JSON; @@ -164,7 +165,7 @@ public class Authorization extends AcmeResource { // ignore... The object was still updated. LOG.debug("Retry-After", ex); } catch (AcmeException ex) { - throw new AcmeProtocolException("Could not load lazily", ex); + throw new AcmeLazyLoadingException(this, ex); } } } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java index b6922e08..fc6f4ec8 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Certificate.java @@ -27,6 +27,7 @@ import java.util.List; import org.shredzone.acme4j.connector.Connection; import org.shredzone.acme4j.connector.Resource; import org.shredzone.acme4j.exception.AcmeException; +import org.shredzone.acme4j.exception.AcmeLazyLoadingException; import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.util.AcmeUtils; import org.shredzone.acme4j.util.JSONBuilder; @@ -81,8 +82,6 @@ public class Certificate extends AcmeResource { * Returns the created certificate. * * @return The created end-entity {@link X509Certificate} without issuer chain. - * @throws AcmeProtocolException - * if lazy downloading failed */ public X509Certificate getCertificate() { lazyDownload(); @@ -95,8 +94,6 @@ public class Certificate extends AcmeResource { * @return The created end-entity {@link X509Certificate} and issuer chain. The first * certificate is always the end-entity certificate, followed by the * intermediate certificates required to build a path to a trusted root. - * @throws AcmeProtocolException - * if lazy downloading failed */ public List getCertificateChain() { lazyDownload(); @@ -109,8 +106,6 @@ public class Certificate extends AcmeResource { * * @param out * {@link Writer} to write to. The writer is not closed after use. - * @throws AcmeProtocolException - * if lazy downloading failed */ public void writeCertificate(Writer out) throws IOException { try { @@ -160,14 +155,14 @@ public class Certificate extends AcmeResource { } /** - * Lazily downloads the certificate. Throws a runtime {@link AcmeProtocolException} if - * the download failed. + * Lazily downloads the certificate. Throws a runtime {@link AcmeLazyLoadingException} + * if the download failed. */ private void lazyDownload() { try { download(); } catch (AcmeException ex) { - throw new AcmeProtocolException("Could not lazily download certificate", ex); + throw new AcmeLazyLoadingException(this, ex); } } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java index ed0fb6c1..1c3534ba 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Order.java @@ -22,7 +22,7 @@ import java.util.List; import org.shredzone.acme4j.connector.Connection; import org.shredzone.acme4j.exception.AcmeException; -import org.shredzone.acme4j.exception.AcmeProtocolException; +import org.shredzone.acme4j.exception.AcmeLazyLoadingException; import org.shredzone.acme4j.util.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -142,7 +142,7 @@ public class Order extends AcmeResource { try { update(); } catch (AcmeException ex) { - throw new AcmeProtocolException("Could not load lazily", ex); + throw new AcmeLazyLoadingException(this, ex); } } } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java index 96d17768..9fd660b9 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Registration.java @@ -34,6 +34,7 @@ import org.shredzone.acme4j.connector.Connection; import org.shredzone.acme4j.connector.Resource; import org.shredzone.acme4j.connector.ResourceIterator; import org.shredzone.acme4j.exception.AcmeException; +import org.shredzone.acme4j.exception.AcmeLazyLoadingException; import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.exception.AcmeRetryAfterException; import org.shredzone.acme4j.util.JSON; @@ -305,7 +306,7 @@ public class Registration extends AcmeResource { // ignore... The object was still updated. LOG.debug("Retry-After", ex); } catch (AcmeException ex) { - throw new AcmeProtocolException("Could not load lazily", ex); + throw new AcmeLazyLoadingException(this, ex); } } } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java new file mode 100644 index 00000000..de7ffc23 --- /dev/null +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/exception/AcmeLazyLoadingException.java @@ -0,0 +1,61 @@ +/* + * acme4j - Java ACME client + * + * Copyright (C) 2016 Richard "Shred" Körber + * http://acme4j.shredzone.org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ +package org.shredzone.acme4j.exception; + +import static java.util.Objects.requireNonNull; + +import java.net.URL; + +import org.shredzone.acme4j.AcmeResource; + +/** + * This runtime exception is thrown when an {@link AcmeException} occured while trying to + * lazy-load a resource from the ACME server. + */ +public class AcmeLazyLoadingException extends RuntimeException { + private static final long serialVersionUID = 1000353433913721901L; + + private final Class type; + private final URL location; + + /** + * Creates a new {@link AcmeLazyLoadingException}. + * + * @param resource + * {@link AcmeResource} to be loaded + * @param cause + * {@link AcmeException} that was raised + */ + public AcmeLazyLoadingException(AcmeResource resource, AcmeException cause) { + super(requireNonNull(resource).getClass().getSimpleName() + " " + + requireNonNull(resource).getLocation(), requireNonNull(cause)); + type = resource.getClass(); + location = resource.getLocation(); + } + + /** + * Returns the {@link AcmeResource} type of the resource that could not be loaded. + */ + public Class getType() { + return type; + } + + /** + * Returns the location of the resource that could not be loaded. + */ + public URL getLocation() { + return location; + } + +} diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/exception/AcmeLazyLoadingExceptionTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/exception/AcmeLazyLoadingExceptionTest.java new file mode 100644 index 00000000..8d9cc23b --- /dev/null +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/exception/AcmeLazyLoadingExceptionTest.java @@ -0,0 +1,59 @@ +/* + * acme4j - Java ACME client + * + * Copyright (C) 2016 Richard "Shred" Körber + * http://acme4j.shredzone.org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ +package org.shredzone.acme4j.exception; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; + +import java.net.URL; + +import org.junit.Test; +import org.shredzone.acme4j.AcmeResource; +import org.shredzone.acme4j.Session; +import org.shredzone.acme4j.util.TestUtils; + +/** + * Unit tests for {@link AcmeLazyLoadingException}. + */ +public class AcmeLazyLoadingExceptionTest { + + private URL resourceUrl = TestUtils.url("http://example.com/acme/resource/123"); + + @Test + public void testAcmeLazyLoadingException() { + Session session = mock(Session.class); + AcmeResource resource = new TestResource(session, resourceUrl); + + AcmeException cause = new AcmeException("Something went wrong"); + + AcmeLazyLoadingException ex = new AcmeLazyLoadingException(resource, cause); + assertThat(ex, is(instanceOf(RuntimeException.class))); + assertThat(ex.getMessage(), containsString(resourceUrl.toString())); + assertThat(ex.getMessage(), containsString(TestResource.class.getSimpleName())); + assertThat(ex.getCause(), is((Throwable) cause)); + assertThat(ex.getType(), is(equalTo(TestResource.class))); + assertThat(ex.getLocation(), is(resourceUrl)); + } + + private static class TestResource extends AcmeResource { + private static final long serialVersionUID = 1023419539450677538L; + + public TestResource(Session session, URL location) { + super(session); + setLocation(location); + } + } + +}