How to aggregate JAX-RS responses from multiple services - java

We have a user dashboard which is displayed after login. The dashboard is composed of multiple widgets.
Each widget pulls content from separate restful service.
for eg : /news /mails /questions /alerts .
Each widget calls the service after it is loaded on the page. This way there are multiple webservice calls.
Is there a way to reduce multiple calls.
The way it should work is when the page is loaded first time the service should return aggregated data for all the widgets in single call.
Each service should also be available independently so that it can be used for refreshing a single widget, and for other system integration.
Note :A widget is this case is any javascript portlet which can consume json data from restful service.
All services are within a single web-application.
How can we aggregate the responses from multiple services and combine into a single JSON?

If you can add your own JAX-RS service simply add a new service that calls each of the others and creates the aggregated response.
for instance:
GET http://myservice.com/rest/aggregate?service=news&service=mails&service=questions
The url prefix for the serivce could be supplied as a separate encoded parameter, or provided within the aggregation service.
If all of these run within the same server just use the existing API for the other services to create the aggregated response instead.

Remember that json services are just methods, so to elaborate on #Vengard's answer (please accept that one as it was earlier) you cou(ld create a aggregate method which would look something like this:
#Path ("15218462")
class Test {
#Path ("aggregate")
public Map<String, Object> aggregate(#QueryParam("service") List<String> services) {
Map<String, Object> result = new HashMap<>();
for (String serviceName : services) {
if(serviceName.equals("mails") {
result.put("mails", mails());
}
// ... etc
}
}
#Path
public List<String> mails() {
// .... processing code ...
}
}
If the services are not under your control and you don't mind being dependent on 3rd parties you might want to check out something like Yahoo pipes (http://pipes.yahoo.com/pipes/)

Related

Jersey 1.0 JAX RS: How to transform uri string paths into REST method calls?

I'm fairly new to Jersey JAX-RS, so please bear with me. We're trying to add batch processing capabilities to our REST API by having the client submit a JSON list of uri paths that it would typically have made individually. For example:
[{"/rest/shoes/1"} , {"/rest/shirts/24"} , {"/rest/costume?color=green"}]
Again, each string in this list would be paths (or subpaths) in the REST api.
This list would be submitted to a single path, say "/rest/queries", which would correspond to a method public List<Response> queries(List<String>) . The idea is to execute the corresponding methods for each path in the list given. Is there a way to do that on Jersey 1.0 JAX-RS? Or, alternatively, is there a way to configure JAX-RS that it would just automatically do batch GET requests?
Our goal is to have the batch request that contain several GET requests that can be entirely different from each other, similar to my example above.

Jersey web service proxy

I am trying to implement a web service that proxies another service that I want to hide from external users of the API. Basically I want to play the middle man to have ability to add functionality to the hidden api which is solr.
I have to following code:
#POST
#Path("/update/{collection}")
public Response update(#PathParam("collection") String collection,
#Context Request request) {
//extract URL params
//update URL to target internal web service
//put body from incoming request to outgoing request
//send request and relay response back to original requestor
}
I know that I need to rewrite the URL to point to the internally available service adding the parameters coming from either the URL or the body.
This is where I am confused how can I access the original request body and pass it to the internal web service without having to unmarshall the content? Request object does not seem to give me the methods to performs those actions.
I am looking for Objects I should be using with potential methods that would help me. I would also like to get some documentation if someone knows any I have not really found anything targeting similar or portable behaviour.
Per section 4.2.4 of the JSR-311 spec, all JAX-RS implementations must provide access to the request body as byte[], String, or InputStream.
You can use UriInfo to get information on the query parameters. It would look something like this:
#POST
#Path("/update/{collection}")
public Response update(#PathParam("collection") String collection, #Context UriInfo info, InputStream inputStream)
{
String fullPath = info.getAbsolutePath().toASCIIString();
System.out.println("full request path: " + fullPath);
// query params are also available from a map. query params can be repeated,
// so the Map values are actually Lists. getFirst is a convenience method
// to get the value of the first occurrence of a given query param
String foo = info.getQueryParameters().getFirst("bar");
// do the rewrite...
String newURL = SomeOtherClass.rewrite(fullPath);
// the InputStream will have the body of the request. use your favorite
// HTTP client to make the request to Solr.
String solrResponse = SomeHttpLibrary.post(newURL, inputStream);
// send the response back to the client
return Response.ok(solrResponse).build();
One other thought. It looks like you're simply rewriting the requests and passing through to Solr. There are a few others ways that you could do this.
If you happen to have a web server in front of your Java app server or Servlet container, you could potentially accomplish your task without writing any Java code. Unless the rewrite conditions were extremely complex, my personal preference would be to try doing this with Apache mod_proxy and mod_rewrite.
There are also libraries for Java available that will rewrite URLs after they hit the app server but before they reach your code. For instance, https://code.google.com/p/urlrewritefilter/. With something like that, you'd only need to write a very simple method that invoked Solr because the URL would be rewritten before it hits your REST resource. For the record, I haven't actually tried using that particular library with Jersey.
1/ for the question of the gateway taht will hide the database or index, I would rather use and endpoint that is configured with #Path({regex}) (instead of rebuilding a regexp analyser in your endpoint) .
Use this regex directly in the #path, this is a good practice.
Please take a look at another post that is close to this : #Path and regular expression (Jersey/REST)
for exemple you can have regexp like this one :
#Path("/user/{name : [a-zA-Z][a-zA-Z_0-9]}")
2/ Second point in order to process all the request from one endpoint, you will need to have a dynamic parameter. I would use a MultivaluedMap that gives you the possibility to add params to the request without modifying your endpoint :
#POST
#Path("/search")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces({"application/json"})
public Response search( MultivaluedMap<String, String> params ) {
// perform search operations
return search( params);
}
3/ My 3rd advice is Reuse : make economy and economy make fewer bugs.
it's such a pitty to rewrite a rest api in order to perform solr search. You can hide the params and the endpoint, but could be great to keep the solr uri Rest formatting of the params in order to reuse all the search logic of solr directly in your api. This will make you perform a great economy in code even if you hide your solr instance behind you REST GATEWAY SERVER.
in this case you can imagine :
1. receive a query in search gateway endpoint
2. Transform the query to add your params, controls...
3. execute the REST query on solr (behind your gateway).

GWT RequestFactory client scenarios

My understanding is that the GWT RequestFactory (RF) API is for building data-oriented services whereby a client-side entity can communicate directly with it's server-side DAO.
My understanding is that when you fire a RF method from the client-side, a RequestFactoryServlet living on the server is what first receives the request. This servlet acts like a DispatchServlet and routes the request on to the correct service, which is tied to a single entity (model) in the data store.
I'm used to writing servlets that might pass the request on to some business logic (like an EJB), and then compute some response to send back. This might be a JSP view, some complicated JSON (Jackson) object, or anything else.
In all the RF examples, I see no such existence of these servlets, and I'm wondering if they even exist in GWT-RF land. If the RequestFactoryServlet is automagically routing requests to the correct DAO and method, and the DAO method is what is returned in the response, then I can see a scenario where GWT RF doesn't even utilize traditional servlets. (1) Is this the case?
Regardless, there are times in my GWT application where I want to hit a specific url, such as http://www.example.com?foo=bar. (2) Can I use RF for this, and if so, how?
I think if I could see two specific examples, side-by-side of GWT RF in action, I'd be able to connect all the dots:
Scenario #1 : I have a Person entity with methods like isHappy(), isSad(), etc. that would require interaction with a server-side DAO; and
Scenario #2 : I want to fire an HTTP request to http://www.example.com?foo=bar and manually inspect the HTTP response
If it's possible to accomplish both with the RF API, that would be my first preference. If the latter scenario can't be accomplished with RF, then please explain why and what is the GWT-preferred alternative. Thanks in advance!
1.- Request factory not only works for Entities but Services, so you could define any service in server-side with methods which you call from client. Of course when you use RF services they are able to deal with certain types (primitive, boxed primitives, sets, lists and RF proxies)
#Service(value=RfService.class, locator=RfServiceLocator.class)
public interface TwService extends RequestContext {
Request<String> parse(String value);
}
public class RfService {
public String parse(String value) {
return value.replace("a", "b");
}
2.- RF is not thought to receive other message payloads than the RF servlet produces, and the most you can do in client side with RF is ask for that services hosted in a different site (when you deploy your server and client sides in different hosts).
You can use other mechanisms in gwt world to get data from other urls, take a look to gwtquery Ajax and data-binding or this article

How can I unit test a servlet with a request that just consists of xml content

I'm trying to unit test a java WFS web service implementation. The service can accept requests containing KVP params such as:
http://www.someserver.com/wfs&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=InWaterA_1M
or it can also accept a request containing an XML fragment such as
<?xml version="1.0" ?>
<GetFeature version="1.1.0" service="WFS" maxFeatures="10000"
xmlns="http://www.opengis.net/wfs"
xmlns:myns="http://www.someserver.com/myns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs ../wfs/1.1.0/WFS.xsd">
<Query typeName="myns:InWaterA_1M"/>
</GetFeature>
I'm testing the KVP way using ServletUnit, which is straight forward:
ServletUnitClient sc = servletRunner.newClient();
WebRequest request = new PostMethodWebRequest( "http://www.someserver.com/wfs
request.setParameter( "SERVICE", "WFS );
...
request.setParameter( "TYPENAME" "InWaterA_1M" );
sc.getResponse( request);
I can't figure out how to create a corresponding request for the XML type of request though. Any ideas? I'd rather not have to use another testing framework library unless absolutely necessary.
You can create a do the following:
Create a XML of the request you want..
Create a MockHttpServletRequest
API: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/mock/web/MockHttpServletRequest.html
Call setContent(xml); and setContentType("text/xml");
Call your servlet method directly. e.g. someServlet(mockReq,mockRes);
This way there is no need to fire up the servlet container while jUnit testing...
From a quick look at the docs, it seems that ServletUnitClient can support POST requests, as well as GET requests with KVP style arguments, like you are using now: http://httpunit.sourceforge.net/doc/tutorial/task1editor-form.html
Request with XML works like posting an HTML form, only that you don't necessarily have the HTML UI in front of it.
However, I would probably break out the unit testing of the XML parsing to a separate test, and not test it explicitly through the servlet. The servlet is acting as an HTTP frontend for the XML parsing and other parts of the WFS service, and you should unit test those parts separately (perhaps you're already doing that, disregard this part in that case).
In my experience, testing the HTTP/frontend of a service is usually the least important part, the logic behind it is much more likely to break, and therefore more important to test. Also, testing the service logic separately from the frontend often forces you to use a better design.
Of course, if you have to the time, or the frontend itself involves a lot of logic, you should unit test that part as well.

JAXWS and sessions

I'm fairly new to writing web services. I'm working on a SOAP service using JAXWS. I'd like to be able to have users log-in and in my service know which user is issuing a command. In other words, have some session handling.
One way I've seen to do this is to use cookies and access the HTTP layer from my web service. However, this puts a dependency on using HTTP as the transport layer (I'm aware HTTP is almost always the transport layer but I'm a purist).
Is there a better approach which keeps the service layer unaware of the transport layer? Is there some way I can accomplish this with servlet filters? I'd like the answer to be as framework agnostic as possible.
I'm working on a SOAP service using JAXWS. I'd like to be able to have users log-in and in my service know which user is issuing a command. In other words, have some session handling.
Conventional Web services are stateless in nature, there is no session handling in web services (which has by the say nothing to do with identifying the caller).
If you want to require your users to be authenticated to call a service, the traditional approach is to:
Expose an "authentication" web service (passing user credentials) that returns an authentication token.
Have the users call this authentication first.
Have the users pass the token in a custom header on subsequent calls of "business" web services.
On the server side:
Reject any call that doesn't contain a valid token.
Invalidate tokens after some time of inactivity
You can implement a custom solution for this approach (this is a highly interoperable solution). Or you can use WS-Security/UsernameTokens that provides something similar out of the box. WS-Security is a standard (Metro implements it), it isn't "framework" specific.
As you mention, servlet filters can provide the basis of solution. Use a filter to store the current session details (e.g. the session context Map) in a threadLocal storage. This is implemented as your application class, so is transport agnostic. Your service simply uses a static method to fetch the current context, unaware of where it came from.
E.g.
class ServiceSessionContext
{
static ThreadLocal<Map> local = new ThreadLocal<Map>();
// context set by the transport layer, e.g. servlet filter
static public void setContext(Map map)
{
local.put(map);
}
// called when request is complete
static public void clearContext()
{
local.put(null);
}
// context fetched by the service
static public Map getContext()
{
return local.get();
}
}

Categories