// Path: core-client/src/main/java/net/winterly/rxjersey/client/inject/RemoteResolver.java
// @Singleton
// public class RemoteResolver implements InjectionResolver<Remote> {
// 
//     private InjectionManager injectionManager;
//     private ClientMethodInvoker clientMethodInvoker;
//     private Client client;
// 
//     public RemoteResolver(InjectionManager injectionManager, ClientMethodInvoker methodInvoker, Client client) {
//         this.injectionManager = injectionManager;
//         this.clientMethodInvoker = methodInvoker;
//         this.client = client;
//     }
// 
//     private static URI merge(String value, UriInfo uriInfo) {
//         URI target = URI.create(value);
//         if (target.getHost() == null) {
//             target = UriBuilder.fromUri(uriInfo.getBaseUri()).uri(target).build();
//         }
// 
//         return target;
//     }
// 
//     /**
//      * @return RxWebTarget or Proxy client of specified injectee interface
//      * @throws IllegalStateException if uri is not correct or there is no sufficient injection resolved
//      */
//     @Override
//     public Object resolve(Injectee injectee) {
//         Remote remote = injectee.getParent().getAnnotation(Remote.class);
//         UriInfo uriInfo = injectionManager.getInstance(UriInfo.class);
// 
//         URI target = merge(remote.value(), uriInfo);
//         WebTarget webTarget = client.target(target);
//         Type type = injectee.getRequiredType();
// 
//         if (type instanceof Class) {
//             Class<?> required = (Class) type;
// 
//             if (WebTarget.class.isAssignableFrom(required)) {
//                 return webTarget;
//             }
// 
//             if (required.isInterface()) {
//                 return WebResourceFactory.newResource(required, webTarget, clientMethodInvoker);
//             }
//         }
// 
//         throw new IllegalStateException(format("Can't find proper injection for %s", type));
//     }
// 
//     @Override
//     public boolean isConstructorParameterIndicator() {
//         return true;
//     }
// 
//     @Override
//     public boolean isMethodParameterIndicator() {
//         return true;
//     }
// 
//     @Override
//     public Class<Remote> getAnnotation() {
//         return Remote.class;
//     }
// }
// 
// Path: core-client/src/main/java/net/winterly/rxjersey/client/inject/RxJerseyBinder.java
// public abstract class RxJerseyBinder extends AbstractBinder {
// 
//     private final Field injectionManagerField;
// 
//     public RxJerseyBinder() {
//         try {
//             // Damn private properties everywhere
//             injectionManagerField = AbstractBinder.class.getDeclaredField("injectionManager");
//             injectionManagerField.setAccessible(true);
//         } catch (NoSuchFieldException e) {
//             throw new RuntimeException(e);
//         }
//     }
// 
//     protected InjectionManager getInjectionManager() {
//         try {
//             return (InjectionManager) injectionManagerField.get(this);
//         } catch (IllegalAccessException e) {
//             throw new RuntimeException(e);
//         }
//     }
// }


import net.winterly.rxjersey.client.inject.RemoteResolver;
import net.winterly.rxjersey.client.inject.RxJerseyBinder;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.rx.rxjava2.RxFlowableInvokerProvider;
import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
package net.winterly.rxjersey.client.rxjava2;



/**
 * Feature implementation to configure RxJava support for clients
 */
public class RxJerseyClientFeature implements Feature {

    private Client client;

    public RxJerseyClientFeature setClient(Client client) {
        this.client = client;
        return this;
    }

    @Override
    public boolean configure(FeatureContext context) {
        if (client == null) {
            client = defaultClient();
        }

        client.register(RxBodyReader.class);
        context.register(new Binder());

        return true;
    }

    private Client defaultClient() {
        int cores = Runtime.getRuntime().availableProcessors();
        ClientConfig config = new ClientConfig();
        config.connectorProvider(new GrizzlyConnectorProvider());
        config.property(ClientProperties.ASYNC_THREADPOOL_SIZE, cores);
        config.register(RxFlowableInvokerProvider.class);

        return ClientBuilder.newClient(config);
    }

    private class Binder extends RxJerseyBinder {

