// Path: src/main/java/net/klakegg/pkix/ocsp/api/OcspFetcher.java
// public interface OcspFetcher {
// 
//     OcspFetcherResponse fetch(URI uri, byte[] content) throws IOException;
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/api/OcspFetcherResponse.java
// public interface OcspFetcherResponse extends Closeable {
// 
//     int getStatus() throws IOException;
// 
//     String getContentType() throws IOException;
// 
//     InputStream getContent() throws IOException;
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/BuildHandler.java
// public interface BuildHandler<T> {
// 
//     T build(Properties properties);
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Builder.java
// public class Builder<T> {
// 
//     protected BuildHandler<T> buildHandler;
// 
//     protected Map<Property<?>, Object> map = new HashMap<>();
// 
//     public Builder(BuildHandler<T> buildHandler) {
//         this(buildHandler, new HashMap<Property<?>, Object>());
//     }
// 
//     private Builder(BuildHandler<T> buildHandler, Map<Property<?>, Object> map) {
//         this.buildHandler = buildHandler;
//         this.map = map;
//     }
// 
//     public <S> Builder<T> set(Property<S> property, S value) {
//         Map<Property<?>, Object> map = new HashMap<>(this.map);
//         map.put(property, value);
// 
//         return new Builder<>(buildHandler, map);
//     }
// 
//     public T build() {
//         return buildHandler.build(new Properties(map));
//     }
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Properties.java
// public class Properties {
// 
//     private Map<Property<?>, Object> map;
// 
//     protected Properties(Map<Property<?>, Object> map) {
//         this.map = map;
//     }
// 
//     @SuppressWarnings("unchecked")
//     public <S> S get(Property<S> property) {
//         return map.containsKey(property) ? (S) map.get(property) : property.getDefaultValue();
//     }
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Property.java
// public class Property<T> {
// 
//     private final T defaultValue;
// 
//     public static <T> Property<T> create() {
//         return new Property<>(null);
//     }
// 
//     public static <T> Property<T> create(T defaultValue) {
//         return new Property<>(defaultValue);
//     }
// 
//     private Property(T defaultValue) {
//         this.defaultValue = defaultValue;
//     }
// 
//     public T getDefaultValue() {
//         return defaultValue;
//     }
// 
// }


import net.klakegg.pkix.ocsp.api.OcspFetcher;
import net.klakegg.pkix.ocsp.api.OcspFetcherResponse;
import net.klakegg.pkix.ocsp.builder.BuildHandler;
import net.klakegg.pkix.ocsp.builder.Builder;
import net.klakegg.pkix.ocsp.builder.Properties;
import net.klakegg.pkix.ocsp.builder.Property;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
package net.klakegg.pkix.ocsp.fetcher;



/**
 * @author erlend
 */
public class ApacheOcspFetcher extends AbstractOcspFetcher {

    public static final Property<HttpClientConnectionManager> CONNECTION_MANAGER = Property.create();

    public static final Property<Boolean> CONNECTION_MANAGER_SHARED = Property.create(false);

    public static final Property<Integer> TIMEOUT_CONNECTION_MANAGER = Property.create(-1);

    /**
     * Builder to create an instance of OcspFetcher using Apache HttpClient for connectivity.
     *
     * @return Prepared fetcher.
     */
    public static Builder<OcspFetcher> builder() {
        return new Builder<>(new BuildHandler<OcspFetcher>() {
            @Override
            public OcspFetcher build(Properties properties) {
                return new ApacheOcspFetcher(properties);
            }
        });
    }

    private ApacheOcspFetcher(Properties properties) {
        super(properties);
    }

    @Override
    public OcspFetcherResponse fetch(URI uri, byte[] content) throws IOException {
        HttpPost httpPost = new HttpPost(uri);
        httpPost.setHeader("Content-Type", "application/ocsp-request");
        httpPost.setHeader("Accept", "application/ocsp-response");
        httpPost.setEntity(new ByteArrayEntity(content));
        httpPost.setConfig(getRequestConfig());

        return new ApacheOcspFetcherResponse(getHttpClient().execute(httpPost));
    }

