All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.shredzone.acme4j.Problem Maven / Gradle / Ivy

There is a newer version: 3.4.0
Show newest version
/*
 * 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 java.util.stream.Collectors.toUnmodifiableList;

import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Optional;

import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.toolbox.JSON;
import org.shredzone.acme4j.toolbox.JSON.Value;

/**
 * A JSON problem. It contains further, machine- and human-readable details about the
 * reason of an error or failure.
 *
 * @see RFC 7807
 */
public class Problem implements Serializable {
    private static final long serialVersionUID = -8418248862966754214L;

    private final URL baseUrl;
    private final JSON problemJson;

    /**
     * Creates a new {@link Problem} object.
     *
     * @param problem
     *            Problem as JSON structure
     * @param baseUrl
     *            Document's base {@link URL} to resolve relative URIs against
     */
    public Problem(JSON problem, URL baseUrl) {
        this.problemJson = problem;
        this.baseUrl = baseUrl;
    }

    /**
     * Returns the problem type. It is always an absolute URI.
     */
    public URI getType() {
        return problemJson.get("type")
                    .map(Value::asString)
                    .map(it -> {
                        try {
                            return baseUrl.toURI().resolve(it);
                        } catch (URISyntaxException ex) {
                            throw new IllegalArgumentException("Bad base URL", ex);
                        }
                    })
                    .orElseThrow(() -> new AcmeProtocolException("Problem without type"));
    }

    /**
     * Returns a short, human-readable summary of the problem. The text may be localized
     * if supported by the server. Empty if the server did not provide a title.
     *
     * @see #toString()
     */
    public Optional getTitle() {
        return problemJson.get("title").map(Value::asString);
    }

    /**
     * Returns a detailed and specific human-readable explanation of the problem. The
     * text may be localized if supported by the server.
     *
     * @see #toString()
     */
    public Optional getDetail() {
        return problemJson.get("detail").map(Value::asString);
    }

    /**
     * Returns a URI that identifies the specific occurence of the problem. It is always
     * an absolute URI.
     */
    public Optional getInstance() {
        return problemJson.get("instance")
                        .map(Value::asString)
                        .map(it ->  {
                            try {
                                return baseUrl.toURI().resolve(it);
                            } catch (URISyntaxException ex) {
                                throw new IllegalArgumentException("Bad base URL", ex);
                            }
                        });
    }

    /**
     * Returns the {@link Identifier} this problem relates to.
     *
     * @since 2.3
     */
    public Optional getIdentifier() {
        return problemJson.get("identifier")
                        .optional()
                        .map(Value::asIdentifier);
    }

    /**
     * Returns a list of sub-problems.
     */
    public List getSubProblems() {
        return problemJson.get("subproblems")
                        .asArray()
                        .stream()
                        .map(o -> o.asProblem(baseUrl))
                        .collect(toUnmodifiableList());
    }

    /**
     * Returns the problem as {@link JSON} object, to access other, non-standard fields.
     *
     * @return Problem as {@link JSON} object
     */
    public JSON asJSON() {
        return problemJson;
    }

    /**
     * Returns a human-readable description of the problem, that is as specific as
     * possible. The description may be localized if supported by the server.
     * 

* If {@link #getSubProblems()} exist, they will be appended. *

* Technically, it returns {@link #getDetail()}. If not set, {@link #getTitle()} is * returned instead. As a last resort, {@link #getType()} is returned. */ @Override public String toString() { var sb = new StringBuilder(); if (getDetail().isPresent()) { sb.append(getDetail().get()); } else if (getTitle().isPresent()) { sb.append(getTitle().get()); } else { sb.append(getType()); } var subproblems = getSubProblems(); if (!subproblems.isEmpty()) { sb.append(" ("); var first = true; for (var sub : subproblems) { if (!first) { sb.append(" ‒ "); } sb.append(sub.toString()); first = false; } sb.append(')'); } return sb.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy