• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
  • Knute Snortum
Saloon Keepers:
  • Ron McLeod
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Frits Walraven
Bartenders:
  • Carey Brown
  • salvin francis
  • Claude Moore

Using custom Configurator with WebSockets  RSS feed

 
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,

Just a quick question with regard to extending ServerEndpointConfig.Configurator to override Tomcat's default action of instantiating the POJO class annotated with @ServerEndpoint on receiving a WebSocket request.  My reason for doing this is that my endpoint class depends on IoC dependency injection, and therefore needs to be got from the registry to have its dependencies in place.

My Configurator method:



The @ServerEndpoint annotation is placed on on my HarbourServerEndpointImpl POJO class, not the interface that it implements.  Based on the below runtime catalina.out error message the problem appears to be that the registry is returning HarbourServerEndpoint whereas Tomcat is expecting an instance of HarbourServerEndpointImpl?

I'm hoping someone can please explain what is going wrong with my custom Configurator.


15-Apr-2019 12:45:28.488 SEVERE [http-nio-8080-exec-915] org.apache.coyote.AbstractProtocol$ConnectionHandler.process Error reading request, ignored java.lang.ClassCastException: Cannot cast $HarbourServerEndpoint_39c9cc24eb8b2a to com.optomus.harbour.services.HarbourServerEndpointImpl
       at java.lang.Class.cast(Class.java:3369)
       at com.optomus.harbour.services.HarbourServerEndpointConfigurator.getEndpointInstance(HarbourServerEndpointConfigurator.java:17)
       at org.apache.tomcat.websocket.pojo.PojoEndpointServer.onOpen(PojoEndpointServer.java:44)
       at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.init(WsHttpUpgradeHandler.java:133)
       at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:846)
       at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)
       at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
       at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
       at java.lang.Thread.run(Thread.java:748)


Finally, with no casting at all, the compiler gives the error:

   Error:(17, 40) java: incompatible types: inference variable T has incompatible bounds
       equality constraints: com.optomus.harbour.services.HarbourServerEndpoint
       upper bounds: T,java.lang.Object

Regards,

Chris.
 
Ranch Hand
Posts: 380
2
Fedora IntelliJ IDE Spring
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
is that the full error message without casting?  It seems like something screwy is going on with the class types.  The expected class and the given class don't match, so you need to make sure they match up.
 
Christopher Dodunski
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Al Hobbs wrote:is that the full error message without casting?  It seems like something screwy is going on with the class types.  The expected class and the given class don't match, so you need to make sure they match up.



Hi Al,

In the meanwhile I researched Tapestry-IoC and how it works.  Turns out there is a reason for what is being returned looking a little 'screwy' ($HarbourServerEndpoint_39c9cc24eb8b2a).  It is a service proxy object, not an instance of the service implementation as I was expecting.  I'm not sure how typical this is for IoC containers.  Quoting from the Tapestry website:


Services consist of two main parts: a service interface and a service implementation.

The service interface is how the service will be represented throughout the rest of the registry. Since what gets passed around is normally a proxy, you can't expect to cast a service object down to the implementation class (you'll see a ClassCastException instead). In other words, you should be careful to ensure that your service interface is complete, since Tapestry IoC effectively walls you off from back doors such as casts.



This makes it rather tricky to acquire from the IoC registry instances of the class annotated with @ServerEndpoint, and I'm now exploring other options.

Regards,

Chris.
 
Al Hobbs
Ranch Hand
Posts: 380
2
Fedora IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It seems like what the site says is to put those classes into a service  class and then get that service class from the registry.
 
Christopher Dodunski
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Al Hobbs wrote:It seems like what the site says is to put those classes into a service  class and then get that service class from the registry.



Indeed, except that what you get back from the IoC registry is a proxy object that implements the interface for that particular service.  The service implementation of course implements this same interface, but unfortunately the registry does not return an instance of this implementation.  Therein lies the problem: Tomcat requires an instance of the class annotated with @ServerEndpoint, and this is on the service implementation class.

Someone suggested shifting the WebSocket annotations from the implementation to the interface.  I will try this, though I've only ever seen POJOs annotated as WebSocket endpoints, never interfaces.

Regards,

Chris.
 
Al Hobbs
Ranch Hand
Posts: 380
2
Fedora IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yeah, I was thinking you could put the annotation on the interface.  That seems like a better design anyway.  If you have an interface that acts as a server endpoint, you probably aren't going to use it in another situation where you don't need the annotation. maybe..
 
Christopher Dodunski
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Al Hobbs wrote:Yeah, I was thinking you could put the annotation on the interface.  That seems like a better design anyway.  If you have an interface that acts as a server endpoint, you probably aren't going to use it in another situation where you don't need the annotation. maybe..



According to the folks at Tomcat...

> The WebSocket spec explicitly states that WebSocket annotations do not
> follow Java inheritance so moving the annotation to the interface is not
> an option.
>
> I think you are going to have to build your ServerEndpointConfig
> programmatically so you can specify the correct endpoint class.
 
Al Hobbs
Ranch Hand
Posts: 380
2
Fedora IntelliJ IDE Spring
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So you get the interface implementation from the registry and then when you cast it to the underlying class it throws a cast exception?  It seems like that should work.
 
Christopher Dodunski
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Al Hobbs wrote:So you get the interface implementation from the registry and then when you cast it to the underlying class it throws a cast exception?  It seems like that should work.



Good point!  Looking at the Tapestry-IoC Registry code I notice that although it constructs a (plastic) service proxy object, it does cast it to its associated interface before making it available from the registry's getService() method.  So if I move the WebSocket annotations to my interface as previously intended, Tomcat should be getting back from the registry what it expects: an instance of the interface annotated with @ServerEndpoint.  My first job for tomorrow.  :-)

You seem to be in a similar time zone Al?  I'm in Taranaki, NZ.
 
Christopher Dodunski
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hit a dead end with the 'WebSocket annotations on interface' idea, sorry to say.  

From the Java WebSockets specification:


4.1
@ServerEndpoint
This class level annotation signifies that the Java class it decorates must be deployed by the implementation as a websocket server endpoint and made available in the URI-space of the websocket implementation. The class must be public, CONCRETE, and have a public no-args constructor.


May have to venture into the unfamiliar world of programmatic endpoints by the looks.

Regards,

Chris.
 
No matter. Try again. Fail again. Fail better. This time, do it with this tiny ad:
Create Edit Print & Convert PDF Using Free API with Java
https://coderanch.com/wiki/703735/Create-Convert-PDF-Free-Spire
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!