/*
* COMSAT
* Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.fibers.ws.rs.client;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.security.KeyStore;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Configuration;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
import org.glassfish.jersey.spi.ExecutorServiceProvider;
/**
* Main entry point to the client API used to bootstrap Client instances that integrate with Quasar fibers.
*/
public class AsyncClientBuilder extends ClientBuilder {
private final ClientBuilder clientBuilder;
protected AsyncClientBuilder(ClientBuilder clientBuilder) {
this.clientBuilder = clientBuilder;
}
/**
* Create a new {@code ClientBuilder} instance using the default client builder
* implementation class provided by the JAX-RS implementation provider.
*
* @return new client builder instance.
*/
public static ClientBuilder newBuilder() {
return new AsyncClientBuilder(ClientBuilder.newBuilder().withConfig(addDefaultConfigurations(null)));
}
/**
* Create a new {@link Client} instance using the default client builder implementation
* class provided by the JAX-RS implementation provider.
*
* @return new client instance.
*/
public static Client newClient() {
return newClient(null);
}
/**
* Create a new custom-configured {@link Client} instance using the default client builder
* implementation class provided by the JAX-RS implementation provider.
*
* @param configuration data used to provide initial configuration for the new client instance.
* @return a new, configured, client instance.
*/
public static Client newClient(Configuration configuration) {
return new FiberClient(ClientBuilder.newClient(addDefaultConfigurations(configuration)));
}
private static ClientConfig addDefaultConfigurations(Configuration configuration) {
// currently there is no usage with the singleThreadPool variable due to jersey bug. See below.
final ExecutorServiceProvider singleThreadPool = new ExecutorServiceProvider() {
private ExecutorService tp = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setDaemon(true).setNameFormat("jersey-puniverse-single-worker-%d").build());
@Override
public ExecutorService getExecutorService() {
return tp;
}
@Override
public void dispose(ExecutorService es) {
}
};
final ClientConfig config = new ClientConfig().
// This is commented since, jersey has major problem (since ~2.5) - it blocks the calling thread !!!
// When this bug will be fixed we should uncomment this line in order to enable a lot of concurrent open requsets
// register(singleThreadPool, RequestExecutorProvider.class).
property(ClientProperties.ASYNC_THREADPOOL_SIZE, 20);
if (configuration != null)
config.loadFrom(configuration);
if (config.getConnectorProvider() == null)
config.connectorProvider(new JettyConnectorProvider());
return config;
}
@Override
public Client build() {
return new FiberClient(clientBuilder.build());
}
@Override
public ClientBuilder withConfig(Configuration config) {
clientBuilder.withConfig(addDefaultConfigurations(config));
return this;
}
@Override
public ClientBuilder sslContext(SSLContext sslContext) {
clientBuilder.sslContext(sslContext);
return this;
}
@Override
public ClientBuilder keyStore(KeyStore keyStore, char[] password) {
clientBuilder.keyStore(keyStore, password);
return this;
}
@Override
public ClientBuilder keyStore(KeyStore keyStore, String password) {
clientBuilder.keyStore(keyStore, password);
return this;
}
@Override
public ClientBuilder trustStore(KeyStore trustStore) {
clientBuilder.trustStore(trustStore);
return this;
}
@Override
public ClientBuilder hostnameVerifier(HostnameVerifier verifier) {
clientBuilder.hostnameVerifier(verifier);
return this;
}
@Override
public ClientBuilder property(String name, Object value) {
clientBuilder.property(name, value);
return this;
}
@Override
public ClientBuilder register(Class<?> componentClass) {
clientBuilder.register(componentClass);
return this;
}
@Override
public ClientBuilder register(Class<?> componentClass, int priority) {
clientBuilder.register(componentClass, priority);
return this;
}
@Override
public ClientBuilder register(Class<?> componentClass, Class<?>... contracts) {
clientBuilder.register(componentClass, contracts);
return this;
}
@Override
public ClientBuilder register(Class<?> componentClass, Map<Class<?>, Integer> contracts) {
clientBuilder.register(componentClass, contracts);
return this;
}
@Override
public ClientBuilder register(Object component) {
clientBuilder.register(component);
return this;
}
@Override
public ClientBuilder register(Object component, int priority) {
clientBuilder.register(component, priority);
return this;
}
@Override
public ClientBuilder register(Object component, Class<?>... contracts) {
clientBuilder.register(component, contracts);
return this;
}
@Override
public ClientBuilder register(Object component, Map<Class<?>, Integer> contracts) {
clientBuilder.register(component, contracts);
return this;
}
@Override
public Configuration getConfiguration() {
return clientBuilder.getConfiguration();
}
@Override
public int hashCode() {
return clientBuilder.hashCode();
}
@Override
public boolean equals(Object obj) {
return clientBuilder.equals(obj);
}
@Override
public String toString() {
return clientBuilder.toString();
}
}