How to implement one-way operation in Web Services (using Java or Spring annotations)?
I have tried to add one way as given below
#WebService
public interface DanduServices {
#Oneway
public void saveDanduInformation(#WebParam(name = "serv") ServDTO Serv, #WebParam(name = "dandu") DanduDTO danduDto);
but it is still request-response not asynchronus or one way.
Could anyone suggest to make a operation one-way in service endpoint and let other operations behave as per request-response?
You need to think in terms of the protocol as well though. In HTTP when you send a request you wait for a response, if no response comes back after an amount of time then you will receive a time-out error. So when you talk about one-way (you should rather say async request maybe) you really need to specify exactly what you mean. Do you want to have confirmation that your message was received i.e. have the server respond back with an OK status code and go off and complete it's task but you not wait for the task to be completed? Then you would need to spawn another thread. Spring has AOP for this the same way it has for transactions with #Transactional. Instead you annotated your method with #Async and return a Future<Something>. You'll also need #EnableAsync in your config. Refer to this article for an example Hot To Do #Async
If you don't even care about if the server received your request you don't want to use TCP/HTTP but instead UDP which is used in VOIP (phone over internet) for instance and is quicker, but it will depend on your client.
Related
we have a larger multi service java spring app that declares about 100 exchanges and queues in RabbitMQ on startup. Some are declared explicitly via Beans, but most of them are declared implicitly via #RabbitListener Annotations.
#Component
#RabbitListener(
bindings = #QueueBinding(key = {"example.routingkey"},
exchange = #Exchange(value = "example.exchange", type = ExchangeTypes.TOPIC),
value = #Queue(name = "example_queue", autoDelete = "true", exclusive = "true")))
public class ExampleListener{
#RabbitHandler
public void handleRequest(final ExampleRequest request) {
System.out.println("got request!");
}
There are quite a lot of these listeners in the whole application.
The services of the application sometimes talk to each other via RabbitMq, so take a example Publisher that publishes a message to the Example Exchange that the above ExampleListener is bound to.
If that publish happens too early in the application lifecycle (but AFTER all the Spring Lifecycle Events are through, so after ApplicationReadyEvent, ContextStartedEvent), the binding of the Example Queue to the Example Exchange has not yet happend and the very first publish and reply chain will fail. In other words, the above Example Listener would not print "got request".
We "fixed" this problem by simply waiting 3 seconds before we start sending any RabbitMq messages to give it time to declare all queues,exchanges and bindings but this seems like a very suboptimal solution.
Does anyone else have some advice on how to fix this problem? It is quite hard to recreate as I would guess that it only occurs with a large amount of queues/exchanges/bindings that RabbitMq can not create fast enough. Forcing Spring to synchronize this creation process and wait for a confirmation by RabbitMq would probably fix this but as I see it, there is no built in way to do this.
Are you using multiple connection factories?
Or are you setting usePublisherConnection on the RabbitTemplate? (which is recommended, especially for a complex application like yours).
Normally, a single connection is used and all users of it will block until the admin has declared all the elements (it is run as a connection listener).
If the template is using a different connection factory, it will not block because a different connection is used.
If that is the case, and you are using the CachingConnectionFactory, you can call createConnection().close() on the consumer connection factory during initialization, before sending any messages. That call will block until all the declarations are done.
I have a REST service defined in Spring Boot, which exposes a synchronous REST API, to be invoked by a user from a Web based UI. The service is expected to provide a real time response.
The service talks to an external endpoint in an asynchronous fashion. That is:
- A single one - way outbound message for the request
- A single one - way inbound message for the response
How can I combine the two messages to provide an impression of a synchronous behavior? I am thinking of a few approaches like:
The Rest Service posts a request to the endpoint. Once the endpoint responds, the response is added to a ConcurrentHashMap. The Rest Service queries the HashMap every few milliseconds and once it finds the right response it exits with a valid HTTP reason code.
It is akin to polling and I am thinking if we can avoid that.
The Rest Service posts a request to the endpoint. Once the endpoint responds, the waiting thread in the Rest Service is notified. However the waiting thread should conclude only if the right response is received (i.e. matching correlation Ids etc.)
Is this possible?
I realize that this is similar to a JMS Queue Request Response scenario, where each JMS queue request opens up a listener on the response queue with a message selector criteria.
However in this case I have to implement this using HTTP.
Any thoughts on this are welcome. I am fully convinced I am missing something very basic, but am not sure what.
Thanks a lot!
UPDATE: I upgraded the code to Java 8 without too much of a hassle. So I would like answers tied to Spring 4/Java 8.
I am working on a task to fix performance issues (Tomcat max thread count of 200 reached at a request rate of just 400/s, request latencies building up periodically, etc) in a Tomcat/Spring 4.2.4/Java 8 web mvc application.
It is a typical web application which looks up Mysql via Hibernate for small but frequent things like user info per request, then does actual data POST/GET to another web service via RestTemplate.
The code is in Java 7 style as I just migrated to Java 8, but no new code has been written in that style yet. (I am also back using Spring after ages, so not sure what would be best).
As expected in a normal such application, the Service layer calls other services for info, and then also passes that along to a call to the DAO. So I have some dependent callbacks here.
Setup
#EnableAsync is set
The flow of our Http requests goes from Controller -> Service -> DAO -> REST or Hibernate
Sample flow
Say Controller receives POST request R and expects a DeferredResult
Controller calls entityXService.save()
EntityXService calls userService.findUser(id)
UserService calls UserDAO.findUser(id) which in turn talks to Hibernate
UserService returns a Spring ListenableFuture to the caller
EntityXService awaits the user info (using callback) in and calls EntityXDAO.save(user, R)
EntityXDAO calls AsyncRestTemplate.postForEntity(user, R)
EntityXDAO receives DeferredResult> which is our data abstraction for the response.
EntityXDAO processes the response and converts to EntityXDTO
Eventually somehow the DeferredResult is sent back through the same chain as a response.
I am getting lost at how in step 3, EntityXService asynchronously calls UserService.findUser(id) with an onSuccess callback to EntityXDAO.save(user, R). However, EntityXDAO.save(user, R) also now returns a DeferredResult from the AsyncRestTemplate.
Questions:
Is using DeferredResult a good way to get concurrency going in this application?
Is using Guava's ListenableFuture or Java 8 CompletableFuture going to help make it better in anyway, rather than using DeferredResult?
My BIGGEST question and confusion is how to arrange the DeferredResult from one service lookup to be used by another, and then finally set a DeferredResult of a completely different return type for the final response?
Is there an example of how to chain such callbacks and what is the recommended way to build such a flow? If this sounds completely wrong, is Java 7 going to be the right choice for this?
Thanks in advance!
I am using CometD and I have a service setup (Java on the server side) as follows:
http://localhost:8086/service/myService/get-player-details?params={id:1234}
This works fine in practice but what concerns me is that any user can query my service using the above URL and retrieve another players details.
What would be the suggested way of guarding against such an issue? Would authorizers be the correct approach?
If the URL you posted is a mapped to CometD, then I strongly discourage you to use those kind of URLs to pass information such as params in the URL.
First, this will not work if you use other transports that are not HTTP, such as WebSocket.
Second, as you note that URL may expose information that you don't want to expose.
I recommend that you change the way you retrieve information from the server to not use URLs but only messages.
If all your communication with the server happens via messages, CometD on the server already validates that the message comes from a client that was allowed to handshake. You just need to enforce the right authentication checks at handshake time using a SecurityPolicy as explained the in authentication section.
The messages will have this form, using the CometD JavaScript client library:
cometd.publish("/service/player", { action:"get", playerId: 1234 });
There may be variations of this pattern where you want to put the "action" into the channel itself, for example:
cometd.publish("/service/player/get", { playerId: 1234 });
In this way, you have more little services (each responding to a different channel and therefore to a different action), which may be desirable.
Reading the examples of the services section may give you additional information.
I don't recommend to put the playerId into the channel for two reasons:
to avoid to create too many channels
to have this information promptly available in the code, so you don't need to parse the channel (although CometD support use of parameters in channels); parsing is more costly than just doing message.get("playerId").
To send the response to the client, the server can just call:
#Service
public class GetPlayer
{
#Session
private LocalSession sender;
#Listener("/service/player/get")
public void perform(ServerSession session, ServerMessage message)
{
Map<String, Object> player = retrievePlayerInfo(message.get("playerId"));
session.deliver(sender, message.getChannel(), player);
}
}
Note usage of ServerSession.deliver() to return the response to that specific client.
What above guarantees you (with a proper SecurityPolicy) that only authenticated clients can send and receive messages.
What you need to do now is to put in place the right authorizations, in particular that player 123 cannot play as player 789 by hacking the CometD messages that it sends.
This is the job for Authorizers, see the section and the examples in the Authorizers documentation.
What you must do is to establish a relation between the user that authenticated with the playerIds that she's allowed to see. That is application specific and it's the core of your Authorizer implementation.
With proper SecurityPolicy and Authorizers in place, your application is safe from the concerns of your question.
Strictly speaking, Authorizers may be enough, but typically if you want an authorization policy to be enforced, you also need authentication, which is provided by the SecurityPolicy.
I've seen a number of Atmosphere examples including pub-sub. I want to do something like pub-sub (client subscribes to a channel that is unique to that client; server periodically publishes to that channel), except that the client will send data to the server as well. The client will send data in response to data sent by the server and in other cases when something important happens on the client that the server needs to know about (which the server doesn't need to acknowledge).
Is it even possible to do this with Atmosphere?
It might look something like this:
#Stateless
#Path("/id/{clientId}/key/{clientKey}")
public class MyService {
#POST
#Produces("application/xml")
#Consumes("application/xml")
#Suspend
public StreamingOutput subscribe(#PathParam("clientId") String clientId,
#PathParam("clientKey") String clientKey,
#Context Broadcaster broadcaster,
InputStream body) {
if (!authenticate(clientId, clientKey) {
throw new WebApplicationException(401);
}
broadcaster.setID(clientId);
// Do something here... Not sure what
}
}
But there are a couple of problems here:
The incoming connection will suspend, so it won't be able to send anything to the server except when resumed via broadcast;
Any usage of the InputStream will result in blocking I/O, which kind of defeats the purpose of using Atmosphere.
Both of these problems could be solved simply by removing #Suspend, but then I'm in the thread-per-connection situation.
I get the feeling that Atmosphere isn't going to be the appropriate technology here and perhaps I might have to do something a bit lower level. But I'm not sure how to go about it. Ideas?
Edit:
I can't find a straightforward way of parsing XML asynchronously anyway, so this whole thing is looking less like something that can be done asynchronously.
Just broadcast a Callable to execute your asynchronous XML parsing. Take a look at this sample:
TwitterFeed