1. Client Introduction
2. Approaches/Ways to create client
2.1 Using build() or Bootstrapping with ClientBuilder [used to build client with meta-data]
2.2 Using newClient() [Used to create a hallow/empty client quickly]
1. Client Introduction:
One huge gaping hole in the first version of the JAX-RS specification was the lack of a client API. We could slog (work-hard) through the very difficult-to-use java.net.URL set of classes to invoke on remote RESTful services. Alternate we could use something like Apache HTTP Client, which is not JAX-RS aware, so we have to do marshalling and un-marshalling of Java objects manually. Finally, we need opt (choose, select, pick) to use one of the proprietary client APIs of one of the many JAX-RS implementations out there. That means we need to relay on specific client which is go into to work with that specific vendor for example if we use RESTEasy we need relay on RESTEasy Client, if we JERSEY then we need to use JERSEY provided Client which leads to client is tightly coupled to vendor specific classes.
So before JAX-RS 2.0 like in JAX-RS 1.1 we need to relay on vendor specific clients to access the Resource.
This would, of course, lock you into that vendor’s implementation. JAX-RS 2.0 fixed this problem by introducing a new HTTP client API.
So by using client API we need to send the req to the Resource and we need to read the response that Resource has sent to the client.
1. Sending the req to the Resource using Client req API.
2. Reading the response that Resource has sent using Client response API.
2. Approaches/Ways to create client:
Client:
Client is the obj that represents the connection to communicate with Resource that is there on the server side.
We can create a client obj in ways.
1. Using build() or Bootstrapping with ClientBuilder [used to build client with meta-data]
2. Using newClient() [Used to create a hallow/empty client quickly]
1. Using build() or Bootstrapping with ClientBuilder [used to build client with meta-data]:
In order to create a client we should not create Client client=new Client() bcz JAX-RS is an API so we need to use Factory to create the client, but if we use Factory that will creates only empty client but we need to build a client with pre-populated data like connection timeout, sslContext etc so we need to use Builder to create a client which is called as ClientBuilder.
SSL:
SSL (Secure Sockets Layer) is the standard security technology for establishing an encrypted link between a web server and a browser. This link ensures that all data passed between the web server and browsers remain private and integral.
SSL allows sensitive information such as credit card numbers, social security numbers, and login credentials to be transmitted securely. Normally, data sent between browsers and web servers is sent in plain text—leaving someone can vulnerable to eavesdropping (secretly listen to a conversation).
Bootstrapping with ClientBuilder:
The javax.ws.rs.client.Client interface is the main entry point into the JAX-RS Client API. Client instances manage client socket connections and are pretty heavyweight. Instances of this interface should be reused wherever possible, as it can be quite expensive to create and destroy these objects.
Client objects are created with the help of ClientBuilder class:
package javax.ws.rs.client; import java.net.URL; import java.security.KeyStore; import javax.ws.rs.core.Configurable; import javax.ws.rs.core.Configuration; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; public abstract class ClientBuilder implements Configurable<ClientBuilder> { public static Client newClient() {...} public static Client newClient(final Configuration configuration) {...} public static ClientBuilder newBuilder() {...} public abstract ClientBuilder sslContext(final SSLContext sslContext); public abstract ClientBuilder keyStore(final KeyStore keyStore, final char[] password); public ClientBuilder keyStore(final KeyStore keyStore,final String password) {...} public abstract ClientBuilder trustStore(final KeyStore trustStore); public abstract ClientBuilder hostnameVerifier(final HostnameVerifier verifier); public abstract Client build(); }
The JAX-RS has provided one method newBuilder() to call ClientBuilder.newBuilder(). It instantiates a pre-initialized Client that we can use right away. To fine-tune the construction of your Client interfaces, the newBuilder() method creates a ClientBuilder instance that allows you to register components and set configuration properties. It inherits these capabilities by implementing the Configurable interface:
package javax.ws.rs.core;
public interface Configurable<C extends Configurable> {
public C property(String name, Object value);
public C register(Class<?> componentClass);
public C register(Object component);
...
}
The Resource is expecting either xml/json etc then we need to send as part of the xml/json but we are dealing with obj's in our application so we need to convert this obj into the xml/json format so that we can send the input to the Resource that's where we need to use MessageBodyWriters and MessageReaders at client side as well for marshalling/un-marshalling.
Mesaage Body Writer will writes the obj of data to the xml/json and then calls the toWrite() to write the data to output stream to call the server.
Similarly we need to use Message Body Readers to read the data in the form of java obj that that is coming in terms of xml/json as part of the response body.
If we observe we need to MessageBodyWriters at the client side is used to write obj of data in the form of xml/json to the Resource over the network and to read this xml/json data at the server side we need use MessageBodyReader to convert this xml/json obj into obj format at server side.
After performing the operation by the server it needs to send the data to the client in the form of xml/json so inorder to send obj of data to the client in the form of xml/json we need use MessageBodyWriter which will writes obj of data in the xml/json to the output stream so now Runtime will sends this obj of data to the client, now client need to read the data that is sent by the Resource as response for this we need to use MessageBodyReaders to read the data in the form of obj from the xml/json by performing un-marshalling (xml/json to obj convertion).
Similarly we need to use ContextResolver as well at the client sides.
So we need to register all these by using register() method that is there as part of the ClientBuilder so that client be build with pre-defined meta-data.
ClientBuilder builder = ClientBuilder.newBuilder(); builder.property("coonection.timeout", 100); // Now client has been created with predefined metadata or properties Client client = builder.build();
The build() method is used to build the client obj on the builder obj.
The ClientBuilder class also has methods to configure SSL which is useful for REST Security. Let’s take a look at using ClientBuilder:
ClientBuilder builder = ClientBuilder.newBuilder();
builder.property("coonection.timeout", 100);
builder.sslContext(sslContext);
builder.register(JacksonJsonProvider.class);// (or)
builder.register(JAXBProvider.class);
// Now client has been created with predefined metadata or properties
Client client = builder.build();
Instead creating builder and then building the client in multiple lines we can create in a single line bcz they provided method chaining to create the client easily.
Client client = ClientBuilder.newBuilder() .property("connection.timeout", 100) .sslContext(sslContext) .register(JacksonJsonProvider.class) .build();
// Now client has been created with predefined metadata or properties
We created a ClientBuilder instance by calling the static method ClientBuilder.newBuilder(). We then set a proprietary, JAX-RS implementation–specific configuration property that controls socket connection timeouts. Next we specify the sslContext we want to use to manage HTTPS connections. The RESTful services we're going to interact with are primarily JSON, so we register() an @Provider that knows how to marshal Java objects to and from JSON. Finally, we call build() to create the Client instance.
Client objects often pool connections for performance reasons like connection obj in Jdbc so ClentBuilder will maintains pool of clients with pre-populated meta data so whenever the programmer will calls build() the it will gives one client connection from the client-pool which is pre-populated meta-data. If we ask one obj by calling build() it will gives one more client obj from the pool which is also pre-populated meta-data bcz we are asking the builder to build the client so it will creates and gives client with pre-populated meta-data.
2. Using newClient():
For example if ClientBuilder is creating 10-client obj's then if we populate pre-populated meta data then ClientBuilder will creates the all client obj's or all client obj's pool with predefined meta-data which is better if we want to use same meta data for all the clients, but we wanted use these meta data for specific clients only then memory will be wasted bcz all the clients loaded with un-used meta data even though the specific clients don't want so to avoid such type problems we can create a client using ClientBuilder.newCLient() then add specific meta data at the client level rather than at the builder level so that we can avoid creating a client with costly meta data for all the clients.
For example for some clients we wanted to load with xml/json provider classes and some clients we don’t want json then we can register provider classes for specific classes by using this mechanism so that we can avoid multiple clients loaded with un-used meta-data.
But if we wanted to create a multiple clients with same meta data then go for build() so that all the clients loaded with common meta data at the builder level so that builder will creates client pool with same meta data like sessionFactory is loaded with all meta data using configuration and by using this pre-build sessionFactory meta data we can create multiple sessions with same meta-data for all the sessions.
It is the quickest way of creating a client when we don't want to build a client with meta-data.
If we want we register at meta data for specific clients then we can register all the properties and provider classes bcz both ClientBuilder (AC) and Client (I) and inheriting form the Configurable (I) so both will have the methods.
The newClient() always creates hallow/empty new client obj on ClientBuilder class.
Client client = ClientBuilder.newClient();
Internally JAX-RA API will creates Client using build() method only but with empty/hallow meta-data as follows
public abstract interface Client extends Configurable<Client> {
public abstract void close();
....
}
public abstract class ClientBuilder implements Configurable<ClientBuilder> {
public static Client newClient() {
return newBuilder().build();
}
....
}
Client client = ClientBuilder.newClient(); client.property("coonection.timeout", 100); client.register(JacksonJsonProvider.class);// (or) client.register(JAXBProvider.class); client.close();
Always remember to close our Client objects as client.close(). Client objects often pool connections for performance reasons. If we do not close them, we are leaking valuable system resources. While most JAX-RS implementations implement a finalize() method for Client, it is not a good idea to rely on the garbage collector to clean up poorly written code, that is the reason we need to close the client obj's explicitly to make client obj free for other client connections.
Run the ClientPoolTest.java (whch is JSE programme to test the client-pool)
Output on console:
org.glassfish.jersey.client.JerseyClient@7f10f850
org.glassfish.jersey.client.JerseyClient@331e8d5c
client1==client2: false
--------------------------
org.glassfish.jersey.client.JerseyClient@7393e1fc
org.glassfish.jersey.client.JerseyClient@71d9a2ab
client1==client2: false
So as client is costly obj we need to close client, so that it can used by some other client connections from the client-pool The client-pool is maintained by implementation vendor like JERSEY and RESTEasy by using ClientBuilder (ClientBuilder is JAX-RS API class). That is the reason it printed obj's as org.glassfish.jersey.client.JerseyClient@7f10f850 etc bcz we are using JERSEY.
How many we can create a client?
We can create client in 2-ways.
1. Using build() or Bootstrapping with ClientBuilder [used to build client with meta-data]
2 Using newClient() [Used to create a hallow/empty client quickly]
How to increase the connection-timeout at the client side?
By using builder.property(“connection-timeout”, 200) or client.property(“connection-timeout”, 200);
2 Comments
please explain soap one also
ReplyDeleteI read this post your post so nice and very informative post thanks for sharing this post
ReplyDelete