        @Override
        protected void configure() {
// Path: core-client/src/main/java/net/winterly/rxjersey/client/inject/RemoteResolver.java
// @Singleton
// public class RemoteResolver implements InjectionResolver<Remote> {
// 
//     private InjectionManager injectionManager;
//     private ClientMethodInvoker clientMethodInvoker;
//     private Client client;
// 
//     public RemoteResolver(InjectionManager injectionManager, ClientMethodInvoker methodInvoker, Client client) {
//         this.injectionManager = injectionManager;
//         this.clientMethodInvoker = methodInvoker;
//         this.client = client;
//     }
// 
//     private static URI merge(String value, UriInfo uriInfo) {
//         URI target = URI.create(value);
//         if (target.getHost() == null) {
//             target = UriBuilder.fromUri(uriInfo.getBaseUri()).uri(target).build();
//         }
// 
//         return target;
//     }
// 
//     /**
//      * @return RxWebTarget or Proxy client of specified injectee interface
//      * @throws IllegalStateException if uri is not correct or there is no sufficient injection resolved
//      */
//     @Override
//     public Object resolve(Injectee injectee) {
//         Remote remote = injectee.getParent().getAnnotation(Remote.class);
//         UriInfo uriInfo = injectionManager.getInstance(UriInfo.class);
// 
//         URI target = merge(remote.value(), uriInfo);
//         WebTarget webTarget = client.target(target);
//         Type type = injectee.getRequiredType();
// 
//         if (type instanceof Class) {
//             Class<?> required = (Class) type;
// 
//             if (WebTarget.class.isAssignableFrom(required)) {
//                 return webTarget;
//             }
// 
//             if (required.isInterface()) {
//                 return WebResourceFactory.newResource(required, webTarget, clientMethodInvoker);
//             }
//         }
// 
//         throw new IllegalStateException(format("Can't find proper injection for %s", type));
//     }
// 
//     @Override
//     public boolean isConstructorParameterIndicator() {
//         return true;
//     }
// 
//     @Override
//     public boolean isMethodParameterIndicator() {
//         return true;
//     }
// 
//     @Override
//     public Class<Remote> getAnnotation() {
//         return Remote.class;
//     }
// }
// 
// Path: core-client/src/main/java/net/winterly/rxjersey/client/inject/RxJerseyBinder.java
// public abstract class RxJerseyBinder extends AbstractBinder {
// 
//     private final Field injectionManagerField;
// 
//     public RxJerseyBinder() {
//         try {
//             // Damn private properties everywhere
//             injectionManagerField = AbstractBinder.class.getDeclaredField("injectionManager");
//             injectionManagerField.setAccessible(true);
//         } catch (NoSuchFieldException e) {
//             throw new RuntimeException(e);
//         }
//     }
// 
//     protected InjectionManager getInjectionManager() {
//         try {
//             return (InjectionManager) injectionManagerField.get(this);
//         } catch (IllegalAccessException e) {
//             throw new RuntimeException(e);
//         }
//     }
// }


// Path: rxjava2-client/src/main/java/net/winterly/rxjersey/client/rxjava2/RxJerseyClientFeature.java
import net.winterly.rxjersey.client.inject.RemoteResolver;
import net.winterly.rxjersey.client.inject.RxJerseyBinder;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.rx.rxjava2.RxFlowableInvokerProvider;
import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;

package net.winterly.rxjersey.client.rxjava2;



/**
 * Feature implementation to configure RxJava support for clients
 */
public class RxJerseyClientFeature implements Feature {

    private Client client;

    public RxJerseyClientFeature setClient(Client client) {
        this.client = client;
        return this;
    }

    @Override
    public boolean configure(FeatureContext context) {
        if (client == null) {
            client = defaultClient();
        }

        client.register(RxBodyReader.class);
        context.register(new Binder());

        return true;
    }

    private Client defaultClient() {
        int cores = Runtime.getRuntime().availableProcessors();
        ClientConfig config = new ClientConfig();
        config.connectorProvider(new GrizzlyConnectorProvider());
        config.property(ClientProperties.ASYNC_THREADPOOL_SIZE, cores);
        config.register(RxFlowableInvokerProvider.class);

        return ClientBuilder.newClient(config);
    }

    private class Binder extends RxJerseyBinder {

        @Override
        protected void configure() {
            bind(new RemoteResolver(