Add Problem object for JSON problem documents

pull/55/head
Richard Körber 2017-05-01 14:21:02 +02:00
parent e192f300b4
commit 4e1d173cc3
6 changed files with 148 additions and 2 deletions

View File

@ -0,0 +1,69 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2017 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;
import java.io.Serializable;
import org.shredzone.acme4j.util.JSON;
/**
* Represents a JSON Problem.
*
* @see <a href="https://tools.ietf.org/html/rfc7807">RFC 7807</a>
*/
public class Problem implements Serializable {
private static final long serialVersionUID = -8418248862966754214L;
private final JSON problem;
/**
* Creates a new {@link Problem} object.
*
* @param problem
* Problem as JSON structure
*/
public Problem(JSON problem) {
this.problem = problem;
}
/**
* Returns the problem type.
*/
public String getType() {
return problem.get("type").asString();
}
/**
* Returns a human-readable description of the problem.
*/
public String getDetail() {
return problem.get("detail").asString();
}
/**
* Returns the problem as {@link JSON} object, to access other fields.
*/
public JSON asJSON() {
return problem;
}
/**
* Returns the problem as JSON string.
*/
@Override
public String toString() {
return problem.toString();
}
}

View File

@ -41,6 +41,7 @@ import java.util.stream.StreamSupport;
import org.jose4j.json.JsonUtil;
import org.jose4j.lang.JoseException;
import org.shredzone.acme4j.Problem;
import org.shredzone.acme4j.Status;
import org.shredzone.acme4j.exception.AcmeProtocolException;
@ -302,6 +303,19 @@ public final class JSON implements Serializable {
}
}
/**
* Returns the value as {@link Problem}.
*
* @return {@link Problem}, or {@code null} if the value was not set.
*/
public Problem asProblem() {
if (val == null) {
return null;
}
return new Problem(asObject());
}
/**
* Returns the value as JSON array.
*

View File

@ -0,0 +1,41 @@
/*
* acme4j - Java ACME client
*
* Copyright (C) 2017 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;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs;
import org.junit.Test;
import org.shredzone.acme4j.util.JSON;
import org.shredzone.acme4j.util.TestUtils;
/**
* Unit tests for {@link Problem}.
*/
public class ProblemTest {
@Test
public void testProblem() {
JSON original = TestUtils.getJSON("problem");
Problem problem = new Problem(original);
assertThat(problem.getType(), is("urn:ietf:params:acme:error:connection"));
assertThat(problem.getDetail(), is("connection refused"));
assertThat(problem.asJSON().toString(), is(sameJSONAs(original.toString())));
assertThat(problem.toString(), is(sameJSONAs(original.toString())));
}
}

View File

@ -36,6 +36,7 @@ import java.util.NoSuchElementException;
import java.util.stream.Collectors;
import org.junit.Test;
import org.shredzone.acme4j.Problem;
import org.shredzone.acme4j.Status;
import org.shredzone.acme4j.exception.AcmeProtocolException;
@ -86,7 +87,7 @@ public class JSONTest {
assertThat(json.keySet(), containsInAnyOrder(
"text", "number", "boolean", "uri", "url", "date", "array",
"collect", "status", "binary"));
"collect", "status", "binary", "problem"));
assertThat(json.contains("text"), is(true));
assertThat(json.contains("music"), is(false));
assertThat(json.get("text"), is(notNullValue()));
@ -208,6 +209,11 @@ public class JSONTest {
JSON sub = array.get(3).asObject();
assertThat(sub.get("test").asString(), is("ok"));
Problem problem = json.get("problem").asProblem();
assertThat(problem, is(notNullValue()));
assertThat(problem.getType(), is("urn:ietf:params:acme:error:rateLimited"));
assertThat(problem.getDetail(), is("too many requests"));
}
/**
@ -225,6 +231,7 @@ public class JSONTest {
assertThat(json.get("none").asObject(), is(nullValue()));
assertThat(json.get("none").asStatusOrElse(Status.INVALID), is(Status.INVALID));
assertThat(json.get("none").asBinary(), is(nullValue()));
assertThat(json.get("none").asProblem(), is(nullValue()));
try {
json.get("none").asInt();
@ -299,6 +306,13 @@ public class JSONTest {
} catch (AcmeProtocolException ex) {
// expected
}
try {
json.get("text").asProblem();
fail("no exception was thrown");
} catch (AcmeProtocolException ex) {
// expected
}
}
/**

View File

@ -8,5 +8,9 @@
"array": ["foo", 987, [1, 2, 3], {"test": "ok"}],
"collect": ["foo", "bar", "barfoo"],
"status": "VALID",
"binary": "Q2hhaW5zYXc"
"binary": "Q2hhaW5zYXc",
"problem": {
"type": "urn:ietf:params:acme:error:rateLimited",
"detail": "too many requests"
}
}

View File

@ -0,0 +1,4 @@
{
"type": "urn:ietf:params:acme:error:connection",
"detail": "connection refused"
}