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

com.sun.jersey.api.client.Client Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2010-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * http://glassfish.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package com.sun.jersey.api.client;

import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.ClientFilter;
import com.sun.jersey.api.client.filter.Filterable;
import com.sun.jersey.client.impl.CopyOnWriteHashMap;
import com.sun.jersey.client.proxy.ViewProxy;
import com.sun.jersey.client.proxy.ViewProxyProvider;
import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentInjector;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.core.spi.component.ProviderFactory;
import com.sun.jersey.core.spi.component.ProviderServices;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProcessor;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProcessorFactory;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProcessorFactoryInitializer;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProviderFactory;
import com.sun.jersey.core.spi.component.ioc.IoCProviderFactory;
import com.sun.jersey.core.spi.factory.ContextResolverFactory;
import com.sun.jersey.core.spi.factory.InjectableProviderFactory;
import com.sun.jersey.core.spi.factory.MessageBodyFactory;
import com.sun.jersey.core.util.FeaturesAndProperties;
import com.sun.jersey.core.util.LazyVal;
import com.sun.jersey.spi.MessageBodyWorkers;
import com.sun.jersey.spi.inject.ClientSide;
import com.sun.jersey.spi.inject.Errors;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import com.sun.jersey.spi.inject.SingletonTypeInjectableProvider;
import com.sun.jersey.spi.service.ServiceFinder;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Providers;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * The main class for creating {@link WebResource} instances and configuring
 * the properties of connections and requests.
 * 

* {@link ClientFilter} instances may be added to the client for filtering * requests and responses, including those of {@link WebResource} instances * created from the client. *

* A client may be configured by passing a {@link ClientConfig} instance to * the appropriate constructor. *

* Methods to create instances of {@link WebResource} are thread-safe. Methods * that modify configuration and or filters are not guaranteed to be * thread-safe. *

* The creation of a Client instance is an expensive operation and * the instance may make use of and retain many resources. It is therefore * recommended that a Client instance is reused for the creation of * {@link WebResource} instances that require the same configuration settings. *