    protected CloseableHttpClient getHttpClient() {
        return HttpClientBuilder.create()
                .setConnectionManager(properties.get(CONNECTION_MANAGER))
// Path: src/main/java/net/klakegg/pkix/ocsp/api/OcspFetcher.java
// public interface OcspFetcher {
// 
//     OcspFetcherResponse fetch(URI uri, byte[] content) throws IOException;
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/api/OcspFetcherResponse.java
// public interface OcspFetcherResponse extends Closeable {
// 
//     int getStatus() throws IOException;
// 
//     String getContentType() throws IOException;
// 
//     InputStream getContent() throws IOException;
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/BuildHandler.java
// public interface BuildHandler<T> {
// 
//     T build(Properties properties);
// 
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Builder.java
// public class Builder<T> {
// 
//     protected BuildHandler<T> buildHandler;
// 
//     protected Map<Property<?>, Object> map = new HashMap<>();
// 
//     public Builder(BuildHandler<T> buildHandler) {
//         this(buildHandler, new HashMap<Property<?>, Object>());
//     }
// 
//     private Builder(BuildHandler<T> buildHandler, Map<Property<?>, Object> map) {
//         this.buildHandler = buildHandler;
//         this.map = map;
//     }
// 
//     public <S> Builder<T> set(Property<S> property, S value) {
//         Map<Property<?>, Object> map = new HashMap<>(this.map);
//         map.put(property, value);
// 
//         return new Builder<>(buildHandler, map);
//     }
// 
//     public T build() {
//         return buildHandler.build(new Properties(map));
//     }
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Properties.java
// public class Properties {
// 
//     private Map<Property<?>, Object> map;
// 
//     protected Properties(Map<Property<?>, Object> map) {
//         this.map = map;
//     }
// 
//     @SuppressWarnings("unchecked")
//     public <S> S get(Property<S> property) {
//         return map.containsKey(property) ? (S) map.get(property) : property.getDefaultValue();
//     }
// }
// 
// Path: src/main/java/net/klakegg/pkix/ocsp/builder/Property.java
// public class Property<T> {
// 
//     private final T defaultValue;
// 
//     public static <T> Property<T> create() {
//         return new Property<>(null);
//     }
// 
//     public static <T> Property<T> create(T defaultValue) {
//         return new Property<>(defaultValue);
//     }
// 
//     private Property(T defaultValue) {
//         this.defaultValue = defaultValue;
//     }
// 
//     public T getDefaultValue() {
//         return defaultValue;
//     }
// 
// }


// Path: src/main/java/net/klakegg/pkix/ocsp/fetcher/ApacheOcspFetcher.java
import net.klakegg.pkix.ocsp.api.OcspFetcher;
import net.klakegg.pkix.ocsp.api.OcspFetcherResponse;
import net.klakegg.pkix.ocsp.builder.BuildHandler;
import net.klakegg.pkix.ocsp.builder.Builder;
import net.klakegg.pkix.ocsp.builder.Properties;
import net.klakegg.pkix.ocsp.builder.Property;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

package net.klakegg.pkix.ocsp.fetcher;



/**
 * @author erlend
 */
public class ApacheOcspFetcher extends AbstractOcspFetcher {

    public static final Property<HttpClientConnectionManager> CONNECTION_MANAGER = Property.create();

    public static final Property<Boolean> CONNECTION_MANAGER_SHARED = Property.create(false);

    public static final Property<Integer> TIMEOUT_CONNECTION_MANAGER = Property.create(-1);

    /**
     * Builder to create an instance of OcspFetcher using Apache HttpClient for connectivity.
     *
     * @return Prepared fetcher.
     */
    public static Builder<OcspFetcher> builder() {
        return new Builder<>(new BuildHandler<OcspFetcher>() {
            @Override
            public OcspFetcher build(Properties properties) {
                return new ApacheOcspFetcher(properties);
            }
        });
    }

    private ApacheOcspFetcher(Properties properties) {
        super(properties);
    }

    @Override
    public OcspFetcherResponse fetch(URI uri, byte[] content) throws IOException {
        HttpPost httpPost = new HttpPost(uri);
        httpPost.setHeader("Content-Type", "application/ocsp-request");
        httpPost.setHeader("Accept", "application/ocsp-response");
        httpPost.setEntity(new ByteArrayEntity(content));
        httpPost.setConfig(getRequestConfig());

        return new ApacheOcspFetcherResponse(getHttpClient().execute(httpPost));
    }

    protected CloseableHttpClient getHttpClient() {
        return HttpClientBuilder.create()
                .setConnectionManager(properties.get(CONNECTION_MANAGER))
                .setConnectionManagerShared(properties.get(CONNECTION_MANAGER_SHARED))