i am creating a http REST service that consumes other http REST services.
I am using Jersey Client to call other services and i have many doubt about which creation pattern of the http client is the best.
Currently i am using EJB with injection of the client that is a Singleton shared by every methods, but i would like to remove java ee dependency and use Jetty as embedded application server.
I see from the doc that Client creation is an expensive operation so i cannot create one every time i need it.
I think about creating 1 in the constructor of every Servlet/Rest class is the simpler solution but i am not sure about the lifecycle of the servlet (if an instance is created for every request, this method is quite the same as the previous)
Or maybe is better to create a Singleton shared by every Servlet/Rest class
Or maybe better a pool of N client.
About this last two solution i need some advice... What do you think it's the better solution?
Thanks
According to you, there is a REST Service deployed in some environment and there is one application, a client or consumer, which wants to access that service.
If i am writing a normal Java class as client using Jersey API, then i will write something lime this :
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
Client client = Client.create();
WebResource webResource = client
.resource("http://localhost:8080/rest/example/employees");
ClientResponse response = webResource.accept("application/json")
.get(ClientResponse.class);
String result = response.getEntity(String.class);
Now say you are writing a servlet, which does some defined job in you application, also it makes a call to the REST Service using client block of code, everytime you access the servlet it will create a instance of com.sun.jersey.api.client.Client each time.
If you want to avoid this then you can create a initial class that will create an instance of com.sun.jersey.api.client.Client, one and only, and make it static and use the same reference where ever you want. WebResource should be created as and when required, because you might be interested to call different URIs.
I would have followed this approach, if i were in your situation.
Related
My API currently calls one Elasticsearch endpoint using JestClient. I want to add some functionality that requires calling a second, different Elasticsearch endpoint. How is this possible, when you have to specify the endpoint upon initializing JestClient?
#Provides
#Singleton
public JestClient jestClient() {
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(
new HttpClientConfig.Builder("http://localhost:9200")
.build());
return factory.getObject();
}
My application design uses Singleton classes for these initializations so I'm not sure how to fix this aside from using a different Elasticsearch client for my second endpoint.
Or you can create two clients and based on the use-case in calling classes, if you require both the clients, inject both clients or if you requires one specific client, inject that client in your class, you just need to have a different name(like clientv2 for es 2 version, and clientv5 for ES 5.x version) for your client to make it work, its easy as well, as you know your use-case and know what all versions of clients is need in your classes.
on a side note, active development of JEST is stopped long ago, and now elasticsearch provides the official java client know as Java high level rest client, so IMHO you should switch to JHLRC to get the maximum benefit and to make future migration easy, which I think is the use-case of yours.
You could create a factory and return the client depending on a parameter.
The parameter could be the url itself or just an enum that represents the endpoint.
Create a javax.ws.rs-ap.jar client and send the request to the server:
javax.ws.rs.client.Client client = ClientBuilder.newBuilder().build();
I have writtten the above code to call multiple api(get user by id, get all users and deleteUser).
My question is here.
I am creating a new Client for each api cal.
Just wanted to know i can create a single instance of Client and make multiple calls ?
Yes, a Client can be reused as long as it's lifecycle is managed properly. This means when a client instance is created, it should be closed properly as well using the close() method, once it's purpose is served. Refer to the Client API documentation.
Note that multiple client instances would be needed if each client has a different client configuration.
I am using jersey client to send POST requests to a third party webservice. Since creating jersey clients is expensive, I am doing this inside the constructor of a service client class which is Spring managed. My thinking is that when my server starts up, Spring will create my service client bean, which in turn will cause the constructor to be invoked and so my jersey client will be created once. As long as the server is up, this jersey client will be responsible for sending out the requests and no further client initializations are required. However, I will be creating a new webresource for each call as creating jersey webresources is much cheaper.
package com.mypackage;
//Bunch of imports
class MyWebserviceClient {
//jersey client member variable
private Client jClient;
public MyWebserviceClient(){
//Create jersey client
jClient = Client.create();
//Other stuff
}
public void sendRequest(){
WebResource wr = jClient.resource(someUrl);
//Use the webresource to make webservice call
}
}
MyWebserviceClient is spring managed as such in the Spring config xml:
<bean id="myClient" class="com.mypackage,MyWebserviceClient"></bean>
The bean myClient will then be injected into the appropriate place where the service call needs to be made.
My questions
1) If my application is dealing with thousands of requests per hour is it efficient enough to handle all the requests with just one jersey client.
2) Do I need some kind of jersey client pool so that a large number of requests are taken care of more efficiently. If so, is there a way to do it?
3) I would like to know in general how multiple requests coming in from the end users are handled on the server side. Each request is a separate thread of execution on the server and all of them have access to the same jersey client object. If the jersey client object is busy with one such request, are the other requests from different end users going to wait till a response is received for the ongoing request?
4) Any better alternative to the one I am using.
Your thinking is right on track.
1 - Yes, and it is recommended to reuse a client instance:
from https://jersey.java.net/documentation/1.18/client-api.html#d4e623:
Client instances are expensive resources. It is recommended a configured instance is reused for the creation of Web resources. The creation of Web resources, the building of requests and receiving of responses are guaranteed to be thread safe. Thus a Client instance and WebResource instances may be shared between multiple threads.
2 - No need, the client itself can handle the requests. In the case of asynchronous requests, it internally uses a thread pool that is configurable.
3 - The Jersey client is thread safe, so threads will not block each other
4 - You can also consider providing the client as a dependency to MyWebserviceClient, and possibly reuse the same client between multiple classes
I have two Java EE applications on two separate application servers. One of them already contains a working EJB. I want to be able to communicate with this EJB from the other application by using a JAX-WS webservice (the communication has to work between different application servers and different server versions, so remote EJB call is no option). It is no problem to expose the server api to the client application.
The server side is quite clear, adding #Webservice annotation seems to work quite well. But i wonder what is the best way to build the client: I don't really want to generate the client stub from the wsdl (which itself has been generated from the ejb code by the container in my case) and pack all these generated classes into the client ear - but this seems to be the only way i can make use of #WebServiceRef annotations.
The alternative to make a dynamic proxy myself with the help of the static methods of javax.xml.ws.Service (sth. like service=Service.create() and service.getPort()) is not recommended by the Spec and "container providers are not required to support managed Service Instances created using these methods".
But that is exactly sth. that I want to use:
Is there a way to get a dynamic proxy injected in my code, managed by the application server? Or is the only way to get a managed webservice client instance to be done with generated client stub classes?
Read JAX-WS 2.2 spec, Chapter 4: Client APIs.
1. Static Client Generation
Is really the simplest way to work with JAX-WS. From a web services perspective, the WSDL is the interface AND the connection properties. Even if you choose not to work with it physically, you still need to know it in a logical sense to make meaningful SOAP calls.
Note from JAX-WS spec: An Endpoint that uses the SOAP 1.1/HTTP binding MUST
make its contract available as a WSDL 1.1 document at the publishing address suffixed with ?WSDL or ?wsdl
2. Dynamic Client Programming
Is there a way to get a dynamic proxy injected in my code, managed by the application server?
This approach involves dynamic programming against the JAX-WS API to connect to a web service either with or without using WSDL. There's no way to just "inject" a dynamic proxy out of nowhere. You need to construct & configure one with the SEI's port URLs. The WSDL document is the standard place to store such configuration information, although it is possible to avoid it and to programmatically insert the info.
2A) Dynamic programming with WSDL:
javax.xml.ws.Service service = Service.create(
new URL("http://example.org/stocks.wsdl"),
new QName("http://example.org/stocks", "StockQuoteService"));
com.example.StockQuoteProvider proxy = service.getPort(portName,
com.example.StockQuoteProvider.class)
javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider)proxy;
Map<String,Object> context = bp.getRequestContext();
context.setProperty("javax.xml.ws.session.maintain", Boolean.TRUE);
proxy.getLastTradePrice("ACME");
Advantages over (1): can dynamically dynamically change the WSDL doc after app is deployed, provided such changes do not affect the java interface to client.
i.e. very little benefit to you. Your WSDL is static. Whilst you could point your client to <service endpoint URL>?wsdl to dynamically lookup, this means you need to manually configure <service endpoint URL> AND that leaves little else that can change in the SEI/WSDL without impacting your client logic.
2B) Dynamic programming without WSDL:
String endpointUrl = ...;
QName serviceName = new QName("http://example.org/wssample/echo/", "EchoService");
QName portName = new QName("http://example.org/wssample/echo/", "EchoServicePort");
/** Create a service and add at least one port to it. **/
Service service = Service.create(serviceName);
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl);
/** Create a Dispatch instance from a service.**/
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName,
SOAPMessage.class, Service.Mode.MESSAGE);
/** Create SOAPMessage request. **/
// compose a request message
MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
// Create a message. This example works with the SOAPPART.
SOAPMessage request = mf.createMessage();
SOAPPart part = request.getSOAPPart();
// Obtain the SOAPEnvelope and header and body elements.
SOAPEnvelope env = part.getEnvelope();
SOAPHeader header = env.getHeader();
SOAPBody body = env.getBody();
// Construct the message payload.
SOAPElement operation = body.addChildElement("invoke", "ns1",
"http://com/ibm/was/wssample/echo/");
SOAPElement value = operation.addChildElement("arg0");
value.addTextNode("ping");
request.saveChanges();
/** Invoke the service endpoint. **/
SOAPMessage response = dispatch.invoke(request);
Advantage (not really): can eventually get it to carry out same behaviour as above.
Disadvantages: Complex programming. Non-standard configuration (outside of WSDL). Need to avoid hard-coding settings. Brittle to interface changes. Manually synchronising settings between server and client - easy to omit something, extremely difficult to debug.
Answer:
Go back to (1). Generate a client stub from the WSDL. Use it as an interface contract - it should be designed well and not change.
Then spend the time you save solving real problems... ;) ;)
I am using the ServletTester class provided by Jetty to test one of my servlets.
The servlet reads the the body of the request using InputStream.read() to construct a byte[] which is the decoded and acted on by the servlet.
The ServletTest class provides a method getResponses(ByteArrayBuffer) but I'm unsure how to create one of these in the correct format since it would also need to contain things like headers (e.g. "Content-Type: application/octet-stream).
Can anyone show me an easy way to construct this, preferably using an existing library so that I can use it in a similar way to the HttpTester class.
If there is a "better" way to test servlets (ideally using a local connector rather than via the tcp stack) I'd like to hear that also.
Many thanks,
Why use a mock at all? Why not test the servlet by running it in jetty?
Servlet servlet = new MyServlet();
String mapping = "/foo";
Server server = new Server(0);
Context servletContext = new Context(server, contextPath, Context.SESSIONS);
servletContext.addServlet(new ServletHolder(servlet), mapping);
server.start();
URL url = new URL("http", "localhost", server.getConnectors()[0].getLocalPort(), "/foo?bar");
//get the url...assert what you want
//finally server.stop();
Edit: Just wanting to reassure people that this is very fast. Its also a very reliable indicator of what your code will actually do, because it is in fact doing it.
Spring MVC provides a small set of "mock" classes for the various javax.servlet interfaces, such as HttpServletRequest, HttpSession, and so on. This makes it easy to unit test the likes of a servlet, you just inject mocks into the e.g. doGet() method.
Even if you don't use Spring itself on the server, you can still use the mock from the library, just for your tests.
You can use HttpClient to simplify testing somewhat. Take a look at the following article:
http://roberthanson.blogspot.com/2007/12/testing-servlets-with-junit.html
That in combination with servlet tester should give you what you want unit test wise.