Long Polling fallback with websocket spring initialization - java

I am using Spring annotations to initialize my BayeuxServer. I enabled websocket by setting the transport in my Spring bean -
BayeuxServerImpl bean = new BayeuxServerImpl();
bean.setTransports(new WebSocketTransport(bean));
But now, when websocket connection fails or is disabled in js($.cometd.websocketEnabled = false;), it's not falling back to long polling successfully. It throws error "400 Unknown Bayeux Transport" in firebug console.
I couldn't set LongPollingTransport in setTransports since LongPollingTransport is an abstract class in the library. I tried creating a class which extends LongPollingTransport and specifying it in the setTransports API, but that didn't work either. Please let me know if I am doing something wrong. We need long polling to work in case websockets fail.
cometd version: 2.5.1
jetty version: 7.6.8

By calling BayeuxServer.setTransports(...) with just one transport, you basically disable any fall back capability since you are explicitly telling CometD to use 1 transport only.
Class LongPollingTransport has 2 subclasses depending on the specific mechanism to use; you may want to use class JSONTransport.
Note that the CometD documentation has an example of how to setup WebSocket with Spring using XML, but it is enough to translate the XML into code to have it working with annotations.
Basically, it all boils down to:
bayeuxServer.setTransports(new WebSocketTransport(bayeuxServer), new JSONTransport(bayeuxServer));

Related

Programmatically created Feign client and Eureka target

I have started a few days ago to learn about fault tolerance solutions in microservices. I have some microservices in my ecosystem and they are now interconnected with Eureka service lookup. I used FeignClient to call from one to another. As I heard and read, that Hystrix is getting into maintenance, I wondered if I could use Resilience4J in Feign instead of Hystrix. Well, at least not from annotation level right now as it seems. I found a great Feign.Builder adapter to add resilience4j fault tolerance features above a FeignClient as a decorator (https://github.com/resilience4j/resilience4j/tree/master/resilience4j-feign) so I wanted to use it.
So I used this, added together the features and added the default encoder, decoder, etc. items into the feign builder. Turns out I have to finish of course my code with a .target call which creates my client proxy and I could not really do this with Eureka in a good way:
The first constructor, which takes the class type and the URL is hardcoded, so if I add an eureka next server query into this parameter, it is just a hardcoded url for one of the instances, this is not load balanced. Some kinda workaround could be that I create prototype-scope or similar short lived scoped beans of this client and always get the "next url" for the call. This adds lots of burden to use the clients in every class I make. At least as I saw it. Maybe I could add some kind of singleton helper bean around the prototyping, but again this is not a good design as I see
I thought maybe I could create an EurekaTarget from the Target interface, but of course none of the methods indicate any "end of lifecycle" things, not even the apply method. I thought maybe that is one point which is called before doing a service call, but I saw multiple calls towards it so I had to change the url for all calls.
Do you know any better solution to do this migration?
I guess you are using Spring Boot?
The next version v1.0.0 of Resilience4j will support the #FeignClient annotation.
There was a PR which added the functionality -> https://github.com/resilience4j/resilience4j/pull/579
You can then use it as follows:
#FeignClient(name = DUMMY_FEIGN_CLIENT_NAME)
#CircuitBreaker(name = DUMMY_FEIGN_CLIENT_NAME)
public interface DummyFeignClient {
String DUMMY_FEIGN_CLIENT_NAME = "dummyFeignClient";
#GetMapping(path = "/api/{param}")
void doSomething(#PathVariable(name = "param") String param);
}

Dropwizard registering two classes/clients

I have two instances of clients with different configs that I am creating (timeout, threadpool, etc...), and would like to leverage Dropwizard's metric on both of the clients.
final JerseyClientBuilder jerseyClientBuilder = new JerseyClientBuilder(environment)
.using(configuration.getJerseyClientConfiguration());
final Client config1Client = jerseyClientBuilder.build("config1Client");
environment.jersey().register(config1Client);
final Client config2Client = jerseyClientBuilder.build("config2Client");
environment.jersey().register(config2Client);
However, I am getting
org.glassfish.jersey.internal.Errors: The following warnings have been detected:
HINT: Cannot create new registration for component type class org.glassfish.jersey.client.JerseyClient:
Existing previous registration found for the type.
And only one client's metric shows up.
How do I track both clients' metrics or is it not common to have 2 clients in a single dropwizard app?
Never mind, turned out I was an idiot (for trying to save some resource on the ClientBuilder).
2 Things that I did wrong with my original code:
1. You don't need to register Jersey clients, just the resource is enough... somehow I missed the resource part in my code and just straight up trying to register the client
2. You need to explicitly build each JerseyClientBuilder and then build your individually configured clients, then dropwizard will fetch by each JerseyClientBuilder's metrics
In the end, I just had to change my code to the following:
final Client config1Client = new JerseyClientBuilder(environment)
.using(configuration.getJerseyClientConfiguration()).build("config1Client");
final Client config2Client = new JerseyClientBuilder(environment)
.using(configuration.getJerseyClientConfiguration()).build("config2Client");
Doh.
environment.jersey().register() has a javadoc listing of Adds the given object as a Jersey singleton component meaning that the objects registered become part of the jersey dependency injection framework. Specifically this method is used to add resource classes to the jersey context, but any object with an annotation or type that Jersey looks for can be added this way. Additionally, since they are singletons you can only have one of them per any concrete type (which is why you are getting a "previous registration" error from Jersey).
I imagine that you want to have two Jersey clients to connect to two different external services via REST/HTTP. Since your service needs to talk to these others to do its work, you'll want to have the clients accessible wherever the "work" or business logic is being performed.
For example, this guide creates a resource class that requires a client to an external http service to do currency conversions. I'm not saying this is a great example (just a top google result for dropwizard external client example). In fact, I think this not a good to structure your application. I'd create several internal objects that hide from the resource class how the currency information is fetched, like a business object (BO) or data access object (DAO), etc.
For your case, you might want something like this (think of these as constructor calls). JC = jersey client, R = resource object, BO = business logic object
JC1()
JC2()
B1(JC1)
B2(JC2)
R1(B1)
R2(B2)
R3(B1, B2)
environment.jersey().register(R1)
environment.jersey().register(R2)
environment.jersey().register(R3)
The official Dropwizard docs are somewhat helpful. They at least explain how to create a jersey client; they don't explain how to structure your application.
If you're using the Jersey client builder from dropwizard, each of the clients that you create should be automatically registered to record metrics. Make sure you're using the client builder from the dropwizard-client artifact and package io.dropwizard.client. (Looks like you are because you have the using(config) method.)

Why does Jetty JSR356 behave differently with regards to checkOrigin and modifyHandshake

I was playing around with Jetty (9.2.3v20140905) by connecting a web socket endpoint where I tried to use my own ServerEndpointConfig when I came across Jetty's code to see how it was used.
I notice that it is used in JsrCreator when a web socket object is created:
Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp){
...
// modify handshake
configurator.modifyHandshake(config,hsreq,hsresp);
...
}
I read the javadoc of modifyHandshake of ServerEndpointConfig (javax.websocket-api 1.0) that states:
Called by the container after it has formulated a handshake response resulting from
a well-formed handshake request. The container has already
checked that this configuration has a matching URI, determined the
validity of the origin using the checkOrigin method, and filled
out the negotiated subprotocols and extensions based on this configuration.
Custom configurations may override this method in order to inspect
the request parameters and modify the handshake response that the server has formulated.
and the URI checking also.
If the developer does not override this method, no further
modification of the request and response are made by the implementation.
Here's what Jetty does:
Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp){
...
// modify handshake
configurator.modifyHandshake(config,hsreq,hsresp);
// check origin
if (!configurator.checkOrigin(req.getOrigin())){...}
...
resp.setAcceptedSubProtocol(subprotocol);
...
resp.setExtensions(configs);
}
As you can see, the origin is checked after the configurator as been called. The response is modified after the configurator as been called.
The method acceptWebSocket of WebSocketServerFactory makes a call to the WebSocketCreator:
Object websocketPojo = creator.createWebSocket(sockreq, sockresp);
And after that calls:
private boolean upgrade(HttpConnection http, ServletUpgradeRequest request, ServletUpgradeResponse response, EventDriver driver)
which also modifies the response via HandshakeRFC6455:
// build response
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("Sec-WebSocket-Accept",AcceptHash.hashKey(key));
So I have no way modifying the response only with my configurator because Jetty will change it anyway.
It seems to me Jetty does not comply with JSR 356, the Java API for WebSocket, does it?
Ah, one of the many ambiguous and ill defined parts of the JSR-356 spec.
You might want to read the open bugs against the spec.
There are many real world examples of scenarios that are rendered impossible if the original 1.x spec is follow exactly.
Now, to tackle the specific details of your question:
Why is checkOrigin called after modifyHandshake in the Jetty implementation?
This is because there are valid scenarios (esp with CDI and Spring) where the information needed by a checkOrigin implementation by the end user is not valid, or exists, until the modifyHandshake call is called.
Basically, the endpoint Configurator is created, the modifyHandshake is called, and at that point, all of the library integration (CDI, Spring, etc.) starts, that's when the endpoint enters the WebSocket (RFC6455) CONNECTING state. (once the endpoint's onOpen is called, then the WebSocket RFC6455 state goes to the OPEN state)
As you have probably noticed, there's no definitions in the spec of the scopes and lifetimes of objects when CDI (or Spring) is involved.
The 1.x JSR356 spec actually distances itself from servlet container specific behavior, it was done to make the spec as generic as possible, with the ability to have non-servlet websocket server containers too. Unfortunately, that also means that there are many use cases in a servlet container that doesn't mesh with the 1.x JSR356 spec.
Once the JSR356 spec is updated to properly define the CDI scopes on WebSocket, then this quirk of checkOrigin after modifyHandshake can be fixed.
Why is the implementation modifying the response after modifyHandshake?
The implementation has to modify the response, otherwise the response is invalid for HTTP/1.1 upgrade, the need of the implementation to cooperate with the endpoint and its configuration, for sub protocols, and extensions makes this a reality. (Notice that the the JSR356 spec punts on Extensions?)
This is also an area that is promised to be corrected in the next JSR356 revision.
The current work on the WebSocket over HTTP/2 spec makes this even more interesting, as it isn't (currently) using the HTTP/1.1 upgrade semantic. It just comes into existence with a handshake only (no Upgrade, no Origin, etc).

Insert MBean interceptor

I am working in a java project which implements MBeans and my need is to intercept MBean and change/add their properties before registry. Example :
domainName:name=myMBean --> domainName:name=myMBean1,type=myType
I found this link which presents how to apply an interceptor other then default interceptor but I have no idea to how do that in code.
Thanks in advance.
Once you register the bean obviously it is too late. The easiest thing to do is to change how the registration is done. If you show us what framework you are using to register the bean then I'll be able to help more.
Typically whatever is doing the actual registration is doing something like:
private MBeanServer mbeanServer;
...
mbeanServer.registerMBean(mbean, objectName);
You can therefore provide a different ObjectName:
ObjectName objectName = new ObjectName("domainName:name=myMBean1,type=myType");
But I assume you are not doing the registration yourself.
As an aside, I'm not sure you can switch to use a different JMX framework but I've put the finishing touches on my Simple JMX system recently. It allows objects to name themselves programmatically when they are published.

Custom serialization of JDK5 Enum in Axis 1.2 on client-side

I am migrating a SOAP web service to JDK1.5.
I have took advantage of native java enums in the new code.
For some reasons, I'm stuck with Axis 1.2 and it does not natively support JDK5 "enums".
I have found a tutorial on how to implement custom a serialization / deserialization for java enums:
http://www.developpez.net/forums/d236564/java/developpement-web-java/web-services/utiliser-type-enum-jdk5-axis/ (in French).
I have been able to successfully register those custom serialization handlers on the server side via the use of "typeMapping" elements in the ".wsdd" file.
However, I can't figure out how to register the same classes on the client side, as I do not have a ".wssd" file here.
Any help would be appreciated.
Thanks,
Raphael
I have finally found how to manually register a custom type mapping.
I do it when creating an instance of a Service :
service = new Service();
// Get default type mapping
TypeMapping tmap = DefaultTypeMappingImpl.getSingletonDelegate();
// Register our custom serializer / deserializer
tmap.register(
MyCustomClass.class,
MyCustomClassQName,
new MyCustomSerizalizerFactory(),
new MyCustomDeserizalizerFactory());
// Add it back to the service
service.getTypeMappingRegistry().register(
"http://schemas.xmlsoap.org/soap/encoding/", // Default encoding
tmap);
I don't know whether it is the right way to do it, but it works !

Categories

Resources