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

org.shredzone.acme4j.impl.GenericAcmeClient Maven / Gradle / Ivy

/*
 * acme4j - Java ACME client
 *
 * Copyright (C) 2015 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.impl;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.Date;
import java.util.EnumMap;
import java.util.Map;

import org.shredzone.acme4j.AcmeClient;
import org.shredzone.acme4j.challenge.Challenge;
import org.shredzone.acme4j.challenge.GenericChallenge;
import org.shredzone.acme4j.challenge.GenericTokenChallenge;
import org.shredzone.acme4j.connector.Connection;
import org.shredzone.acme4j.connector.Resource;
import org.shredzone.acme4j.exception.AcmeException;
import org.shredzone.acme4j.exception.AcmeNetworkException;
import org.shredzone.acme4j.exception.AcmeProtocolException;
import org.shredzone.acme4j.provider.AcmeClientProvider;

/**
 * A generic implementation of {@link AcmeClient}. It uses an {@link AcmeClientProvider}
 * for managing individual server features.
 *
 * @author Richard "Shred" Körber
 */
public class GenericAcmeClient extends AbstractAcmeClient {

    private final AcmeClientProvider provider;
    private final URI directoryUri;
    private final Map directoryMap = new EnumMap<>(Resource.class);
    /* package protected */ Date directoryCacheExpiry;

    /**
     * Creates a new {@link GenericAcmeClient}.
     *
     * @param provider
     *            {@link AcmeClientProvider} creating this client
     * @param directoryUri
     *            {@link URI} of the ACME server's directory service
     */
    public GenericAcmeClient(AcmeClientProvider provider, URI directoryUri) {
        if (provider == null) {
            throw new NullPointerException("provider must not be null");
        }

        this.provider = provider;
        this.directoryUri = directoryUri;
    }

    @Override
    protected Challenge createChallenge(Map data) {
        String type = (String) data.get("type");
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type must not be empty or null");
        }

        Challenge challenge = provider.createChallenge(type);
        if (challenge == null) {
            if (data.containsKey("token")) {
                challenge = new GenericTokenChallenge();
            } else {
                challenge = new GenericChallenge();
            }
        }
        challenge.unmarshall(data);
        return challenge;
    }

    @Override
    protected Connection createConnection() {
        return provider.createConnection();
    }

    @Override
    protected URI resourceUri(Resource resource) throws AcmeException {
        if (resource == null) {
            throw new NullPointerException("resource must not be null");
        }

        Date now = new Date();

        if (directoryMap.isEmpty() || !directoryCacheExpiry.after(now)) {
            if (directoryUri == null) {
                throw new AcmeProtocolException("directoryUri was null on construction time");
            }

            try (Connection conn = createConnection()) {
                int rc = conn.sendRequest(directoryUri);
                if (rc != HttpURLConnection.HTTP_OK) {
                    conn.throwAcmeException();
                }

                // use nonce header if there is one, saves a HEAD request...
                conn.updateSession(getSession());

                Map newMap = conn.readDirectory();

                // only reached when readDirectory did not throw an exception
                directoryMap.clear();
                directoryMap.putAll(newMap);
                directoryCacheExpiry = new Date(now.getTime() + 60 * 60 * 1000L);
            } catch (IOException ex) {
                throw new AcmeNetworkException(ex);
            }
        }
        return directoryMap.get(resource);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy