spring deferredresult - ajax

I am new to spring and want to implement long polling for a website to display admin message immediately when it becomes available to all clients,i searched google for hours and could only find out deferredresult(spring 3.2) can be used to implement it.my question is how i can achieve long polling with deferredresult, I would appreciate it if anyone could refer me to such a tutorial.

Another option is to use AsyncContext. This will keep the initial GET request "open" and enable you to send multiple messages as part of the response, unlike DeferredResult which allows to send only ONE response message. Here is a good-link that explains how !

Straight from the horses mouth.
You have two basic options: Option 1 is a Callable
, where the Callable returns the String view name (you may also be able to use #ResponseBody or some of the other normal Spring return types like ModelAndView, but I have never investigated that).
Option two is to return DeferredResult, which is like Callable. except you can pass that off to a separate thread and fill in the results there. Again, not sure if you can return a ModelAndView or use #ResponseBody to return XML/JSON, but I am sure you can.

Short background about DeferredResult:
Your controller is eventually a function executed by the servlet container (for that matter, let's assume that the server container is Tomcat) worker thread. Your service flow start with Tomcat and ends with Tomcat. Tomcat gets the request from the client, holds the connection, and eventually returns a response to the client. Your code (controller or servlet) is somewhere in the middle.
Consider this flow:
Tomcat get client request.
Tomcat executes your controller.
Release Tomcat thread but keep the client connection (don't return response) and run heavy processing on different thread.
When your heavy processing complete, update Tomcat with its response and return it to the client (by Tomcat).
Because the servlet (your code) and the servlet container (Tomcat) are different entities, then to allow this flow (releasing tomcat thread but keep the client connection) we need to have this support in their contract, the package javax.servlet, which introduced in Servlet 3.0 . Spring MVC use this new Servlet 3.0 capability when the return value of the controller is DeferredResult or Callable, although they are two different things. Callable is an interface that is part of java.util, and it is an improvement for the Runnable interface. DeferredResult is a class designed by Spring to allow more options (that I will describe) for asynchronous request processing in Spring MVC, and this class just holds the result (as implied by its name) while your Callable implementation holds the async code. So it means you can use both in your controller, run your async code with Callable and set the result in DeferredResult, which will be the controller return value. So what do you get by using DeferredResult as the return value instead of Callable? DeferredResult has built-in callbacks like onError, onTimeout, and onCompletion. It makes error handling very easy. In addition, as it is just the result container, you can choose any thread (or thread pool) to run on your async code. With Callable, you don't have this choice.
Here you can find a simple working examples I created with both options, Callable and DeferredResult.

Related

Can I use block() method of Flux returned from Spring5's WebClient?

I created Spring Boot 2.0 demo application which contains two applications that communicate using WebClient. And I'm suffering that they often stop communicating when I use block() method of Flux from the WebClient's response. I want to use List not Flux by some reasons.
The server side application is like this. It just returns Flux object.
#GetMapping
public Flux<Item> findAll() {
return Flux.fromIterable(items);
}
And the client side (or BFF side) application is like this. I get Flux from the server and convert it to List by calling block() method.
#GetMapping
public List<Item> findBlock() {
return webClient.get()
.retrieve()
.bodyToFlux(Item.class)
.collectList()
.block(Duration.ofSeconds(10L));
}
While it works well at first, findBlock() won't respond and timeouts after several times access. When I modify the findBlock() method to return Flux deleting collectList() and block(), it works well. Then I assume that block() method cause this problem.
And, when I modify the findAll() method to return List, nothing changes.
Source code of the entire example application is here.
https://github.com/cero-t/webclient-example
"resource" is the server application, and "front" is the client application. After running both application, when I access to localhost:8080 it works well and I can reload any times, but when I access to localhost:8080/block it seems to work well but after several reloads it won't respond.
By the way, when I add "spring-boot-starter-web" dependency to the "front" applications's (not resource application's) pom.xml, which means I use tomcat, this problem never happens. Is this problem due to Netty server?
Any guidance would be greatly appreciated.
First, let me point that using Flux.fromIterable(items) is advised only if items has been fetched from memory, no I/O involved. Otherwise chances are you'd be using a blocking API to get it - and this can break your reactive application. In this case, this is an in-memory list, so no problem. Note that you can also go Flux.just(item1, item2, item3).
Using the following is the most efficient:
#GetMapping("/")
public Flux<Item> findFlux() {
return webClient.get()
.retrieve()
.bodyToFlux(Item.class);
}
Item instances will be read/written, decoded/encoded on the fly in a very efficient way.
On the other hand, this is not the preferred way:
#GetMapping("/block")
public List<Item> findBlock() {
return webClient.get()
.retrieve()
.bodyToFlux(Item.class)
.collectList()
.block(Duration.ofSeconds(10L));
}
In this case, your front application is buffering in memory the whole items list with collectList but is also blocking one of the few server threads available. This might cause very poor performance because your server might be blocked waiting for that data and can't service other requests at the same time.
In this particular case it's worse, since the application totally breaks.
Looking at the console, we can see the following:
WARN 3075 --- [ctor-http-nio-7] io.netty.util.concurrent.DefaultPromise : An exception was thrown by reactor.ipc.netty.channel.PooledClientContextHandler$$Lambda$532/356589024.operationComplete()
reactor.core.Exceptions$BubblingException: java.lang.IllegalArgumentException: Channel [id: 0xab15f050, L:/127.0.0.1:59350 - R:localhost/127.0.0.1:8081] was not acquired from this ChannelPool
at reactor.core.Exceptions.bubble(Exceptions.java:154) ~[reactor-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
This is probably linked to a reactor-netty client connection pool issue that should be fixed in 0.7.4.RELEASE. I don't know the specifics of this, but I suspect the whole connection pool gets corrupted as HTTP responses aren't properly read from the client connections.
Adding spring-boot-starter-web does make your application use Tomcat, but it mainly turns your Spring WebFlux application into a Spring MVC application (which now supports some reactive return types, but has a different runtime model). If you wish to test your application with Tomcat, you can add spring-boot-starter-tomcat to your POM and this will use Tomcat with Spring WebFlux.

Where should i store thread dependent data within a receiving rabbitListener component in a multithreaded environment?

I'm using the annotation based approach of spring amqp in a multithreaded environment (i have multiple consumers => multiple rabbit listener containers).
#RabbitListener(queues = "tasks")
public void receiveMessage(#Payload Task task) {
// usage of httpClient here with its own httpContext (would be fine)
// this method gets called from different listenerContainers / threads
}
My component which contains the annotated receiveMessage() method needs to do some http calls with the apache http client. Since i'm working with multiple consumers at the same time, this method gets called from different threads and the apache http client documentation says that i should create a httpContext for each thread to be thread safe. Since all threads are calling the same component method i can't put the httpContext into the component.
Is there something like a listener container context for each listener container where i can put the httpClientContext? Or does somebody have an idea how to solve this easy? I thought about ThreadLocal or a central registry for httpContexts but it would be fine if this would be more easy.
There is nothing like that provided by the framework; the simplest solution is to store them in something like a LinkedBlockingQueue and check one out, use it, and put it back in the queue when you're done (creating one as necessary if the queue is empty).
ThreadLocal will work too, but I prefer to use a pool.

Spring Integration: the SecurityContext propagation

I have some perplexity about the SecurityContext propagation in Spring Integration.
Here is the point of the documentation:
http://docs.spring.io/spring-integration/reference/htmlsingle/#security-context-propagation
My perplexity are the following:
(1) To be sure that our interaction with the application is secure,
according to its security system rules, we should supply some security
context with an authentication (principal) object. The Spring
Security project provides a flexible, canonical mechanism to
authenticate our application clients over HTTP, WebSocket or SOAP
protocols (as can be done for any other integration protocol with a
simple Spring Security extension) and it provides a SecurityContext
for further authorization checks on the application objects, such as
message channels. By default, the SecurityContext is tied with the
current Thread's execution state using the
(ThreadLocalSecurityContextHolderStrategy). It is accessed by an AOP
interceptor on secured methods to check if that principal of the
invocation has sufficent permissions to call that method, for example.
This works well with the current thread, but often, processing logic
can be performed on another thread or even on several threads, or on
to some external system(s).
This means that the SecurityContext (normally) is accessible only for the current Thread. Right?
So, how to make it accessible for another thread of another application (integrated with Spring Integration) ?
(2) Standard thread-bound behavior is easy to configure if our application is built on the Spring Integration components and its
message channels. In this case, the secured objects may be any
service activator or transformer, secured with a
MethodSecurityInterceptor in their
(see Section 8.8, “Adding Behavior to Endpoints”) or even
MessageChannel (see Section D.2, “Securing channels” above). When
using DirectChannel communication, the SecurityContext is available
automatically, because the downstream flow runs on the current thread.
But in case of the QueueChannel, ExecutorChannel and
PublishSubscribeChannel with an Executor, messages are transferred
from one thread to another (or several) by the nature of those
channels. In order to support such scenarios, we can either transfer
an Authentication object within the message headers and extract and
authenticate it on the other side before secured object access.
Or, we can propagate the SecurityContext to the thread receiving the
transferred message.
This means that we have to extract the Principal manually? If yes, how?
Or it's enough to use the propagation aspect, from 4.2 version?
(3) Starting with version 4.2 SecurityContext propagation has been
introduced. It is implemented as a
SecurityContextPropagationChannelInterceptor, which can simply be
added to any MessageChannel or configured as a
#GlobalChannelInterceptor. The logic of this interceptor is based on
the SecurityContext extraction from the current thread from the
preSend() method, and its populating to another thread from the
postReceive() (beforeHandle()) method. Actually, this interceptor
is an extension of the more generic
ThreadStatePropagationChannelInterceptor, which wraps the
message-to-send together with the state-to-propagate in an internal
Message extension - MessageWithThreadState, - on one side and
extracts the original message back and state-to-propagate on another.
The ThreadStatePropagationChannelInterceptor can be extended for any
context propagation use-case and
SecurityContextPropagationChannelInterceptor is a good sample on the
matter.
"Starting with version 4.2 SecurityContext propagation has been introduced." => Ok, very well.
But: "It is implemented as a SecurityContextPropagationChannelInterceptor, which can simply be added to any MessageChannel or configured as a #GlobalChannelInterceptor."
What does it mean? I have to implement an interceptor that extends "SecurityContextPropagationChannelInterceptor" ?
What I have to "add" in my <int:channel> configuration?
And if I use <int:channel-interceptor> (the same of #GlobalChannelInterceptor), it's different from using <int:interceptors> ?
Other perplexity:
"The logic of this interceptor is based on the SecurityContext extraction from the current thread from the preSend() method, and its populating to another thread from the postReceive()
(beforeHandle()) method."
But why there are a "obtainPropagatingContext" method and a "populatePropagatedContext" method in the SecurityContextPropagationChannelInterceptor class?
Where is made the propagation? In the preSend() / postReceive() methods, or in those two methods?
Furthermore, I tried to propagate the SecurityContext to an external application, without success...
Any explanations about this argument would be appreciated.
You have a lot of questions here, but let me try to answer to them.
What does it mean? I have to implement an interceptor that extends "SecurityContextPropagationChannelInterceptor" ?
No, there is such an interceptor in the Framework out-of-the-box. What you have to do to understand how to add interceptor to MessageChannel: http://docs.spring.io/spring-integration/reference/html/messaging-channels-section.html#channel-configuration-interceptors.
Or like this:
#Bean
#GlobalChannelInterceptor(patterns = {
"#{'queueChannel'}",
"${security.channel:executorChannel}",
"publishSubscribeChannel" })
public ChannelInterceptor securityContextPropagationInterceptor() {
return new SecurityContextPropagationChannelInterceptor();
}
See their JavaDocs for more information.
But why there are a "obtainPropagatingContext" method and a "populatePropagatedContext" method in the SecurityContextPropagationChannelInterceptor class?
SecurityContextPropagationChannelInterceptor extends ThreadStatePropagationChannelInterceptor<Authentication> , where obtainPropagatingContext and populatePropagatedContext are just generic method to extract some current State in the preSend() (on Thread) and provide that State for population/manipulation in the postReceive(), which may happen in the different Thread.
Yes, SecurityContext is thread-bound in Spring Security and the logic to be sure that we can perform a secured function is fully based on the ThreadLocal variable. That's why we have to transfer it that way. The "propagation" is a process not state.
Not sure what you mean about "external application", but there is only one mechanism to do that: send credentials together with the request to that application.

Associating a user with a session after authentication in JSF [duplicate]

Suppose, I have a webserver which holds numerous servlets. For information passing among those servlets I am setting session and instance variables.
Now, if 2 or more users send request to this server then what happens to the session variables?
Will they all be common for all the users or they will be different for each user?
If they are different, then how was the server able to differentiate between different users?
One more similar question, if there are n users accessing a particular servlet, then this servlet gets instantiated only the first time the first user accessed it or does it get instantiated for all the users separately?
In other words, what happens to the instance variables?
ServletContext
When the servlet container (like Apache Tomcat) starts up, it will deploy and load all its web applications. When a web application is loaded, the servlet container creates the ServletContext once and keeps it in the server's memory. The web app's web.xml and all of included web-fragment.xml files is parsed, and each <servlet>, <filter> and <listener> found (or each class annotated with #WebServlet, #WebFilter and #WebListener respectively) will be instantiated once and be kept in the server's memory as well, registred via the ServletContext. For each instantiated filter, its init() method is invoked with a new FilterConfig argument which in turn contains the involved ServletContext.
When a Servlet has a <servlet><load-on-startup> or #WebServlet(loadOnStartup) value greater than 0, then its init() method is also invoked during startup with a new ServletConfig argument which in turn contains the involved ServletContext. Those servlets are initialized in the same order specified by that value (1 is 1st, 2 is 2nd, etc). If the same value is specified for more than one servlet, then each of those servlets is loaded in the same order as they appear in the web.xml, web-fragment.xml, or #WebServlet classloading. In the event the "load-on-startup" value is absent, the init() method will be invoked whenever the HTTP request hits that servlet for the very first time.
When the servlet container is finished with all of the above described initialization steps, then the ServletContextListener#contextInitialized() will be invoked with a ServletContextEvent argument which in turn contains the involved ServletContext. This will allow the developer the opportunity to programmatically register yet another Servlet, Filter or Listener.
When the servlet container shuts down, it unloads all web applications, invokes the destroy() method of all its initialized servlets and filters, and all Servlet, Filter and Listener instances registered via the ServletContext are trashed. Finally the ServletContextListener#contextDestroyed() will be invoked and the ServletContext itself will be trashed.
HttpServletRequest and HttpServletResponse
The servlet container is attached to a web server that listens for HTTP requests on a certain port number (port 8080 is usually used during development and port 80 in production). When a client (e.g. user with a web browser, or programmatically using URLConnection) sends an HTTP request, the servlet container creates new HttpServletRequest and HttpServletResponse objects and passes them through any defined Filter in the chain and, eventually, the Servlet instance.
In the case of filters, the doFilter() method is invoked. When the servlet container's code calls chain.doFilter(request, response), the request and response continue on to the next filter, or hit the servlet if there are no remaining filters.
In the case of servlets, the service() method is invoked. By default, this method determines which one of the doXxx() methods to invoke based off of request.getMethod(). If the determined method is absent from the servlet, then an HTTP 405 error is returned in the response.
The request object provides access to all of the information about the HTTP request, such as its URL, headers, query string and body. The response object provides the ability to control and send the HTTP response the way you want by, for instance, allowing you to set the headers and the body (usually with generated HTML content from a JSP file). When the HTTP response is committed and finished, both the request and response objects are recycled and made available for reuse.
HttpSession
When a client visits the webapp for the first time and/or the HttpSession is obtained for the first time via request.getSession(), the servlet container creates a new HttpSession object, generates a long and unique ID (which you can get by session.getId()), and stores it in the server's memory. The servlet container also sets a Cookie in the Set-Cookie header of the HTTP response with JSESSIONID as its name and the unique session ID as its value.
As per the HTTP cookie specification (a contract any decent web browser and web server must adhere to), the client (the web browser) is required to send this cookie back in subsequent requests in the Cookie header for as long as the cookie is valid (i.e. the unique ID must refer to an unexpired session and the domain and path are correct). Using your browser's built-in HTTP traffic monitor, you can verify that the cookie is valid (press F12 in Chrome / Firefox 23+ / IE9+, and check the Net/Network tab). The servlet container will check the Cookie header of every incoming HTTP request for the presence of the cookie with the name JSESSIONID and use its value (the session ID) to get the associated HttpSession from server's memory.
The HttpSession stays alive until it has been idle (i.e. not used in a request) for more than the timeout value specified in <session-timeout>, a setting in web.xml. The timeout value defaults to 30 minutes. So, when the client doesn't visit the web app for longer than the time specified, the servlet container trashes the session. Every subsequent request, even with the cookie specified, will not have access to the same session anymore; the servlet container will create a new session.
On the client side, the session cookie stays alive for as long as the browser instance is running. So, if the client closes the browser instance (all tabs/windows), then the session is trashed on the client's side. In a new browser instance, the cookie associated with the session wouldn't exist, so it would no longer be sent. This causes an entirely new HttpSession to be created, with an entirely new session cookie being used.
In a nutshell
The ServletContext lives for as long as the web app lives. It is shared among all requests in all sessions.
The HttpSession lives for as long as the client is interacting with the web app with the same browser instance, and the session hasn't timed out at the server side. It is shared among all requests in the same session.
The HttpServletRequest and HttpServletResponse live from the time the servlet receives an HTTP request from the client, until the complete response (the web page) has arrived. It is not shared elsewhere.
All Servlet, Filter and Listener instances live as long as the web app lives. They are shared among all requests in all sessions.
Any attribute that is defined in ServletContext, HttpServletRequest and HttpSession will live as long as the object in question lives. The object itself represents the "scope" in bean management frameworks such as JSF, CDI, Spring, etc. Those frameworks store their scoped beans as an attribute of its closest matching scope.
Thread Safety
That said, your major concern is possibly thread safety. You should now know that servlets and filters are shared among all requests. That's the nice thing about Java, it's multithreaded and different threads (read: HTTP requests) can make use of the same instance. It would otherwise be too expensive to recreate, init() and destroy() them for every single request.
You should also realize that you should never assign any request or session scoped data as an instance variable of a servlet or filter. It will be shared among all other requests in other sessions. That's not thread-safe! The below example illustrates this:
public class ExampleServlet extends HttpServlet {
private Object thisIsNOTThreadSafe;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object thisIsThreadSafe;
thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
}
}
See also:
What is the difference between JSF, Servlet and JSP?
Best option for Session management in Java
Difference between / and /* in servlet mapping url pattern
doGet and doPost in Servlets
Servlet seems to handle multiple concurrent browser requests synchronously
Why Servlets are not thread Safe?
Sessions
In short: the web server issues a unique identifier to each visitor on his first visit. The visitor must bring back that ID for him to be recognised next time around. This identifier also allows the server to properly segregate objects owned by one session against that of another.
Servlet Instantiation
If load-on-startup is false:
If load-on-startup is true:
Once he's on the service mode and on the groove, the same servlet will work on the requests from all other clients.
Why isn't it a good idea to have one instance per client? Think about this: Will you hire one pizza guy for every order that came? Do that and you'd be out of business in no time.
It comes with a small risk though. Remember: this single guy holds all the order information in his pocket: so if you're not cautious about thread safety on servlets, he may end up giving the wrong order to a certain client.
Session in Java servlets is the same as session in other languages such as PHP. It is unique to the user. The server can keep track of it in different ways such as cookies, url rewriting etc. This Java doc article explains it in the context of Java servlets and indicates that exactly how session is maintained is an implementation detail left to the designers of the server. The specification only stipulates that it must be maintained as unique to a user across multiple connections to the server. Check out this article from Oracle for more information about both of your questions.
Edit There is an excellent tutorial here on how to work with session inside of servlets. And here is a chapter from Sun about Java Servlets, what they are and how to use them. Between those two articles, you should be able to answer all of your questions.
When the servlet container (like Apache Tomcat) starts up, it will read from the web.xml file (only one per application) if anything goes wrong or shows up an error at container side console, otherwise, it will deploy and load all web applications by using web.xml (so named it as deployment descriptor).
During instantiation phase of the servlet, servlet instance is ready but it cannot serve the client request because it is missing with two pieces of information:
1: context information
2: initial configuration information
Servlet engine creates servletConfig interface object encapsulating the above missing information into it
servlet engine calls init() of the servlet by supplying servletConfig object references as an argument. Once init() is completely executed servlet is ready to serve the client request.
Q) In the lifetime of servlet how many times instantiation and initialization happens ??
A)only once (for every client request a new thread is created)
only one instance of the servlet serves any number of the client request ie, after serving one client request server does not die. It waits for other client requests ie what CGI (for every client request a new process is created) limitation is overcome with the servlet (internally servlet engine creates the thread).
Q)How session concept works?
A)whenever getSession() is called on HttpServletRequest object
Step 1: request object is evaluated for incoming session ID.
Step 2: if ID not available a brand new HttpSession object is created and its corresponding session ID is generated (ie of HashTable) session ID is stored into httpservlet response object and the reference of HttpSession object is returned to the servlet (doGet/doPost).
Step 3: if ID available brand new session object is not created session ID is picked up from the request object search is made in the collection of sessions by using session ID as the key.
Once the search is successful session ID is stored into HttpServletResponse and the existing session object references are returned to the doGet() or doPost() of UserDefineservlet.
Note:
1)when control leaves from servlet code to client don't forget that session object is being held by servlet container ie, the servlet engine
2)multithreading is left to servlet developers people for implementing ie., handle the multiple requests of client nothing to bother about multithread code
Inshort form:
A servlet is created when the application starts (it is deployed on the servlet container) or when it is first accessed (depending on the load-on-startup setting)
when the servlet is instantiated, the init() method of the servlet is called
then the servlet (its one and only instance) handles all requests (its service() method being called by multiple threads). That's why it is not advisable to have any synchronization in it, and you should avoid instance variables of the servlet
when the application is undeployed (the servlet container stops), the destroy() method is called.
Sessions - what Chris Thompson said.
Instantiation - a servlet is instantiated when the container receives the first request mapped to the servlet (unless the servlet is configured to load on startup with the <load-on-startup> element in web.xml). The same instance is used to serve subsequent requests.
The Servlet Specification JSR-315 clearly defines the web container behavior in the service (and doGet, doPost, doPut etc.) methods (2.3.3.1 Multithreading Issues, Page 9):
A servlet container may send concurrent requests through the service
method of the servlet. To handle the requests, the Servlet Developer
must make adequate provisions for concurrent processing with multiple
threads in the service method.
Although it is not recommended, an alternative for the Developer is to
implement the SingleThreadModel interface which requires the container
to guarantee that there is only one request thread at a time in the
service method. A servlet container may satisfy this requirement by
serializing requests on a servlet, or by maintaining a pool of servlet
instances. If the servlet is part of a Web application that has been
marked as distributable, the container may maintain a pool of servlet
instances in each JVM that the application is distributed across.
For servlets not implementing the SingleThreadModel interface, if the
service method (or methods such as doGet or doPost which are
dispatched to the service method of the HttpServlet abstract class)
has been defined with the synchronized keyword, the servlet container
cannot use the instance pool approach, but must serialize requests
through it. It is strongly recommended that Developers not synchronize
the service method (or methods dispatched to it) in these
circumstances because of detrimental effects on performance
No. Servlets are not Thread safe
This is allows accessing more than one threads at a time
if u want to make it Servlet as Thread safe ., U can go for
Implement SingleThreadInterface(i)
which is a blank Interface there is no
methods
or we can go for synchronize methods
we can make whole service method as synchronized by using synchronized
keyword in front of method
Example::
public Synchronized class service(ServletRequest request,ServletResponse response)throws ServletException,IOException
or we can the put block of the code in the Synchronized block
Example::
Synchronized(Object)
{
----Instructions-----
}
I feel that Synchronized block is better than making the whole method
Synchronized
As is clear from above explanations, by implementing the SingleThreadModel, a servlet can be assured thread-safety by the servlet container. The container implementation can do this in 2 ways:
1) Serializing requests (queuing) to a single instance - this is similar to a servlet NOT implementing SingleThreadModel BUT synchronizing the service/ doXXX methods; OR
2) Creating a pool of instances - which's a better option and a trade-off between the boot-up/initialization effort/time of the servlet as against the restrictive parameters (memory/ CPU time) of the environment hosting the servlet.

How to pass a web socket handler instance instead of class

I'm working with embedded Jetty websockets and what I see in the examples is passing the Class of the handler to the container instead of an instance. I would to know if it's possible to pass an instance instead of a class and how that works.
ServerContainer wscontainer = webSocketServerContainerInitializer.configureContext(context);
// Add WebSocket endpoint to javax.websocket layer
wscontainer.addEndpoint(EventSocket.class);
I would like to be able to do
wscontainer.addEndpoint(new EventSocket());
of course this method is not supported.
I see that on the client side you can provide an instance of a handler
Session session = container.connectToServer(new ClientSocket(), uri);
I'm curious why the api was designed to accept a class instead of an instance, which is unlike how servlets work.
Update:
The following solution works:
// contains ServerEndpoint annotation and onMessage, onOpen etc
final EventSocket eventSocket = new EventSocket();
ServerEndpointConfig config = ServerEndpointConfig.Builder.create(eventSocket.getClass(), eventSocket.getClass().getAnnotation(ServerEndpoint.class).value())
.configurator(new Configurator() {
#Override
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
return (T) eventSocket;
}
})
.build();
wscontainer.addEndpoint(config);
In servlets, you have 1 instance for all requests to the same servlet.
In a websocket server, you have long lived connections, and the normal technique is to have a new websocket endpoint instance per connection. In websocket clients, you don't have to worry about this. You are just 1 instance to start with. If you want multiple connections, you have multiple instances of that websocket endpoint that you created yourself.
ServerContainer is a javax.websocket.server.ServerContainer (aka JSR-356).
It has 2 addEndpoint() mechanisms:
addEndpoint(Class<?> endpointClass) assumes that the class either extends from Endpoint or is annotated with #ServerEndpoint (yes, you can have server that doesn't initialize via annotation scanning, but still uses annotations and this addEndpoint mechanism to programatically add endpoints). It assumes that the server will instantiate a new Endpoint on each incoming websocket upgrade request.
addEndpoint(ServerEndpointConfig serverConfig) takes a ServerEndpointConfig that declares how you want your endpoint to bound. It too assumes that the server will instantiate a new Endpoint on each incoming websocket upgrade request. However, there is way out using this technique. Define your own Configurator object that overrides the getEndpointInstance(Class<?> endpointClass) method, returning the same object over and over again. Just note that the instance you return must be of the class type that was passed into that method (otherwise its an error).
If you choose to use the jetty native websocket implementation, then you can also use the WebSocketCreator to handle the creation of websocket instances, even singletons.

Resources