I have a problem with my REST webservice I want to run asynchronously. The example shows, what I want to do. The main problem is that the web service is not accepting a new request until the old finished. I am using Wildfly 10 as my application server and its RESTeasy implementation.
WebApplication.java
#ApplicationPath("rest")
public class WebApplication extends Application
{
public WebApplication ()
{
super();
}
}
TestService.java
#Path("test")
public class TestService
{
#Inject
private TestBean bean;
#GET
#Produces(MediaType.APPLICATION_JSON)
public void getDateTime(#Suspended final AsyncResponse response)
{
CompletableFuture.supplyAsync(() -> response.resume(bean.getResult()))
.exceptionally((ex) -> (response.resume(ex)));
}
}
TestBean.java
#Stateless
public class TestBean
{
public TestTO getResult()
{
Logger.getLogger(Thread.currentThread().getName()).log(Level.INFO, "Entering REST service");
for (long l = 0; l < Long.MAX_VALUE; l++)
{
// just for simulating a veeeery heavy operation
}
return new TestTO();
}
}
The TestTO is just a simple POJO, so nothing special in there. I cant imagine whats wrong. I searched in google to have a look at different approaches but nothing worked. Something I tried, too, just for testing:
I placed the loop after the response.resume() call and a new request was accepted without leaving the previous one (used simple logging statements to debug).
So... What is blocking a second request? I really dont get it, or am I missing something ridiculous?
Thanks in advance!
Okay, I figured it out.
I didn't write a client appliation which performs the requests simultaneous, instead I used Firefox to quickly see the output. I opened 2 tabs and called the URL for the webservice. Later I did exactly the same with Microsoft Edge and ... its working! The exmaple is working to 100%.
I dont know why... maybe because Edge is spawning a complete new process per tab and Firefoy doesnt? Never mind, next time I use SoupUI to test webservices.
I am sorry for the stupid question. If I had worked correctly, I had seen the issue.
Related
Problem
Very short: I want to create Spring Shell, but as a web application.
I want to create a web-application (preferably using Spring Boot), where the frontend (ReactJS) looks like a terminal (or shell), and the backend processes inputted commands. Look at https://codepen.io/AndrewBarfield/pen/qEqWMq. I want to build a full web app for something that looks like that.
I want to build a framework, so that I can develop backend commands without knowing anything about the frontend/web application structure. I basically want to instantiate a "Terminal" object, where I give some kind of input-stream and output-stream. This way I can program this Terminal based on my given interfaces and structure, without the need of setting up all kind of front-end stuff.
A good summary of the question would be: how to send all keyboard inputs to the backend, and how to send all output to the frontend?
The reason I want to create a web application, is because I want it to be available online.
What I tried
I think the way of reaching this is using websockets. I have created a small web application using this (https://developer.okta.com/blog/2018/09/25/spring-webflux-websockets-react) tutorial, without the security part. The websocket part is almost suitable, I just cannot get an "input" and "output" stream-like object.
#Controller
public class WebSocketController {
private SimpMessagingTemplate simpMessagingTemplate;
#Autowired
public WebSocketController(SimpMessagingTemplate simpMessagingTemplate) {
this.simpMessagingTemplate = simpMessagingTemplate;
}
#MessageMapping("/queue")
#SendToUser("/topic/greetings")
public Greeting greeting(HelloMessage message, #Header(name = "simpSessionId") String sessionId) throws Exception {
System.out.println(sessionId);
// Do some command parsing or whatever.
String output = "You inputted:" + HtmlUtils.htmlEscape(message.getName());
return new Greeting(output);
}
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
return headerAccessor.getMessageHeaders();
}
Now with this code, you can parse a command. However, it doesn't keep any "state". I don't know how it works with states and websockets.
I saw you had this Spring Sessions + WebSockets (https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-websocket.html), but this is not really what I want.
I can send a message from the backend to the frontend by using this code:
simpMessagingTemplate.convertAndSendToUser(sessionId, "/topic/greetings", "hey", createHeaders(sessionId));
However, I want my terminal to be able to wait for input commands from the user. Seems like a stretch, but does anybody know how to achieve this?
What I sort of want
I basically want other people to program to this interface:
public interface ITerminal {
void setInputStream(Object someKindOfWrapperForTheInput);
void setOutputStream(Object someWrapperOfSimpMessagingTemplate);
void start();
}
When somebody opens the web application, they get a dedicated terminal object (so a single connection per user). Whever somebody enters a command in the frontend application, I want it to be received by the terminal object, processed, and response outputted to the frontend.
Reasons for doing this
I really like creating command-line applications, and I don't like building frontend stuff. I work as a software engineer for a company where we build a web application, where I mostly program backend stuff. All the frontend part is done by other people (lucky for me!). However, I like doing some projects at home, and this seemed cool.
If you have any thoughts or ideas on how to approach this, just give an answer! I am interested in the solution, using the SpringBoot framework is not a requirement. I ask this question using Spring Boot and ReactJS, because I have already built applications with that. A lot has been figured out already, and I think this probably exists as well.
The only requirement is that I can achieve this with Java on a tomcat-server. The rest is optional :)
Unclear?
I tried my best to make my story clear, but I am not sure if my purpose of what I want to achieve is clear. However, I don't know how to formulate it in such a way you understand. If you have any suggestions or questions, dont hesitate to comment!
If the only thing you want is a Live Spring shell that shows up in the browser it's fairly simple, all you need is to expose a standard WebSocket via the WebSocketConfigurer, then add a WebSocketHandler that executes the command and then returns the resulting String as a TextMessage.
Firstly the Socket configuration that allows clients to connect to the 'cli' endpoint
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(cliHandler(), "/cli").setAllowedOrigins("*");
}
#Bean
public CLIWebSocketHandler cliHandler() {
return new CLIWebSocketHandler();
}
}
Then the WebSocketHandler that executes the command. I recommend that for every #ShellMethod you specify the return type as String, don't use logging or System writes as they won't be returned during the evaluation.
#Component
public class CLIWebSocketHandler extends TextWebSocketHandler {
#Autowired
private Shell shell;
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String result = shell.evaluate(() -> message.getPayload()).toString();
session.sendMessage(new TextMessage(result));
}
}
You can use an extension like Simple WebSocket Client to test it, by going to ws://localhost:port/cli
This is the most basic solution, adding features like security should be easy after this. Notice that I don't use STOMP, because you probably want to isolate users. But it can work alongside STOMP based endpoints, so you can have pub-sub functionality for other parts of the project.
From the question I sense that answer you'd like is something that involved Input and OutputStreams. You could possibly look into redirecting the output of Spring Shell to a different stream then have them forwarded to the sessions but it's probably much more complicated and has other trade-offs. It's simpler to just return a String as the result, it looks better in print outs anyway.
So, I am just getting into WebClient since RestTemplate got a deprecated note.
Things is, I am a bit lost when it comes to requesting and consuming the responses.
At the moment, I am playing around with the Riot Games API for League of Legends. If you check their documentation, you need to send a API key either as a param or a header to consume their services.
As I am trying the WebClient, I am not worrying about abstraction right now, so the current test I have is:
A Builder class, right now I only set the baseUrl and api key:
#Service
public class WebClientService {
#Autowired
private Environment env;
public WebClient get(String url) {
return WebClient.builder()
.baseUrl(url)
.defaultHeader("X-Riot-Token", env.getProperty("app.riot.api.key"))
.build();
}
}
To test, I am making a call to the /summoners endpoint using the below code:
#Service
public class SummonerServices {
#Autowired
private WebClientService web;
private String riotEndPoint = "https://br1.api.riotgames.com/lol/summoner/v4/summoners/by-name/";
public Flux<Summoners> getSummoner(String summonerName) {
return web.get(riotEndPoint + summonerName).get()
.exchange().flatMapMany(e -> e.bodyToMono(Summoners.class));
}
}
I have a controller (omitted because it's not relevant), I call it, and it gets the result as expected.
But I noticed that instead of a Flux, I can use a Mono like this:
public Mono<Summoners> getSummoner(String summonerName) {
return web.get(riotEndPoint + summonerName).get()
.exchange().flatMap(e -> e.bodyToMono(Summoners.class));
}
What I am failing to understand, by reading the docs and looking at examples on the internet, is when or why to choose one over another?
It seems that for both I can have access to the header response, I have access to the same doOnSucess / doOnError and others methods to treat responses and errors.
They seems pretty much the same, but I they wouldn't just create two exact ways to do the same thing with different names, right? So if anyone could point me to a doc explaining Fux and Mono I would be very glad. Google returned to me pretty much the same tutorials, and they don't explain, they just make use of them.
The question might seem stupid/trivial and might be, but I simply cannot understand how to achieve my goal. (Sorry if the title is misguiding, couldn't think of a better one)
I have a webpage on a App Engine server which uses GWT. I got client code and server code. The client code can call RPC methods without any problem (my problem has nothing to do with the "gwt-client" at all).
I got the following classes:
//MyClassService.java - client package
#RemoteServiceRelativePath("myService")
public interface MyClassService extends RemoteService{
public doSomething();
}
//MyClassServiceAsync.java - client package
public interface MyClassServiceAsync{
public void doSomething(AsyncCallback<Void> callback);
}
//MyClassServiceImpl.java - server package
public class MyClassServiceImpl extends RemoteServiceServlet implements MyClassService{
#Override
public void doSomething()
{
//does something
}
}
A scenario and what I want to do:
I've got a remote client, in other words, a client who's not connecting through the page via the "GWT-interface", it's a client who's simply making GET, POST requests to a path on the server (from elsewhere). This remote client is not "using" GWT at all. The client is connecting through an HttpServlet, inside this servlet I want to reuse the RPC mechanics so that i don't have to rewrite the interfaces, who are on the client side and using client-dependent code (the implementation is already server-side).
To reuse the existing methods on the server-side I could create an instance of MyClassServiceImpl.java and just use those. BUT as you can see above, they are implemented as synchronous methods, since GWT-RPC automatically makes the calls asyncronous when using the GWT-RPC.
How would i go about to reuse the MyClassServiceImpl on the server-side and also get them as asynchronous?
Also if I'm wrong with the approach I'm taking, please suggest some other solution. For example, one solution might be for the remote client to directly communicate with the RemoteServiceServlet instead of creating a HttpServlet which the client connects through, but I don't know if that's possible (and if it is, please tell me how)!
Thank you!
EDIT (thanks to some answers below I got some insight and will try to improve my question):
The server-side implementation of the methods is SYNCHRONOUS. Meaning they will block until results a returned. When invoking these method from the gwt-client code, they are 'automatically' made ASYNCHRONOUS one can call them by doing the following:
MyClassServiceAsync = (MyClassServiceAsync) GWT.create(MyClassService.class);
ServiceDefTarget serviceDef = (ServiceDefTarget) service;
serviceDef.setServiceEntryPoint(GWT.getModuleBaseURL() + "myService");
service.doSomething(new AsyncCallback<Void>() {
#Override
public void onSuccess(Void result) {
//do something when we know server has finished doing stuff
}
#Override
public void onFailure(Throwable caught) {
}
});
As you can see from the above code, there is support for the doSomething method to take an AsyncCallback, without even having the implementation for it. This is what I wanted on the server-side so i didn't have to use threads or create a new implementation for "async-usage". Sorry if I was unclear!
1) Any client can call MyClassServiceImpl.doSomething() with the current configuration. MyClassServiceImpl is a servlet and properly exposed. In order to achieve communication this way, the client must be able to "speak" the GWT dialect for data transportation. Google may provide you with libraries implementing this. I haven't used any, so I cannot make suggestions.
An example, proof-of-concept setup: Check the network communications with Firebug to get an idea of what is going on. Then try calling the service with curl.
2) If you do not want to use the GWT dialect, you can easily expose the same service as REST (JSON) or web services (SOAP). There are plenty of libraries, e.g. for the REST case RestEasy and Jersey. You do not mention any server-side frameworks (Spring? Guice? CDI?), so the example will be simplistic.
I'd suggest implementing your business method in a class independent of transportation method:
public class MyBusinessLogic {
public void doSomething() {
...
}
}
Then, the transport implementations use this business logic class, adding only transport-specific stuff (e.g. annotations):
GWT:
public class MyClassServiceImpl extends RemoteServiceServlet implements MyClassService{
#Override
public void doSomething() {
MyBusinessLogic bean = ... // get it from IoC, new, whatever
bean.doSomething();
}
}
JAX-RS:
#Path("myService")
public class MyResource {
#GET
public void doSomething() {
MyBusinessLogic bean = ... // get it from IoC, new, whatever
bean.doSomething();
}
}
So the transport endpoints are just shells for the real functionality, implemented in one place, the class MyBusinessLogic.
Is this a real example? Your method takes no arguments and returns no data.
Anyhow you can create a new servlet and invoke it via normal HTTP request. The servlet then just invokes the target method:
public class MyNewServlet extends HttpServlet{
protected void doGet(HttpServletRequest request, HttpServletResponse response){
MyBusinessLogic bean = ... // get it from IoC, new, whatever
bean.doSomething();
}
}
I have a java program that has some number of classes. Three methods taken input A and give output B. I need to make these methods available as a web service so that I can ask something like http://test.com/method?input=A and the result B is returned. I don't want to re-write my existing code. Is there something which is available such as a web service framework for JAVA that can allow me to create a web service interface for these three methods. What is the easiest way?
I have ran into many acronyms and other stuff during my research such as dynamic project, JAVA EE, Glassfish etc... What can implement my requirement? Thanks!
You will probably need some sort of web framework -- Glassfish is one example. Basically, your application is not built to receive web requests, so you need some sort of container (e.g. a Servlet Container like Tomcat http://en.wikipedia.org/wiki/Web_container ).
I think "restlet" is a little servlet container that might suit your needs.
Check it out: http://www.restlet.org/
If you're running on a Java EE 6 server, you can use JAX-RS: http://docs.oracle.com/javaee/6/tutorial/doc/gilik.html
The easiest way to do quick Java services I've found is Restlet.
You can use their tutorials to get a webserver up and running like literally 20 minutes from scratch. The Restlet below should work right out of the box as a skeleton framework. You'll replace the call of String b = ... of course, and replace it with your own library.
public class Main extends Application {
public static void main(String[] args) {
Main main = new Main();
main.start();
}
private void start() {
Component c = new Component();
c.getServers().add(Protocol.HTTP, 80);
Application app = new Main();
c.getDefaultHost().attach(app);
c.start();
}
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/method/{input}", new Restlet(getContext()) {
public void handle(Request request, Response response) {
String a = request.getAttributes().get("input").toString();
String b = MyLibraries.compute(a);
response.setEntity(b, MediaType.TEXT_HTML);
}
});
return router;
}
}
I'm completely new to the Spring framework (and most web development in general), but I'm trying to hook up some heavy Java backend code to a new Spring and JSP project. My Controller's handleRequest() is kicking off a long running worker thread before it returns my request.jsp ModelAndView object. After that I'd like to be able to still interface with this Controller from my JSP form to be able to call isThreadDone() in the Controller whenever a button in the form is clicked. Based on three different results, I then redirect accordingly. Is this possible with my current approach? This seems to violate some of the Spring MVC approach, but I can't think of a good way to do this that I can wrap my head around. If anything is way off here, please excuse my ignorance. Thanks in advance.
Take a look at the Spring #Async annotation. If you annotate a Service-layer bean with that annotation, it then runs in its own thread, allowing your Controller thread to run without interruption after calling the Service method. Have that thread is set a value held at the Class level for the Service via synchronous methods, and your Controller code can just check those toggles at will to see if the process is done or not. Something like:
#Service
public myServiceClass {
private boolean isDone = false;
public synchronized void setIsDone(boolean isDone) {
isDone = isDone;
}
public synchronized boolean getIsDone() {
return isDone;
}
#Async
public void myServiceMethod() {
...long-running stuff...
setIsDone(true);
}
In the Controller:
#Controller
class MyController {
#RequestMapping
public kickOffHandlerMethod() {
myServiceClass.myServiceMethod();
}
}
#RequestMapping
public dependentHandlerMethod() {
if(myServiceClass.getIsDone()) {
...do something...
}
}
}
If more than one request might kick off the process, then I would save each isDone toggle in a HashMap with some kind of identifier. Then the threads would update individual toggles, one for each request.
Well, anything is possible, right? Based on what you've provided, you can just keep a reference to the thread--maybe in the HttpSession--so that when a new request comes in from clicking the button, you can query it and return an appropriate response.