Use new date/time API

pull/30/head
Richard Körber 2017-02-11 11:56:26 +01:00
parent 0ed0a9219f
commit c1b677f310
23 changed files with 159 additions and 169 deletions

View File

@ -17,11 +17,11 @@ import static org.shredzone.acme4j.util.AcmeUtils.parseTimestamp;
import java.net.HttpURLConnection;
import java.net.URI;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.shredzone.acme4j.challenge.Challenge;
@ -43,7 +43,7 @@ public class Authorization extends AcmeResource {
private String domain;
private Status status;
private Date expires;
private Instant expires;
private List<Challenge> challenges;
private List<List<Challenge>> combinations;
private boolean loaded = false;
@ -86,7 +86,7 @@ public class Authorization extends AcmeResource {
/**
* Gets the expiry date of the authorization, if set by the server.
*/
public Date getExpires() {
public Instant getExpires() {
load();
return expires;
}

View File

@ -19,10 +19,10 @@ import java.net.HttpURLConnection;
import java.net.URI;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@ -234,7 +234,7 @@ public class Registration extends AcmeResource {
* for default. May be ignored by the server.
* @return The {@link Certificate}
*/
public Certificate requestCertificate(byte[] csr, Date notBefore, Date notAfter)
public Certificate requestCertificate(byte[] csr, Instant notBefore, Instant notAfter)
throws AcmeException {
Objects.requireNonNull(csr, "csr");

View File

@ -15,8 +15,9 @@ package org.shredzone.acme4j;
import java.net.URI;
import java.security.KeyPair;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.EnumMap;
import java.util.List;
import java.util.Locale;
@ -48,7 +49,7 @@ public class Session {
private JSON directoryJson;
private Metadata metadata;
private Locale locale = Locale.getDefault();
protected Date directoryCacheExpiry;
protected Instant directoryCacheExpiry;
/**
* Creates a new {@link Session}.
@ -210,10 +211,10 @@ public class Session {
*/
private void readDirectory() throws AcmeException {
synchronized (this) {
Date now = new Date();
if (directoryJson == null || !directoryCacheExpiry.after(now)) {
Instant now = Instant.now();
if (directoryJson == null || !directoryCacheExpiry.isAfter(now)) {
directoryJson = provider().directory(this, getServerUri());
directoryCacheExpiry = new Date(now.getTime() + 60 * 60 * 1000L);
directoryCacheExpiry = now.plus(Duration.ofHours(1));
JSON meta = directoryJson.get("meta").asObject();
if (meta != null) {

View File

@ -15,7 +15,7 @@ package org.shredzone.acme4j.challenge;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Date;
import java.time.Instant;
import java.util.Objects;
import org.shredzone.acme4j.AcmeResource;
@ -113,8 +113,8 @@ public class Challenge extends AcmeResource {
/**
* Returns the validation date, if returned by the server.
*/
public Date getValidated() {
return data.get(KEY_VALIDATED).asDate();
public Instant getValidated() {
return data.get(KEY_VALIDATED).asInstant();
}
/**

View File

@ -27,12 +27,13 @@ import java.security.KeyPair;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -253,9 +254,9 @@ public class DefaultConnection implements Connection {
try {
if (conn.getResponseCode() == HttpURLConnection.HTTP_ACCEPTED) {
Date retryAfter = getRetryAfterHeader();
if (retryAfter != null) {
throw new AcmeRetryAfterException(message, retryAfter);
Optional<Instant> retryAfter = getRetryAfterHeader();
if (retryAfter.isPresent()) {
throw new AcmeRetryAfterException(message, retryAfter.get());
}
}
} catch (IOException ex) {
@ -338,27 +339,29 @@ public class DefaultConnection implements Connection {
/**
* Gets the instant sent with the Retry-After header.
*/
private Date getRetryAfterHeader() {
private Optional<Instant> getRetryAfterHeader() {
// See RFC 2616 section 14.37
String header = conn.getHeaderField(RETRY_AFTER_HEADER);
if (header == null) {
return null;
}
if (header != null) {
try {
// delta-seconds
if (header.matches("^\\d+$")) {
int delta = Integer.parseInt(header);
long date = conn.getHeaderFieldDate(DATE_HEADER, System.currentTimeMillis());
return Optional.of(Instant.ofEpochMilli(date).plusSeconds(delta));
}
try {
// delta-seconds
if (header.matches("^\\d+$")) {
int delta = Integer.parseInt(header);
long date = conn.getHeaderFieldDate(DATE_HEADER, System.currentTimeMillis());
return new Date(date + delta * 1000L);
// HTTP-date
long date = conn.getHeaderFieldDate(RETRY_AFTER_HEADER, 0L);
if (date != 0) {
return Optional.of(Instant.ofEpochMilli(date));
}
} catch (Exception ex) {
throw new AcmeProtocolException("Bad retry-after header value: " + header, ex);
}
// HTTP-date
long date = conn.getHeaderFieldDate(RETRY_AFTER_HEADER, 0L);
return date != 0 ? new Date(date) : null;
} catch (Exception ex) {
throw new AcmeProtocolException("Bad retry-after header value: " + header, ex);
}
return Optional.empty();
}
/**
@ -386,9 +389,9 @@ public class DefaultConnection implements Connection {
}
if ("rateLimited".equals(error)) {
Date retryAfter = getRetryAfterHeader();
Optional<Instant> retryAfter = getRetryAfterHeader();
Collection<URI> rateLimits = getLinks("rate-limit");
return new AcmeRateLimitExceededException(type, detail, retryAfter, rateLimits);
return new AcmeRateLimitExceededException(type, detail, retryAfter.orElse(null), rateLimits);
}
return new AcmeServerException(type, detail);

View File

@ -14,9 +14,9 @@
package org.shredzone.acme4j.exception;
import java.net.URI;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
/**
* An exception that is thrown when a rate limit was exceeded.
@ -24,7 +24,7 @@ import java.util.Date;
public class AcmeRateLimitExceededException extends AcmeServerException {
private static final long serialVersionUID = 4150484059796413069L;
private final Date retryAfter;
private final Instant retryAfter;
private final Collection<URI> documents;
/**
@ -41,7 +41,7 @@ public class AcmeRateLimitExceededException extends AcmeServerException {
* @param documents
* URIs pointing to documents about the rate limit that was hit
*/
public AcmeRateLimitExceededException(String type, String detail, Date retryAfter, Collection<URI> documents) {
public AcmeRateLimitExceededException(String type, String detail, Instant retryAfter, Collection<URI> documents) {
super(type, detail);
this.retryAfter = retryAfter;
this.documents =
@ -52,8 +52,8 @@ public class AcmeRateLimitExceededException extends AcmeServerException {
* Returns the moment the request is expected to succeed again. {@code null} if this
* moment is not known.
*/
public Date getRetryAfter() {
return retryAfter != null ? new Date(retryAfter.getTime()) : null;
public Instant getRetryAfter() {
return retryAfter;
}
/**

View File

@ -13,7 +13,7 @@
*/
package org.shredzone.acme4j.exception;
import java.util.Date;
import java.time.Instant;
import java.util.Objects;
/**
@ -23,7 +23,7 @@ import java.util.Objects;
public class AcmeRetryAfterException extends AcmeException {
private static final long serialVersionUID = 4461979121063649905L;
private final Date retryAfter;
private final Instant retryAfter;
/**
* Creates a new {@link AcmeRetryAfterException}.
@ -33,7 +33,7 @@ public class AcmeRetryAfterException extends AcmeException {
* @param retryAfter
* retry-after date returned by the server
*/
public AcmeRetryAfterException(String msg, Date retryAfter) {
public AcmeRetryAfterException(String msg, Instant retryAfter) {
super(msg);
this.retryAfter = Objects.requireNonNull(retryAfter);
}
@ -41,8 +41,8 @@ public class AcmeRetryAfterException extends AcmeException {
/**
* Returns the retry-after date returned by the server.
*/
public Date getRetryAfter() {
return new Date(retryAfter.getTime());
public Instant getRetryAfter() {
return retryAfter;
}
}

View File

@ -17,10 +17,9 @@ import java.io.UnsupportedEncodingException;
import java.net.IDN;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -164,12 +163,12 @@ public final class AcmeUtils {
*
* @param str
* Date string
* @return {@link Date} that was parsed
* @return {@link Instant} that was parsed
* @throws IllegalArgumentException
* if the date string was not RFC 3339 formatted
* @see <a href="https://www.ietf.org/rfc/rfc3339.txt">RFC 3339</a>
*/
public static Date parseTimestamp(String str) {
public static Instant parseTimestamp(String str) {
Matcher m = DATE_PATTERN.matcher(str);
if (!m.matches()) {
throw new IllegalArgumentException("Illegal date: " + str);
@ -198,11 +197,9 @@ public final class AcmeUtils {
tz = TZ_PATTERN.matcher(tz).replaceAll("GMT$1$2:$3");
}
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(tz));
cal.clear();
cal.set(year, month - 1, dom, hour, minute, second);
cal.set(Calendar.MILLISECOND, ms);
return cal.getTime();
return ZonedDateTime.of(
year, month, dom, hour, minute, second, ms * 1_000_000,
ZoneId.of(tz)).toInstant();
}
/**

View File

@ -27,8 +27,8 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.Instant;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -349,12 +349,11 @@ public final class JSON implements Serializable {
}
/**
* Returns the value as {@link Date}.
* Returns the value as {@link Instant}.
*
* @return {@link Date}, or {@code null} if the value was not set. The returned
* {@link Date} object is not shared and can be modified safely.
* @return {@link Instant}, or {@code null} if the value was not set.
*/
public Date asDate() {
public Instant asInstant() {
if (val == null) {
return null;
}

View File

@ -17,12 +17,11 @@ import static org.shredzone.acme4j.util.AcmeUtils.base64UrlEncode;
import java.security.Key;
import java.security.PublicKey;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.TimeZone;
import java.util.TreeMap;
import org.jose4j.json.JsonUtil;
@ -62,25 +61,22 @@ public class JSONBuilder {
}
/**
* Puts a {@link Date} to the JSON. If a property with the key exists, it will be
* Puts an {@link Instant} to the JSON. If a property with the key exists, it will be
* replaced.
*
* @param key
* Property key
* @param value
* Property {@link Date} value
* Property {@link Instant} value
* @return {@code this}
*/
public JSONBuilder put(String key, Date value) {
public JSONBuilder put(String key, Instant value) {
if (value == null) {
put(key, (Object) null);
return this;
}
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = fmt.format(value);
put(key, date);
put(key, DateTimeFormatter.ISO_INSTANT.format(value));
return this;
}

View File

@ -21,8 +21,9 @@ import static org.shredzone.acme4j.util.TestUtils.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;
@ -228,7 +229,7 @@ public class AuthorizationTest {
*/
@Test
public void testUpdateRetryAfter() throws Exception {
final long retryAfter = System.currentTimeMillis() + 30 * 1000L;
final Instant retryAfter = Instant.now().plus(Duration.ofSeconds(30));
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
@ -250,7 +251,7 @@ public class AuthorizationTest {
@Override
public void handleRetryAfter(String message) throws AcmeException {
throw new AcmeRetryAfterException(message, new Date(retryAfter));
throw new AcmeRetryAfterException(message, retryAfter);
}
};
@ -267,7 +268,7 @@ public class AuthorizationTest {
auth.update();
fail("Expected AcmeRetryAfterException");
} catch (AcmeRetryAfterException ex) {
assertThat(ex.getRetryAfter(), is(new Date(retryAfter)));
assertThat(ex.getRetryAfter(), is(retryAfter));
}
assertThat(auth.getDomain(), is("example.org"));

View File

@ -22,7 +22,8 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.time.Duration;
import java.time.Instant;
import org.junit.Test;
import org.shredzone.acme4j.connector.Resource;
@ -107,7 +108,7 @@ public class CertificateTest {
*/
@Test
public void testRetryAfter() throws AcmeException, IOException {
final long retryAfter = System.currentTimeMillis() + 30 * 1000L;
final Instant retryAfter = Instant.now().plus(Duration.ofSeconds(30));
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
@ -125,7 +126,7 @@ public class CertificateTest {
@Override
public void handleRetryAfter(String message) throws AcmeException {
throw new AcmeRetryAfterException(message, new Date(retryAfter));
throw new AcmeRetryAfterException(message, retryAfter);
}
};
@ -135,7 +136,7 @@ public class CertificateTest {
cert.download();
fail("Expected AcmeRetryAfterException");
} catch (AcmeRetryAfterException ex) {
assertThat(ex.getRetryAfter(), is(new Date(retryAfter)));
assertThat(ex.getRetryAfter(), is(retryAfter));
}
provider.close();

View File

@ -23,9 +23,10 @@ import java.net.HttpURLConnection;
import java.net.URI;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Iterator;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jose4j.jws.JsonWebSignature;
@ -335,15 +336,12 @@ public class RegistrationTest {
provider.putTestResource(Resource.NEW_CERT, resourceUri);
byte[] csr = TestUtils.getResourceAsByteArray("/csr.der");
Calendar notBefore = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
notBefore.clear();
notBefore.set(2016, Calendar.JANUARY, 1);
Calendar notAfter = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
notAfter.clear();
notAfter.set(2016, Calendar.JANUARY, 8);
ZoneId utc = ZoneId.of("UTC");
Instant notBefore = LocalDate.of(2016, 1, 1).atStartOfDay(utc).toInstant();
Instant notAfter = LocalDate.of(2016, 1, 8).atStartOfDay(utc).toInstant();
Registration registration = new Registration(provider.createSession(), locationUri);
Certificate cert = registration.requestCertificate(csr, notBefore.getTime(), notAfter.getTime());
Certificate cert = registration.requestCertificate(csr, notBefore, notAfter);
assertThat(cert.download(), is(originalCert));
assertThat(cert.getLocation(), is(locationUri));

View File

@ -21,7 +21,7 @@ import static org.shredzone.acme4j.util.TestUtils.getJsonAsObject;
import java.io.IOException;
import java.net.URI;
import java.security.KeyPair;
import java.util.Date;
import java.time.Instant;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
@ -173,7 +173,7 @@ public class SessionTest {
ArgumentMatchers.any(URI.class));
// Simulate a cache expiry
session.directoryCacheExpiry = new Date();
session.directoryCacheExpiry = Instant.now();
// Make sure directory is read once again
assertSession(session);

View File

@ -25,7 +25,8 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Date;
import java.time.Duration;
import java.time.Instant;
import org.jose4j.lang.JoseException;
import org.junit.Before;
@ -229,7 +230,7 @@ public class ChallengeTest {
*/
@Test
public void testUpdateRetryAfter() throws Exception {
final long retryAfter = System.currentTimeMillis() + 30 * 1000L;
final Instant retryAfter = Instant.now().plus(Duration.ofSeconds(30));
TestableConnectionProvider provider = new TestableConnectionProvider() {
@Override
@ -252,7 +253,7 @@ public class ChallengeTest {
@Override
public void handleRetryAfter(String message) throws AcmeException {
throw new AcmeRetryAfterException(message, new Date(retryAfter));
throw new AcmeRetryAfterException(message, retryAfter);
}
};
@ -265,7 +266,7 @@ public class ChallengeTest {
challenge.update();
fail("Expected AcmeRetryAfterException");
} catch (AcmeRetryAfterException ex) {
assertThat(ex.getRetryAfter(), is(new Date(retryAfter)));
assertThat(ex.getRetryAfter(), is(retryAfter));
}
assertThat(challenge.getStatus(), is(Status.VALID));

View File

@ -25,9 +25,10 @@ import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@ -254,12 +255,12 @@ public class DefaultConnectionTest {
*/
@Test
public void testHandleRetryAfterHeaderDate() throws AcmeException, IOException {
Date retryDate = new Date(System.currentTimeMillis() + 10 * 60 * 60 * 1000L);
Instant retryDate = Instant.now().plus(Duration.ofHours(10));
String retryMsg = "absolute date";
when(mockUrlConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_ACCEPTED);
when(mockUrlConnection.getHeaderField("Retry-After")).thenReturn(retryDate.toString());
when(mockUrlConnection.getHeaderFieldDate("Retry-After", 0L)).thenReturn(retryDate.getTime());
when(mockUrlConnection.getHeaderFieldDate("Retry-After", 0L)).thenReturn(retryDate.toEpochMilli());
try (DefaultConnection conn = new DefaultConnection(mockHttpConnection)) {
conn.conn = mockUrlConnection;
@ -297,7 +298,7 @@ public class DefaultConnectionTest {
conn.handleRetryAfter(retryMsg);
fail("no AcmeRetryAfterException was thrown");
} catch (AcmeRetryAfterException ex) {
assertThat(ex.getRetryAfter(), is(new Date(now + delta * 1000L)));
assertThat(ex.getRetryAfter(), is(Instant.ofEpochMilli(now).plusSeconds(delta)));
assertThat(ex.getMessage(), is(retryMsg));
}

View File

@ -17,9 +17,10 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import org.junit.Test;
@ -35,7 +36,7 @@ public class AcmeRateLimitExceededExceptionTest {
public void testAcmeRateLimitExceededException() {
String type = "urn:ietf:params:acme:error:rateLimited";
String detail = "Too many requests per minute";
Date retryAfter = new Date(System.currentTimeMillis() + 60 * 1000L);
Instant retryAfter = Instant.now().plus(Duration.ofMinutes(1));
Collection<URI> documents = Arrays.asList(
URI.create("http://example.com/doc1.html"),
URI.create("http://example.com/doc2.html"));

View File

@ -16,7 +16,8 @@ package org.shredzone.acme4j.exception;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import java.util.Date;
import java.time.Duration;
import java.time.Instant;
import org.junit.Test;
@ -31,16 +32,12 @@ public class AcmeRetryAfterExceptionTest {
@Test
public void testAcmeRetryAfterException() {
String detail = "Too early";
Date retryAfter = new Date(System.currentTimeMillis() + 60 * 1000L);
Instant retryAfter = Instant.now().plus(Duration.ofMinutes(1));
AcmeRetryAfterException ex
= new AcmeRetryAfterException(detail, retryAfter);
AcmeRetryAfterException ex = new AcmeRetryAfterException(detail, retryAfter);
assertThat(ex.getMessage(), is(detail));
assertThat(ex.getRetryAfter(), is(retryAfter));
// make sure we get a copy of the Date object
assertThat(ex.getRetryAfter(), not(sameInstance(retryAfter)));
}
/**
@ -48,16 +45,12 @@ public class AcmeRetryAfterExceptionTest {
*/
@Test
public void testNullAcmeRetryAfterException() {
Date retryAfter = new Date(System.currentTimeMillis() + 60 * 1000L);
Instant retryAfter = Instant.now().plus(Duration.ofMinutes(1));
AcmeRetryAfterException ex
= new AcmeRetryAfterException(null, retryAfter);
AcmeRetryAfterException ex = new AcmeRetryAfterException(null, retryAfter);
assertThat(ex.getMessage(), nullValue());
assertThat(ex.getRetryAfter(), is(retryAfter));
// make sure we get a copy of the Date object
assertThat(ex.getRetryAfter(), not(sameInstance(retryAfter)));
}
/**

View File

@ -21,11 +21,10 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.security.KeyPair;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.xml.bind.DatatypeConverter;
@ -247,57 +246,55 @@ public class AcmeUtilsTest {
/**
* Matches the given time.
*/
private DateMatcher isDate(int year, int month, int dom, int hour, int minute, int second) {
private InstantMatcher isDate(int year, int month, int dom, int hour, int minute, int second) {
return isDate(year, month, dom, hour, minute, second, 0);
}
/**
* Matches the given time and milliseconds.
*/
private DateMatcher isDate(int year, int month, int dom, int hour, int minute, int second, int ms) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.clear();
cal.set(year, month - 1, dom, hour, minute, second);
cal.set(Calendar.MILLISECOND, ms);
return new DateMatcher(cal);
private InstantMatcher isDate(int year, int month, int dom, int hour, int minute, int second, int ms) {
Instant cmp = ZonedDateTime.of(
year, month, dom, hour, minute, second, ms * 1_000_000,
ZoneId.of("UTC")).toInstant();
return new InstantMatcher(cmp);
}
/**
* Date matcher that gives a readable output on mismatch.
*/
private static class DateMatcher extends BaseMatcher<Date> {
private final Calendar cal;
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
private static class InstantMatcher extends BaseMatcher<Instant> {
private final Instant cmp;
private final DateTimeFormatter dtf = DateTimeFormatter.ISO_INSTANT;
public DateMatcher(Calendar cal) {
this.cal = cal;
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
public InstantMatcher(Instant cmp) {
this.cmp = cmp;
}
@Override
public boolean matches(Object item) {
if (!(item instanceof Date)) {
if (!(item instanceof Instant)) {
return false;
}
Date date = (Date) item;
return date.equals(cal.getTime());
Instant date = (Instant) item;
return date.equals(cmp);
}
@Override
public void describeTo(Description description) {
description.appendValue(sdf.format(cal.getTime()));
description.appendValue(dtf.format(cmp));
}
@Override
public void describeMismatch(Object item, Description description) {
if (!(item instanceof Date)) {
description.appendText("is not a Date");
if (!(item instanceof Instant)) {
description.appendText("is not an Instant");
return;
}
Date date = (Date) item;
description.appendText("was ").appendValue(sdf.format(date));
Instant date = (Instant) item;
description.appendText("was ").appendValue(dtf.format(date));
}
}

View File

@ -19,10 +19,10 @@ import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.TimeZone;
import org.jose4j.json.JsonUtil;
import org.jose4j.lang.JoseException;
@ -81,13 +81,11 @@ public class JSONBuilderTest {
*/
@Test
public void testDate() {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+2"));
cal.clear();
cal.set(2016, Calendar.JUNE, 1, 5, 13, 46);
Instant date = ZonedDateTime.of(2016, 6, 1, 5, 13, 46, 0, ZoneId.of("GMT+2")).toInstant();
JSONBuilder cb = new JSONBuilder();
cb.put("fooDate", cal.getTime());
cb.put("fooNull", (Date) null);
cb.put("fooDate", date);
cb.put("fooNull", (Instant) null);
assertThat(cb.toString(), is("{\"fooDate\":\"2016-06-01T03:13:46Z\",\"fooNull\":null}"));
}

View File

@ -26,10 +26,11 @@ import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Calendar;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.TimeZone;
import org.junit.Test;
import org.shredzone.acme4j.exception.AcmeProtocolException;
@ -145,9 +146,7 @@ public class JSONTest {
*/
@Test
public void testGetter() throws MalformedURLException {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.clear();
cal.set(2016, 0, 8);
Instant date = LocalDate.of(2016, 1, 8).atStartOfDay(ZoneId.of("UTC")).toInstant();
JSON json = TestUtils.getJsonAsObject("json");
@ -155,7 +154,7 @@ public class JSONTest {
assertThat(json.get("number").asInt(), is(123));
assertThat(json.get("uri").asURI(), is(URI.create("mailto:foo@example.com")));
assertThat(json.get("url").asURL(), is(new URL("http://example.com")));
assertThat(json.get("date").asDate(), is(cal.getTime()));
assertThat(json.get("date").asInstant(), is(date));
JSON.Array array = json.get("array").asArray();
assertThat(array.get(0).asString(), is("foo"));
@ -181,7 +180,7 @@ public class JSONTest {
assertThat(json.get("none").asString(), is(nullValue()));
assertThat(json.get("none").asURI(), is(nullValue()));
assertThat(json.get("none").asURL(), is(nullValue()));
assertThat(json.get("none").asDate(), is(nullValue()));
assertThat(json.get("none").asInstant(), is(nullValue()));
assertThat(json.get("none").asArray(), is(nullValue()));
assertThat(json.get("none").asObject(), is(nullValue()));
@ -246,7 +245,7 @@ public class JSONTest {
}
try {
json.get("text").asDate();
json.get("text").asInstant();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected

View File

@ -25,6 +25,8 @@ import java.security.KeyPair;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import org.bouncycastle.asn1.x500.X500Name;
@ -212,17 +214,17 @@ public final class CertificateUtils {
*/
private static X509Certificate createCertificate(KeyPair keypair, String... subject) throws IOException {
final long now = System.currentTimeMillis();
final long validSpanMs = 7 * 24 * 60 * 60 * 1000L;
final String signatureAlg = "SHA256withRSA";
try {
X500Name issuer = new X500Name("CN=acme.invalid");
BigInteger serial = BigInteger.valueOf(now);
Date notBefore = new Date(now);
Date notAfter = new Date(now + validSpanMs);
Instant notBefore = Instant.ofEpochMilli(now);
Instant notAfter = notBefore.plus(Duration.ofDays(7));
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
issuer, serial, notBefore, notAfter, issuer, keypair.getPublic());
issuer, serial, Date.from(notBefore), Date.from(notAfter),
issuer, keypair.getPublic());
GeneralName[] gns = new GeneralName[subject.length];
for (int ix = 0; ix < subject.length; ix++) {

View File

@ -28,6 +28,8 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@ -132,13 +134,13 @@ public class CertificateUtilsTest {
X509Certificate cert = CertificateUtils.createTlsSniCertificate(keypair, subject);
Date now = new Date();
Date end = new Date(now.getTime() + (8 * 24 * 60 * 60 * 1000L));
Instant now = Instant.now();
Instant end = now.plus(Duration.ofDays(8));
assertThat(cert, not(nullValue()));
assertThat(cert.getNotAfter(), is(greaterThan(now)));
assertThat(cert.getNotAfter(), is(lessThan(end)));
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(now)));
assertThat(cert.getNotAfter(), is(greaterThan(Date.from(now))));
assertThat(cert.getNotAfter(), is(lessThan(Date.from(end))));
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(Date.from(now))));
assertThat(cert.getSubjectX500Principal().getName(), is("CN=acme.invalid"));
assertThat(getSANs(cert), containsInAnyOrder(subject));
}
@ -156,13 +158,13 @@ public class CertificateUtilsTest {
X509Certificate cert = CertificateUtils.createTlsSni02Certificate(keypair, sanA, sanB);
Date now = new Date();
Date end = new Date(now.getTime() + (8 * 24 * 60 * 60 * 1000L));
Instant now = Instant.now();
Instant end = now.plus(Duration.ofDays(8));
assertThat(cert, not(nullValue()));
assertThat(cert.getNotAfter(), is(greaterThan(now)));
assertThat(cert.getNotAfter(), is(lessThan(end)));
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(now)));
assertThat(cert.getNotAfter(), is(greaterThan(Date.from(now))));
assertThat(cert.getNotAfter(), is(lessThan(Date.from(end))));
assertThat(cert.getNotBefore(), is(lessThanOrEqualTo(Date.from(now))));
assertThat(cert.getSubjectX500Principal().getName(), is("CN=acme.invalid"));
assertThat(getSANs(cert), containsInAnyOrder(sanA, sanB));
}