Keep Authorization and Certificate

Before this patch, Order generated and bound new Authorization and
Certificate objects everytime the respective getters were invoked. Each
of these instances keeps a separate copy of the server state, which causes
unnecessary traffic.

With this patch, the list of Authorizations and the Certificates are now
loaded lazily and kept in a cache, so the same instance is returned
everytime the getter is invoked.
pull/140/head
Richard Körber 2023-05-07 10:48:34 +02:00
parent c08c85b95c
commit 5db82b1ad7
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
2 changed files with 36 additions and 11 deletions

View File

@ -80,6 +80,7 @@ public abstract class AcmeJsonResource extends AcmeResource {
* New {@link JSON} data, must not be {@code null}. * New {@link JSON} data, must not be {@code null}.
*/ */
protected void setJSON(JSON data) { protected void setJSON(JSON data) {
invalidate();
this.data = Objects.requireNonNull(data, "data"); this.data = Objects.requireNonNull(data, "data");
} }
@ -97,6 +98,9 @@ public abstract class AcmeJsonResource extends AcmeResource {
/** /**
* Invalidates the state of this resource. Enforces an {@link #update()} when * Invalidates the state of this resource. Enforces an {@link #update()} when
* {@link #getJSON()} is invoked. * {@link #getJSON()} is invoked.
* <p>
* Subclasses can override this method to purge internal caches that are based on the
* JSON structure. Remember to invoke {@code super.invalidate()}!
*/ */
protected void invalidate() { protected void invalidate() {
data = null; data = null;

View File

@ -21,6 +21,7 @@ import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import edu.umd.cs.findbugs.annotations.Nullable;
import org.shredzone.acme4j.exception.AcmeException; import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeNotSupportedException; import org.shredzone.acme4j.exception.AcmeNotSupportedException;
import org.shredzone.acme4j.toolbox.JSON; import org.shredzone.acme4j.toolbox.JSON;
@ -36,6 +37,10 @@ public class Order extends AcmeJsonResource {
private static final long serialVersionUID = 5435808648658292177L; private static final long serialVersionUID = 5435808648658292177L;
private static final Logger LOG = LoggerFactory.getLogger(Order.class); private static final Logger LOG = LoggerFactory.getLogger(Order.class);
private transient @Nullable Certificate certificate = null;
private transient @Nullable Certificate autoRenewalCertificate = null;
private transient @Nullable List<Authorization> authorizations = null;
protected Order(Login login, URL location) { protected Order(Login login, URL location) {
super(login, location); super(login, location);
} }
@ -97,13 +102,16 @@ public class Order extends AcmeJsonResource {
* specific order. * specific order.
*/ */
public List<Authorization> getAuthorizations() { public List<Authorization> getAuthorizations() {
var login = getLogin(); if (authorizations == null) {
return getJSON().get("authorizations") var login = getLogin();
authorizations = getJSON().get("authorizations")
.asArray() .asArray()
.stream() .stream()
.map(Value::asURL) .map(Value::asURL)
.map(login::bindAuthorization) .map(login::bindAuthorization)
.collect(toUnmodifiableList()); .collect(toUnmodifiableList());
}
return authorizations;
} }
/** /**
@ -123,10 +131,13 @@ public class Order extends AcmeJsonResource {
* for the status to become {@link Status#VALID}. * for the status to become {@link Status#VALID}.
*/ */
public Certificate getCertificate() { public Certificate getCertificate() {
return getJSON().get("certificate") if (certificate == null) {
.map(Value::asURL) certificate = getJSON().get("certificate")
.map(getLogin()::bindCertificate) .map(Value::asURL)
.orElseThrow(() -> new IllegalStateException("Order is not completed")); .map(getLogin()::bindCertificate)
.orElseThrow(() -> new IllegalStateException("Order is not completed"));
}
return certificate;
} }
/** /**
@ -139,11 +150,14 @@ public class Order extends AcmeJsonResource {
* order has been {@link Status#CANCELED}. * order has been {@link Status#CANCELED}.
*/ */
public Certificate getAutoRenewalCertificate() { public Certificate getAutoRenewalCertificate() {
return getJSON().get("star-certificate") if (autoRenewalCertificate == null) {
.optional() autoRenewalCertificate = getJSON().get("star-certificate")
.map(Value::asURL) .optional()
.map(getLogin()::bindCertificate) .map(Value::asURL)
.orElseThrow(() -> new IllegalStateException("Order is in an invalid state")); .map(getLogin()::bindCertificate)
.orElseThrow(() -> new IllegalStateException("Order is in an invalid state"));
}
return autoRenewalCertificate;
} }
/** /**
@ -279,4 +293,11 @@ public class Order extends AcmeJsonResource {
} }
} }
@Override
protected void invalidate() {
super.invalidate();
certificate = null;
autoRenewalCertificate = null;
authorizations = null;
}
} }