mirror of https://github.com/shred/acme4j
Add AcmeNotSupportedException
- Some Optional return values could only be empty if a method was invoked although the server did not support that feature. In order to keep the API simple, a newly introduced AcmeNotSupportedException is now thrown in that case, so these methods will immediately return a non-null value. There is always a method to check if a feature is available or not, so the invoker can check in advance and does not need to actively handle that exception. - Some other places that previously threw an exception because of missing features, are now also throwing AcmeNotSupportedException for consistency.pull/140/head
parent
5bbf1b5966
commit
23906ff39c
|
@ -27,6 +27,7 @@ import java.util.Optional;
|
|||
import org.shredzone.acme4j.connector.Resource;
|
||||
import org.shredzone.acme4j.connector.ResourceIterator;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.exception.AcmeServerException;
|
||||
import org.shredzone.acme4j.toolbox.AcmeUtils;
|
||||
|
@ -125,7 +126,7 @@ public class Account extends AcmeJsonResource {
|
|||
if (ordersUrl.isEmpty()) {
|
||||
// Let's Encrypt does not provide this field at the moment, although it's required.
|
||||
// See https://github.com/letsencrypt/boulder/issues/3335
|
||||
throw new AcmeProtocolException("This ACME server does not support getOrders()");
|
||||
throw new AcmeNotSupportedException("getOrders()");
|
||||
}
|
||||
return new ResourceIterator<>(getLogin(), KEY_ORDERS, ordersUrl.get(), Login::bindOrder);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.time.Duration;
|
|||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.toolbox.JSON;
|
||||
import org.shredzone.acme4j.toolbox.JSON.Value;
|
||||
|
||||
|
@ -86,14 +87,17 @@ public class Metadata {
|
|||
|
||||
/**
|
||||
* Returns the minimum acceptable value for the maximum validity of a certificate
|
||||
* before auto-renewal. Empty if the CA does not support short-term auto-renewal.
|
||||
* before auto-renewal.
|
||||
*
|
||||
* @since 2.3
|
||||
* @throws AcmeNotSupportedException if the server does not support auto-renewal.
|
||||
*/
|
||||
public Optional<Duration> getAutoRenewalMinLifetime() {
|
||||
return meta.get("auto-renewal").optional().map(Value::asObject)
|
||||
.map(j -> j.get("min-lifetime"))
|
||||
.map(Value::asDuration);
|
||||
public Duration getAutoRenewalMinLifetime() {
|
||||
return meta.getFeature("auto-renewal")
|
||||
.map(Value::asObject)
|
||||
.orElseGet(JSON::empty)
|
||||
.get("min-lifetime")
|
||||
.asDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,21 +105,28 @@ public class Metadata {
|
|||
* date.
|
||||
*
|
||||
* @since 2.3
|
||||
* @throws AcmeNotSupportedException if the server does not support auto-renewal.
|
||||
*/
|
||||
public Optional<Duration> getAutoRenewalMaxDuration() {
|
||||
return meta.get("auto-renewal").optional().map(Value::asObject)
|
||||
.map(j -> j.get("max-duration"))
|
||||
.map(Value::asDuration);
|
||||
public Duration getAutoRenewalMaxDuration() {
|
||||
return meta.getFeature("auto-renewal")
|
||||
.map(Value::asObject)
|
||||
.orElseGet(JSON::empty)
|
||||
.get("max-duration")
|
||||
.asDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the CA also allows to fetch STAR certificates via GET request.
|
||||
*
|
||||
* @since 2.6
|
||||
* @throws AcmeNotSupportedException if the server does not support auto-renewal.
|
||||
*/
|
||||
public boolean isAutoRenewalGetAllowed() {
|
||||
return meta.get("auto-renewal").optional().map(Value::asObject)
|
||||
.map(j -> j.get("allow-certificate-get"))
|
||||
return meta.getFeature("auto-renewal").optional()
|
||||
.map(Value::asObject)
|
||||
.orElseGet(JSON::empty)
|
||||
.get("allow-certificate-get")
|
||||
.optional()
|
||||
.map(Value::asBoolean)
|
||||
.orElse(false);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.toolbox.JSON;
|
||||
import org.shredzone.acme4j.toolbox.JSON.Value;
|
||||
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
||||
|
@ -178,10 +179,10 @@ public class Order extends AcmeJsonResource {
|
|||
* Returns the earliest date of validity of the first certificate issued.
|
||||
*
|
||||
* @since 2.3
|
||||
* @throws AcmeNotSupportedException if auto-renewal is not supported
|
||||
*/
|
||||
public Optional<Instant> getAutoRenewalStartDate() {
|
||||
return getJSON().get("auto-renewal")
|
||||
.optional()
|
||||
return getJSON().getFeature("auto-renewal")
|
||||
.map(Value::asObject)
|
||||
.orElseGet(JSON::empty)
|
||||
.get("start-date")
|
||||
|
@ -193,39 +194,39 @@ public class Order extends AcmeJsonResource {
|
|||
* Returns the latest date of validity of the last certificate issued.
|
||||
*
|
||||
* @since 2.3
|
||||
* @throws AcmeNotSupportedException if auto-renewal is not supported
|
||||
*/
|
||||
public Optional<Instant> getAutoRenewalEndDate() {
|
||||
return getJSON().get("auto-renewal")
|
||||
.optional()
|
||||
public Instant getAutoRenewalEndDate() {
|
||||
return getJSON().getFeature("auto-renewal")
|
||||
.map(Value::asObject)
|
||||
.orElseGet(JSON::empty)
|
||||
.get("end-date")
|
||||
.optional()
|
||||
.map(Value::asInstant);
|
||||
.asInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum lifetime of each certificate.
|
||||
*
|
||||
* @since 2.3
|
||||
* @throws AcmeNotSupportedException if auto-renewal is not supported
|
||||
*/
|
||||
public Optional<Duration> getAutoRenewalLifetime() {
|
||||
return getJSON().get("auto-renewal")
|
||||
public Duration getAutoRenewalLifetime() {
|
||||
return getJSON().getFeature("auto-renewal")
|
||||
.optional()
|
||||
.map(Value::asObject)
|
||||
.orElseGet(JSON::empty)
|
||||
.get("lifetime")
|
||||
.optional()
|
||||
.map(Value::asDuration);
|
||||
.asDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pre-date period of each certificate.
|
||||
*
|
||||
* @since 2.7
|
||||
* @throws AcmeNotSupportedException if auto-renewal is not supported
|
||||
*/
|
||||
public Optional<Duration> getAutoRenewalLifetimeAdjust() {
|
||||
return getJSON().get("auto-renewal")
|
||||
return getJSON().getFeature("auto-renewal")
|
||||
.optional()
|
||||
.map(Value::asObject)
|
||||
.orElseGet(JSON::empty)
|
||||
|
@ -241,7 +242,7 @@ public class Order extends AcmeJsonResource {
|
|||
* @since 2.6
|
||||
*/
|
||||
public boolean isAutoRenewalGetEnabled() {
|
||||
return getJSON().get("auto-renewal")
|
||||
return getJSON().getFeature("auto-renewal")
|
||||
.optional()
|
||||
.map(Value::asObject)
|
||||
.orElseGet(JSON::empty)
|
||||
|
@ -258,7 +259,7 @@ public class Order extends AcmeJsonResource {
|
|||
*/
|
||||
public void cancelAutoRenewal() throws AcmeException {
|
||||
if (!getSession().getMetadata().isAutoRenewalEnabled()) {
|
||||
throw new AcmeException("CA does not support short-term automatic renewals");
|
||||
throw new AcmeNotSupportedException("auto-renewal");
|
||||
}
|
||||
|
||||
LOG.debug("cancel");
|
||||
|
|
|
@ -25,7 +25,7 @@ import java.util.Set;
|
|||
import edu.umd.cs.findbugs.annotations.Nullable;
|
||||
import org.shredzone.acme4j.connector.Resource;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -278,7 +278,7 @@ public class OrderBuilder {
|
|||
var session = login.getSession();
|
||||
|
||||
if (autoRenewal && !session.getMetadata().isAutoRenewalEnabled()) {
|
||||
throw new AcmeException("CA does not support short-term automatic renewals");
|
||||
throw new AcmeNotSupportedException("auto-renewal");
|
||||
}
|
||||
|
||||
LOG.debug("create");
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* acme4j - Java ACME client
|
||||
*
|
||||
* Copyright (C) 2023 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;
|
||||
|
||||
/**
|
||||
* A runtime exception that is thrown if the ACME server does not support a certain
|
||||
* feature. It might be either because that feature is optional, or because the server
|
||||
* is not fully RFC compliant.
|
||||
*/
|
||||
public class AcmeNotSupportedException extends AcmeProtocolException {
|
||||
private static final long serialVersionUID = 3434074002226584731L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AcmeNotSupportedException}.
|
||||
*
|
||||
* @param feature
|
||||
* Feature that is not supported
|
||||
*/
|
||||
public AcmeNotSupportedException(String feature) {
|
||||
super("Server does not support " + feature);
|
||||
}
|
||||
|
||||
}
|
|
@ -50,6 +50,7 @@ import org.jose4j.lang.JoseException;
|
|||
import org.shredzone.acme4j.Identifier;
|
||||
import org.shredzone.acme4j.Problem;
|
||||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
|
||||
/**
|
||||
|
@ -159,6 +160,21 @@ public final class JSON implements Serializable {
|
|||
data.get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Value} of the given key.
|
||||
*
|
||||
* @param key
|
||||
* Key to read
|
||||
* @return {@link Value} of the key
|
||||
* @throws AcmeNotSupportedException
|
||||
* if the key is not present. The key is used as feature name.
|
||||
*/
|
||||
public Value getFeature(String key) {
|
||||
return new Value(
|
||||
path.isEmpty() ? key : path + '.' + key,
|
||||
data.get(key)).onFeature(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content as JSON string.
|
||||
*/
|
||||
|
@ -304,6 +320,22 @@ public final class JSON implements Serializable {
|
|||
return val != null ? Optional.of(this) : Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this value. If the value was {@code null}, an
|
||||
* {@link AcmeNotSupportedException} is thrown. This method is used for mandatory
|
||||
* fields that are only present if a certain feature is supported by the server.
|
||||
*
|
||||
* @param feature
|
||||
* Feature name
|
||||
* @return itself
|
||||
*/
|
||||
public Value onFeature(String feature) {
|
||||
if (val == null) {
|
||||
throw new AcmeNotSupportedException(feature);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this value as an {@link Optional} of the desired type, for further
|
||||
* mapping and filtering.
|
||||
|
|
|
@ -30,7 +30,7 @@ import java.util.Optional;
|
|||
import org.assertj.core.api.AutoCloseableSoftAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.shredzone.acme4j.connector.Resource;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.provider.TestableConnectionProvider;
|
||||
import org.shredzone.acme4j.toolbox.JSON;
|
||||
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
||||
|
@ -107,11 +107,16 @@ public class OrderBuilderTest {
|
|||
.isEqualTo("2016-01-10T00:00:00Z");
|
||||
softly.assertThat(order.getStatus()).isEqualTo(Status.PENDING);
|
||||
softly.assertThat(order.isAutoRenewing()).isFalse();
|
||||
softly.assertThat(order.getAutoRenewalStartDate()).isEmpty();
|
||||
softly.assertThat(order.getAutoRenewalEndDate()).isEmpty();
|
||||
softly.assertThat(order.getAutoRenewalLifetime()).isEmpty();
|
||||
softly.assertThat(order.getAutoRenewalLifetimeAdjust()).isEmpty();
|
||||
softly.assertThat(order.isAutoRenewalGetEnabled()).isFalse();
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::getAutoRenewalStartDate);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::getAutoRenewalEndDate);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::getAutoRenewalLifetime);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::getAutoRenewalLifetimeAdjust);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::isAutoRenewalGetEnabled);
|
||||
softly.assertThat(order.getLocation()).isEqualTo(locationUrl);
|
||||
softly.assertThat(order.getAuthorizations()).isNotNull();
|
||||
softly.assertThat(order.getAuthorizations()).hasSize(2);
|
||||
|
@ -172,8 +177,8 @@ public class OrderBuilderTest {
|
|||
softly.assertThat(order.getNotAfter()).isEmpty();
|
||||
softly.assertThat(order.isAutoRenewing()).isTrue();
|
||||
softly.assertThat(order.getAutoRenewalStartDate().orElseThrow()).isEqualTo(autoRenewStart);
|
||||
softly.assertThat(order.getAutoRenewalEndDate().orElseThrow()).isEqualTo(autoRenewEnd);
|
||||
softly.assertThat(order.getAutoRenewalLifetime().orElseThrow()).isEqualTo(validity);
|
||||
softly.assertThat(order.getAutoRenewalEndDate()).isEqualTo(autoRenewEnd);
|
||||
softly.assertThat(order.getAutoRenewalLifetime()).isEqualTo(validity);
|
||||
softly.assertThat(order.getAutoRenewalLifetimeAdjust().orElseThrow()).isEqualTo(predate);
|
||||
softly.assertThat(order.isAutoRenewalGetEnabled()).isTrue();
|
||||
softly.assertThat(order.getLocation()).isEqualTo(locationUrl);
|
||||
|
@ -187,7 +192,7 @@ public class OrderBuilderTest {
|
|||
*/
|
||||
@Test
|
||||
public void testAutoRenewOrderCertificateFails() {
|
||||
assertThrows(AcmeException.class, () -> {
|
||||
assertThrows(AcmeNotSupportedException.class, () -> {
|
||||
var provider = new TestableConnectionProvider();
|
||||
provider.putTestResource(Resource.NEW_ORDER, resourceUrl);
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
|
||||
import org.assertj.core.api.AutoCloseableSoftAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.provider.TestableConnectionProvider;
|
||||
import org.shredzone.acme4j.toolbox.JSON;
|
||||
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
||||
|
@ -84,11 +85,16 @@ public class OrderTest {
|
|||
softly.assertThat(order.getFinalizeLocation()).isEqualTo(finalizeUrl);
|
||||
|
||||
softly.assertThat(order.isAutoRenewing()).isFalse();
|
||||
softly.assertThat(order.getAutoRenewalStartDate()).isEmpty();
|
||||
softly.assertThat(order.getAutoRenewalEndDate()).isEmpty();
|
||||
softly.assertThat(order.getAutoRenewalLifetime()).isEmpty();
|
||||
softly.assertThat(order.getAutoRenewalLifetimeAdjust()).isEmpty();
|
||||
softly.assertThat(order.isAutoRenewalGetEnabled()).isFalse();
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::getAutoRenewalStartDate);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::getAutoRenewalEndDate);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::getAutoRenewalLifetime);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::getAutoRenewalLifetimeAdjust);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(order::isAutoRenewalGetEnabled);
|
||||
|
||||
softly.assertThat(order.getError()).isNotEmpty();
|
||||
softly.assertThat(order.getError().orElseThrow().getType())
|
||||
|
@ -261,9 +267,9 @@ public class OrderTest {
|
|||
softly.assertThat(order.isAutoRenewing()).isTrue();
|
||||
softly.assertThat(order.getAutoRenewalStartDate().orElseThrow())
|
||||
.isEqualTo("2016-01-01T00:00:00Z");
|
||||
softly.assertThat(order.getAutoRenewalEndDate().orElseThrow())
|
||||
softly.assertThat(order.getAutoRenewalEndDate())
|
||||
.isEqualTo("2017-01-01T00:00:00Z");
|
||||
softly.assertThat(order.getAutoRenewalLifetime().orElseThrow())
|
||||
softly.assertThat(order.getAutoRenewalLifetime())
|
||||
.isEqualTo(Duration.ofHours(168));
|
||||
softly.assertThat(order.getAutoRenewalLifetimeAdjust().orElseThrow())
|
||||
.isEqualTo(Duration.ofDays(6));
|
||||
|
@ -302,15 +308,16 @@ public class OrderTest {
|
|||
var order = login.bindOrder(locationUrl);
|
||||
|
||||
try (var softly = new AutoCloseableSoftAssertions()) {
|
||||
softly.assertThat(order.getCertificate()).isEmpty();
|
||||
softly.assertThatExceptionOfType(IllegalStateException.class)
|
||||
.isThrownBy(order::getCertificate);
|
||||
softly.assertThat(order.getAutoRenewalCertificate().orElseThrow().getLocation())
|
||||
.isEqualTo(url("https://example.com/acme/cert/1234"));
|
||||
softly.assertThat(order.isAutoRenewing()).isTrue();
|
||||
softly.assertThat(order.getAutoRenewalStartDate().orElseThrow())
|
||||
.isEqualTo("2018-01-01T00:00:00Z");
|
||||
softly.assertThat(order.getAutoRenewalEndDate().orElseThrow())
|
||||
softly.assertThat(order.getAutoRenewalEndDate())
|
||||
.isEqualTo("2019-01-01T00:00:00Z");
|
||||
softly.assertThat(order.getAutoRenewalLifetime().orElseThrow())
|
||||
softly.assertThat(order.getAutoRenewalLifetime())
|
||||
.isEqualTo(Duration.ofHours(168));
|
||||
softly.assertThat(order.getAutoRenewalLifetimeAdjust().orElseThrow())
|
||||
.isEqualTo(Duration.ofDays(6));
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test;
|
|||
import org.mockito.ArgumentMatchers;
|
||||
import org.shredzone.acme4j.connector.Resource;
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.provider.AcmeProvider;
|
||||
import org.shredzone.acme4j.provider.GenericAcmeProvider;
|
||||
import org.shredzone.acme4j.toolbox.AcmeUtils;
|
||||
|
@ -169,10 +170,8 @@ public class SessionTest {
|
|||
.isEqualTo("https://www.example.com/");
|
||||
softly.assertThat(meta.getCaaIdentities()).containsExactlyInAnyOrder("example.com");
|
||||
softly.assertThat(meta.isAutoRenewalEnabled()).isTrue();
|
||||
softly.assertThat(meta.getAutoRenewalMaxDuration().orElseThrow())
|
||||
.isEqualTo(Duration.ofDays(365));
|
||||
softly.assertThat(meta.getAutoRenewalMinLifetime().orElseThrow())
|
||||
.isEqualTo(Duration.ofHours(24));
|
||||
softly.assertThat(meta.getAutoRenewalMaxDuration()).isEqualTo(Duration.ofDays(365));
|
||||
softly.assertThat(meta.getAutoRenewalMinLifetime()).isEqualTo(Duration.ofHours(24));
|
||||
softly.assertThat(meta.isAutoRenewalGetAllowed()).isTrue();
|
||||
softly.assertThat(meta.isExternalAccountRequired()).isTrue();
|
||||
softly.assertThat(meta.getJSON()).isNotNull();
|
||||
|
@ -218,9 +217,12 @@ public class SessionTest {
|
|||
softly.assertThat(meta.getWebsite()).isEmpty();
|
||||
softly.assertThat(meta.getCaaIdentities()).isEmpty();
|
||||
softly.assertThat(meta.isAutoRenewalEnabled()).isFalse();
|
||||
softly.assertThat(meta.getAutoRenewalMaxDuration()).isEmpty();
|
||||
softly.assertThat(meta.getAutoRenewalMinLifetime()).isEmpty();
|
||||
softly.assertThat(meta.isAutoRenewalGetAllowed()).isFalse();
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(meta::getAutoRenewalMaxDuration);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(meta::getAutoRenewalMinLifetime);
|
||||
softly.assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(meta::isAutoRenewalGetAllowed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* acme4j - Java ACME client
|
||||
*
|
||||
* Copyright (C) 2023 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.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AcmeNotSupportedException}.
|
||||
*/
|
||||
public class AcmeNotSupportedExceptionTest {
|
||||
|
||||
@Test
|
||||
public void testAcmeNotSupportedException() {
|
||||
var msg = "revoke";
|
||||
var ex = new AcmeNotSupportedException(msg);
|
||||
assertThat(ex).isInstanceOf(RuntimeException.class);
|
||||
assertThat(ex.getMessage()).isEqualTo("Server does not support revoke");
|
||||
assertThat(ex.getCause()).isNull();
|
||||
}
|
||||
|
||||
}
|
|
@ -16,6 +16,7 @@ package org.shredzone.acme4j.toolbox;
|
|||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.shredzone.acme4j.toolbox.TestUtils.url;
|
||||
|
||||
|
@ -34,6 +35,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.shredzone.acme4j.Status;
|
||||
import org.shredzone.acme4j.exception.AcmeNotSupportedException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.toolbox.JSON.Value;
|
||||
|
||||
|
@ -235,6 +237,14 @@ public class JSONTest {
|
|||
assertThat(json.get("none").optional().isPresent()).isFalse();
|
||||
assertThat(json.get("none").map(Value::asString).isPresent()).isFalse();
|
||||
|
||||
assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(() -> json.getFeature("none"))
|
||||
.withMessage("Server does not support none");
|
||||
|
||||
assertThatExceptionOfType(AcmeNotSupportedException.class)
|
||||
.isThrownBy(() -> json.get("none").onFeature("my-feature"))
|
||||
.withMessage("Server does not support my-feature");
|
||||
|
||||
assertThrows(AcmeProtocolException.class,
|
||||
() -> json.get("none").asString(),
|
||||
"asString");
|
||||
|
|
|
@ -5,6 +5,7 @@ This document will help you migrate your code to the latest _acme4j_ version.
|
|||
## Migration to Version 3.0.0
|
||||
|
||||
- All `@Nullable` return values have been reviewed. Collections may now be empty, but never `null`. Most of the other return values are now either `Optional`, or throwing an exception if more reasonable. If your code fails to compile because the return type has changed to `Optional`, you can simply add `.orElse(null)` to restore the old behavior. But often your code will reveal a better way to handle the former `null` pointer instead.
|
||||
- A new `AcmeNotSupportedException` is thrown if a feature is not supported by the server. It is a subclass of the `AcmeProtocolException` runtime exception.
|
||||
- Starting with _acme4j_ v3, we will require the smallest Java SE LTS version that is still receiving premier support according to the [Oracle Java SE Support Roadmap](https://www.oracle.com/java/technologies/java-se-support-roadmap.html). At the moment of writing, these are Java 11 and Java 17, so _acme4j_ requires Java 11 starting from now. With the prospected release of Java 21 (LTS) in September 2023, we will start to require Java 17, and so on. If you still need Java 8, you can use _acme4j_ v2, which will receive bugfixes until September 2023.
|
||||
- Changed to `java.net.http` client. Due to limitations of the API, HTTP errors are only thrown with the error code, but not with the error message. If you checked the message in unit tests, be prepared that the error message might have changed.
|
||||
- acme4j now accepts HTTP gzip compression. It is enabled by default, but can be disabled in the `NetworkSettings` if it causes problems or impedes debugging.
|
||||
|
|
Loading…
Reference in New Issue