* A client may integrate with an IoC framework by passing a * {@link IoCComponentProviderFactory} instance to the appropriate constructor. * * @author [email protected] */ public class Client extends Filterable implements ClientHandler { private static final Logger LOGGER = Logger.getLogger(Client.class.getName()); private ProviderFactory componentProviderFactory; private Providers providers; private boolean destroyed = false; private LazyVal executorService; private CopyOnWriteHashMap properties; private Set vpps; private MessageBodyFactory workers; private static class ContextInjectableProvider extends SingletonTypeInjectableProvider { ContextInjectableProvider(Type type, T instance) { super(type, instance); } } /** * Create a new client instance. * */ public Client() { this(createDefaultClientHander(), new DefaultClientConfig(), null); } /** * Create a new client instance. * * @param root the root client handler for dispatching a request and * returning a response. */ public Client(ClientHandler root) { this(root, new DefaultClientConfig(), null); } /** * Create a new client instance with a client configuration. * * @param root the root client handler for dispatching a request and * returning a response. * @param config the client configuration. */ public Client(ClientHandler root, ClientConfig config) { this(root, config, null); } /** * Create a new instance with a client configuration and a * component provider. * * @param root the root client handler for dispatching a request and * returning a response. * @param config the client configuration. * @param provider the IoC component provider factory. */ public Client(final ClientHandler root, final ClientConfig config, final IoCComponentProviderFactory provider) { // Defer instantiation of root to component provider super(root); Errors.processWithErrors(new Errors.Closure() { @Override public Void f() { Errors.setReportMissingDependentFieldOrMethod(false); init(root, config, provider); return null; } }); } private void init(ClientHandler root, ClientConfig config, IoCComponentProviderFactory provider) { final Object threadpoolSize = config.getProperties().get(ClientConfig.PROPERTY_THREADPOOL_SIZE); this.executorService = new LazyVal() { @Override protected ExecutorService instance() { if(threadpoolSize != null && threadpoolSize instanceof Integer && (Integer)threadpoolSize > 0) { return Executors.newFixedThreadPool((Integer) threadpoolSize); } else { return Executors.newCachedThreadPool(); } } }; Class[] components = ServiceFinder.find("jersey-client-components").toClassArray(); if (components.length > 0) { if (LOGGER.isLoggable(Level.INFO)) { StringBuilder b = new StringBuilder(); b.append("Adding the following classes declared in META-INF/services/jersey-client-components to the client configuration:"); for (Class c : components) b.append('\n').append(" ").append(c); LOGGER.log(Level.INFO, b.toString()); } config = new ComponentsClientConfig(config, components); } final InjectableProviderFactory injectableFactory = new InjectableProviderFactory(); getProperties().putAll(config.getProperties()); if (provider != null) { if (provider instanceof IoCComponentProcessorFactoryInitializer) { IoCComponentProcessorFactoryInitializer i = (IoCComponentProcessorFactoryInitializer)provider; i.init(new ComponentProcessorFactoryImpl(injectableFactory)); } } // Set up the component provider factory this.componentProviderFactory = (provider == null) ? new ProviderFactory(injectableFactory) : new IoCProviderFactory(injectableFactory, provider); ProviderServices providerServices = new ProviderServices( ClientSide.class, this.componentProviderFactory, config.getClasses(), config.getSingletons()); // Get the set of WebResourceProxy vpps = providerServices.getServices(ViewProxyProvider.class); // Allow injection of features and properties injectableFactory.add(new ContextInjectableProvider( FeaturesAndProperties.class, config)); // Allow injection of client config injectableFactory.add(new ContextInjectableProvider( ClientConfig.class, config)); // Allow injection of client injectableFactory.add(new ContextInjectableProvider( Client.class, this)); injectableFactory.configure(providerServices); // Obtain all context resolvers final ContextResolverFactory crf = new ContextResolverFactory(); // Obtain all message body readers/writers final MessageBodyFactory bodyContext = new MessageBodyFactory(providerServices, config.getFeature(FeaturesAndProperties.FEATURE_PRE_1_4_PROVIDER_PRECEDENCE)); workers = bodyContext; // Allow injection of message body context injectableFactory.add(new ContextInjectableProvider( MessageBodyWorkers.class, bodyContext)); // Injection of Providers this.providers = new Providers() { @Override public MessageBodyReader getMessageBodyReader(Class c, Type t, Annotation[] as, MediaType m) { return bodyContext.getMessageBodyReader(c, t, as, m); } @Override public MessageBodyWriter getMessageBodyWriter(Class c, Type t, Annotation[] as, MediaType m) { return bodyContext.getMessageBodyWriter(c, t, as, m); } @Override public ExceptionMapper getExceptionMapper(Class c) { throw new IllegalArgumentException("This method is not supported on the client side"); } @Override public ContextResolver getContextResolver(Class ct, MediaType m) { return crf.resolve(ct, m); } }; injectableFactory.add( new ContextInjectableProvider( Providers.class, this.providers)); injectableFactory.add(new InjectableProvider() { @Override public ComponentScope getScope() { return ComponentScope.Singleton; } @Override public Injectable getInjectable(ComponentContext ic, Context a, Type c) { if (c instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType)c; if (pt.getRawType() == Injectable.class) { if (pt.getActualTypeArguments().length == 1) { final Injectable i = injectableFactory.getInjectable( a.annotationType(), ic, a, pt.getActualTypeArguments()[0], ComponentScope.PERREQUEST_UNDEFINED_SINGLETON); if (i == null) return null; return new Injectable() { @Override public Injectable getValue() { return i; } }; } } } return null; } }); // Initiate context resolvers crf.init(providerServices, injectableFactory); // Initiate message body readers/writers bodyContext.init(); // Inject on all components Errors.setReportMissingDependentFieldOrMethod(true); componentProviderFactory.injectOnAllComponents(); componentProviderFactory.injectOnProviderInstances(config.getSingletons()); componentProviderFactory.injectOnProviderInstance(root); } private class ComponentProcessorFactoryImpl implements IoCComponentProcessorFactory { private final InjectableProviderFactory injectableFactory; ComponentProcessorFactoryImpl(InjectableProviderFactory injectableFactory) { this.injectableFactory = injectableFactory; } @Override public ComponentScope getScope(Class c) { return ComponentScope.Singleton; } @Override public IoCComponentProcessor get(Class c, ComponentScope scope) { final ComponentInjector ci = new ComponentInjector(injectableFactory, c); return new IoCComponentProcessor() { @Override public void preConstruct() { } @Override public void postConstruct(Object o) { ci.inject(o); } }; } } /** * Destroy the client. Any system resources associated with the client * will be cleaned up. *

* This method must be called when there are not responses pending otherwise * undefined behavior will occur. *

* The client must not be reused after this method is called otherwise * undefined behavior will occur. */ public void destroy() { if (!destroyed) { componentProviderFactory.destroy(); destroyed = true; } } /** * Defer to {@link #destroy() } */ @Override @SuppressWarnings("FinalizeDeclaration") protected void finalize() throws Throwable { destroy(); super.finalize(); } /** * Get the {@link Providers} utilized by the client. * * @return the {@link Providers} utilized by the client. */ public Providers getProviders() { return providers; } /** * Get the {@link MessageBodyWorkers} utilized by the client. * * @return the {@link MessageBodyWorkers} utilized by the client. */ public MessageBodyWorkers getMessageBodyWorkers() { return workers; } /** * Create a Web resource from the client. * * @param u the URI of the resource. * @return the Web resource. */ public WebResource resource(String u) { return resource(URI.create(u)); } /** * Create a Web resource from the client. * * @param u the URI of the resource. * @return the Web resource. */ public WebResource resource(URI u) { return new WebResource(this, this.properties, u); } /** * Create an asynchronous Web resource from the client. * * @param u the URI of the resource. * @return the Web resource. */ public AsyncWebResource asyncResource(String u) { return asyncResource(URI.create(u)); } /** * Create an asynchronous Web resource from the client. * * @param u the URI of the resource. * @return the Web resource. */ public AsyncWebResource asyncResource(URI u) { return new AsyncWebResource(this, this.properties, u); } public ViewResource viewResource(String u) { return viewResource(URI.create(u)); } public ViewResource viewResource(URI u) { return new ViewResource(this, u); } public AsyncViewResource asyncViewResource(String u) { return asyncViewResource(URI.create(u)); } public AsyncViewResource asyncViewResource(URI u) { return new AsyncViewResource(this, u); } public T view(String u, Class type) { ViewResource vr = viewResource(u); return vr.get(type); } public T view(URI uri, Class type) { ViewResource vr = viewResource(uri); return vr.get(type); } public T view(String u, T t) { ViewResource vr = viewResource(u); return vr.get(t); } public T view(URI uri, T t) { ViewResource vr = viewResource(uri); return vr.get(t); } public Future asyncView(String u, Class type) { AsyncViewResource vr = asyncViewResource(u); return vr.get(type); } public Future asyncView(URI uri, Class type) { AsyncViewResource vr = asyncViewResource(uri); return vr.get(type); } public Future asyncView(String u, T t) { AsyncViewResource vr = asyncViewResource(u); return vr.get(t); } public Future asyncView(URI uri, T t) { AsyncViewResource vr = asyncViewResource(uri); return vr.get(t); } public T view(Class c, ClientResponse response) { return getViewProxy(c).view(c, response); } public T view(T t, ClientResponse response) { return getViewProxy((Class)t.getClass()).view(t, response); } public ViewProxy getViewProxy(Class c) { for (ViewProxyProvider vpp : vpps) { ViewProxy vp = vpp.proxy(this, c); if (vp != null) { return vp; } } throw new IllegalArgumentException("A view proxy is not " + "available for the class '" + c.getName() + "'"); } /** * Set the {@link ExecutorService} for sending asynchronous * HTTP requests when no underlying asynchronous HTTP implementation is * utilized. * * @param es the {@link ExecutorService}. * @since 1.4 */ public void setExecutorService(ExecutorService es) { if (es == null) throw new IllegalArgumentException("ExecutorService service MUST not be null"); this.executorService.set(es); } /** * Get the {@link ExecutorService} for sending asynchronous * HTTP requests when no underlying asynchronous HTTP implementation is * utilized. *

* By default the implementation returned * from {@link Executors#newCachedThreadPool() } is utilized. * * @return the {@link ExecutorService}. * @since 1.4 */ public ExecutorService getExecutorService() { return executorService.get(); } /** * Get the mutable property bag. * * @return the property bag. */ public Map getProperties() { if (properties == null) properties = new CopyOnWriteHashMap(); return properties; } /** * Set if redirection should be performed or not. * * This method is the functional equivalent to setting the property * {@link ClientConfig#PROPERTY_FOLLOW_REDIRECTS} on the property bag * returned from {@link #getProperties} * * @param redirect if true then the client will automatically redirect * to the URI declared in 3xx responses. */ public void setFollowRedirects(Boolean redirect) { getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, redirect); } /** * Set the read timeout interval, in milliseconds. * * This method is the functional equivalent to setting the property * {@link ClientConfig#PROPERTY_READ_TIMEOUT} on the property bag * returned from {@link #getProperties} * * @param interval the read timeout interval. If null or 0 then * an interval of infinity is declared. */ public void setReadTimeout(Integer interval) { getProperties().put(ClientConfig.PROPERTY_READ_TIMEOUT, interval); } /** * Set the connect timeout interval, in milliseconds. * * This method is the functional equivalent to setting the property * {@link ClientConfig#PROPERTY_CONNECT_TIMEOUT} on the property bag * returned from {@link #getProperties} * * @param interval the connect timeout interval. If null or 0 then * an interval of infinity is declared. */ public void setConnectTimeout(Integer interval) { getProperties().put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, interval); } /** * Set the client to send request entities using chunked encoding * with a particular chunk size. * * This method is the functional equivalent to setting the property * {@link ClientConfig#PROPERTY_CHUNKED_ENCODING_SIZE} on the property bag * returned from {@link #getProperties} * * @param chunkSize the chunked encoding size. If <= 0 then the default * size will be used. If null then chunked encoding will not be * utilized. */ public void setChunkedEncodingSize(Integer chunkSize) { getProperties().put(ClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE, chunkSize); } // ClientHandler @Override public ClientResponse handle(final ClientRequest request) throws ClientHandlerException { Map effectiveProperties = new HashMap(properties); effectiveProperties.put(Client.class.getName(), this); effectiveProperties.putAll(request.getProperties()); request.setProperties(effectiveProperties); final ClientResponse response = getHeadHandler().handle(request); response.getProperties().put(Client.class.getName(), this); return response; } /** * Inject client-side bindings on an instance. * * @param o the instance to inject on. */ public void inject(Object o) { componentProviderFactory.injectOnProviderInstance(o); } /** * Create a default client. * * @return a default client. */ public static Client create() { return new Client(createDefaultClientHander()); } /** * Create a default client with client configuration. * * @param cc the client configuration. * @return a default client. */ public static Client create(ClientConfig cc) { return new Client(createDefaultClientHander(), cc); } /** * Create a default client with client configuration and component provider. * * @param cc the client configuration. * @param provider the IoC component provider factory. * @return a default client. */ public static Client create(ClientConfig cc, IoCComponentProviderFactory provider) { return new Client(createDefaultClientHander(), cc, provider); } /** * Create a default client handler. *

* This implementation returns a client handler implementation that * utilizes {@link HttpURLConnection}. * * @return a default client handler. */ private static ClientHandler createDefaultClientHander() { return new URLConnectionClientHandler(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy