Jetty, JAX-RS 2.1 and SSE - jersey-2.0

I tried to test Server-side events(SSE) on Jetty 9.4.7 but it doesn't work (but works on GlassFish 5). Here is my code:
#Path("sse")
public class SseResource {
#GET
#Produces(MediaType.SERVER_SENT_EVENTS)
#Path("time")
public void currentTime(#Context SseEventSink eventSink, #Context Sse sse) {
new Thread(() -> {
OutboundSseEvent event = sse.newEventBuilder().name("current-time")
.data(String.class, LocalTime.now().toString()).build();
eventSink.send(event);
}).start();
}
}
When I try to call my endpoint /sse/time I get 404 exception:
javax.ws.rs.NotFoundException: HTTP 404 Not Found
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:274) [jersey-server-2.26.jar:?]
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:272) [jersey-common-2.26.jar:?]
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:268) [jersey-common-2.26.jar:?]
at org.glassfish.jersey.internal.Errors.process(Errors.java:316) [jersey-common-2.26.jar:?]
at org.glassfish.jersey.internal.Errors.process(Errors.java:298) [jersey-common-2.26.jar:?]
Please, advise.

I am very new to this , but this code and seems that work, with jax rs connector .
#Path( "events" )
public class ExampleService {
#GET
#Produces( SseFeature.SERVER_SENT_EVENTS )
public EventOutput getServerSentEvents() {
final EventOutput eventOutput = new EventOutput();
new Thread( new Runnable() {
#Override
public void run() {
try {
for( int i = 0; i < 10; i++ ) {
Thread.sleep( 1000 );
final OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
eventBuilder.name( "toevent" );
eventBuilder.data( String.class, "Hello world " + i + "!");
final OutboundEvent event = eventBuilder.build();
eventOutput.write( event );
}
} catch( IOException e ) {
throw new RuntimeException( "Error when writing the event.", e );
} catch( InterruptedException e ) {
e.printStackTrace();
} finally {
try {
eventOutput.close();
} catch( IOException ioClose ) {
throw new RuntimeException( "Error when closing the event output.", ioClose );
}
}
}
} ).start();
return eventOutput;
}
}

The JAX-RS 2.1 follows the Java EE 8 specification. Latest Jetty 9.4.x follows Java EE 7 specification. So, you will need to wait for Jetty 10 which will have support for EE 8 . But it does not have any release date.
That said, Jetty does support SSE with JAX-RS 2.0

Related

Can we throw an exception in fallback or fallbackFactory of #FeignClient

I'm use the #FeignClient and want to do some logic(like record the exception information) when Feign throw Exception and then reply the result to front end.
I noticed Feign will throw FeignException when connection fail or http status not expect.
So I defined a #ExceptionHandler to caught FeignException after the callback method was invoked.
#ExceptionHandler(value = FeignException.class)
#ResponseBody
public ResponseResult feignException(FeignException exception){
String message = exception.getMessage();
byte[] content = exception.content();
int status = exception.status();
if(content!=null){
String response=new String(content);
message=String.format("%s response message : %s",message,response);
}
log.warn("{} : {} , cause by : {}",exception.getClass().getSimpleName(),message,exception.getCause());
return ResponseResult.fail(HttpStatus.valueOf(status),String.format("9%s00",status),message);
But it can't caught when I set the callback or callbackFactory of #FeignClient.
#FeignClient(url = "${onboardingcase.uri}",name = "OnBoardingCaseService",
fallbackFactory = OnBoardingCaseServiceFallBack.class)
#Component
#Slf4j
public class OnBoardingCaseServiceFallBack implements FallbackFactory<OnBoardingCaseService> {
#Override
public OnBoardingCaseService create(Throwable throwable) {
return new OnBoardingCaseService() {
#Override
public OnBoardingCaseVo query(String coid) {
if(throwable instanceof FeignException){
throw (FeignException)throwable;
}
return null;
}
};
}
}
I noticed because hystrix took over this method.And will catch exception in HystrixInvocationHandler.
try {
Object fallback = HystrixInvocationHandler.this.fallbackFactory.create(this.getExecutionException());
Object result = ((Method)HystrixInvocationHandler.this.fallbackMethodMap.get(method)).invoke(fallback, args);
if (HystrixInvocationHandler.this.isReturnsHystrixCommand(method)) {
return ((HystrixCommand)result).execute();
} else if (HystrixInvocationHandler.this.isReturnsObservable(method)) {
return ((Observable)result).toBlocking().first();
} else if (HystrixInvocationHandler.this.isReturnsSingle(method)) {
return ((Single)result).toObservable().toBlocking().first();
} else if (HystrixInvocationHandler.this.isReturnsCompletable(method)) {
((Completable)result).await();
return null;
} else {
return HystrixInvocationHandler.this.isReturnsCompletableFuture(method) ? ((Future)result).get() : result;
}
} catch (IllegalAccessException var3) {
throw new AssertionError(var3);
} catch (ExecutionException | InvocationTargetException var4) {
throw new AssertionError(var4.getCause());
} catch (InterruptedException var5) {
Thread.currentThread().interrupt();
throw new AssertionError(var5.getCause());
}
So I want to know how can I throw an exception when I using callback / callbackFactory or there is another way to instead callbackFactory to do the "call back"?
Many Thanks
I found a solution to this problem.
public class OnBoardingCaseServiceFallBack implements FallbackFactory<OnBoardingCaseService> {
#Override
public OnBoardingCaseService create(Throwable throwable) {
return new OnBoardingCaseService() {
#Override
public OnBoardingCaseVo query(String coid) {
log.error("OnBoardingCaseService#query fallback , exception",throwable);
if(throwable instanceof FeignException){
throw (FeignException)throwable;
}
return null;
}
};
}
}
And then caught the HystrixRuntimeException and get the cause of exception in ExceptionHandler for get the realException that was wrapped by Hystrix.
#ExceptionHandler(value = HystrixRuntimeException.class)
#ResponseBody
public ResponseResult hystrixRuntimeException(HystrixRuntimeException exception){
Throwable fallbackException = exception.getFallbackException();
Throwable assertError = fallbackException.getCause();
Throwable realException = assertError.getCause();
if(realException instanceof FeignException){
FeignException feignException= (FeignException) realException;
String message = feignException.getMessage();
byte[] content = feignException.content();
int status = feignException.status();
if(content!=null){
String response=new String(content);
message=String.format("%s response message : %s",message,response);
}
return ResponseResult.fail(HttpStatus.valueOf(status),String.format("9%s00",status),message);
}
String message = exception.getMessage();
log.warn("{} : {} , cause by : {}",exception.getClass().getSimpleName(),message,exception.getCause());
return ResponseResult.fail(ResultCode.FAIL.httpStatus(),ResultCode.FAIL.code(),message);
}
But I don't think that's a good way~
I have never done this in fallback, I have implemented custom error decoder(“CustomFeignErrorDecoder”) class and extended feign.codec.ErrorDecoder, every time an error occurs it comes to this class.
In decode function throw a custom exception and catch it in the controller or service layer to show your message to the frontend.
Example:
#Component
public class CustomFeignErrorDecoder implements ErrorDecoder {
#Override
public Exception decode(String methodKey, Response response) {
throw new CustomFeignErrorDecoderException(methodKey +" response status "+ response.status() +" request "+ response.request()+ " method "+ response.request().httpMethod());
}
}

Netty connection pool not sending messages to server

I have a simple netty connection pool and a simple HTTP endpoint to use that pool to send TCP messages to ServerSocket. The relevant code looks like this, the client (NettyConnectionPoolClientApplication) is:
#SpringBootApplication
#RestController
public class NettyConnectionPoolClientApplication {
private SimpleChannelPool simpleChannelPool;
public static void main(String[] args) {
SpringApplication.run(NettyConnectionPoolClientApplication.class, args);
}
#PostConstruct
public void setup() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.remoteAddress(new InetSocketAddress("localhost", 9000));
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new DummyClientHandler());
}
});
simpleChannelPool = new SimpleChannelPool(bootstrap, new DummyChannelPoolHandler());
}
#RequestMapping("/test/{msg}")
public void test(#PathVariable String msg) throws Exception {
Future<Channel> future = simpleChannelPool.acquire();
future.addListener((FutureListener<Channel>) f -> {
if (f.isSuccess()) {
System.out.println("Connected");
Channel ch = f.getNow();
ch.writeAndFlush(msg + System.lineSeparator());
// Release back to pool
simpleChannelPool.release(ch);
} else {
System.out.println("not successful");
}
});
}
}
and the Server (ServerSocketRunner)
public class ServerSocketRunner {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(9000);
while (true) {
Socket socket = serverSocket.accept();
new Thread(() -> {
System.out.println("New client connected");
try (PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));) {
String inputLine, outputLine;
out.println("Hello client!");
do {
inputLine = in.readLine();
System.out.println("Received: " + inputLine);
} while (!"bye".equals(inputLine));
System.out.println("Closing connection...");
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
DummyChannelPoolHandler and DummyClientHandler just print out events that happen, so they are not relevant. When the server and the client are started and I send a test message to test endpoint, I can see the server prints "New client connected" but the message sent by client is not printed. None of the consecutive messages sent by client are printed by the server.
If I try telnet, everything works fine, the server prints out messages. Also it works fine with regular netty client with same bootstrap config and without connection pool (SimpleNettyClientApplication).
Can anyone see what is wrong with my connection pool, I'm out of ideas
Netty versioin: 4.1.39.Final
All the code is available here.
UPDATE
Following Norman Maurer advice. I added
ChannelFuture channelFuture = ch
.writeAndFlush(msg + System.lineSeparator());
channelFuture.addListener(writeFuture -> {
System.out
.println("isSuccess(): " + channelFuture.isSuccess() + " : " + channelFuture.cause());
});
This prints out
isSuccess: false : java.lang.UnsupportedOperationException: unsupported message type: String (expected: ByteBuf, FileRegion)
To fix it, I just converted String into ByteBuf
ch.writeAndFlush(Unpooled.wrappedBuffer((msg + System.lineSeparator()).getBytes()));
You should check what the status of the ChannelFuture is that is returned by writeAndFlush(...). I suspect it is failed.

Vertx.deployVerticle does not call the supplied completion handler

I writing a service where a deployed verticle is linked to a rest endpoint. The service is working 100% (I dynamically deployed the verticle and calling the REST endpoint execute a function on the verticle). The problem is that the supplied completion handler is never called. Any ideas?
Following is my code:
LOGGER.debug(String.format("Starting runner %s:%s:%s" ,functionName, faasFunctionClass, fileName));
DeploymentOptions deploymentOptions = new DeploymentOptions();
deploymentOptions.setInstances(1);
JsonObject jsonObject = new JsonObject();
jsonObject.put(FUNCTION_NAME, functionName);
jsonObject.put(FUNCTION_CLASS, faasFunctionClass);
jsonObject.put(FUNCTION_FILENAME, fileName);
deploymentOptions.setConfig(jsonObject);
LOGGER.debug(String.format("Deploying [%s]" ,jsonObject.encode()));
this.vertx.deployVerticle("faas:" + VertxFaasRunner.class.getCanonicalName(),deploymentOptions, event->{
if (event.succeeded()) {
System.out.println("Deployment id is: " + event.result());
} else {
System.out.println("Deployment failed!");
}
});
In this case it depends on how you have implemented your Verticle.
in the below code when future.complete() is executed then only event.succeeded() will be true.
public class MainVerticle extends AbstractVerticle {
#Override
public void start() throws Exception {
System.out.println("[Main] Running in " + Thread.currentThread().getName());
vertx
.deployVerticle("io.vertx.example.core.verticle.worker.WorkerVerticle",
new DeploymentOptions().setWorker(true), event -> {
if (event.succeeded()) {
System.out.println("Deployment id is: " + event.result());
} else {
System.out.println("Deployment failed!");
}
});
}
}
public class WorkerVerticle extends AbstractVerticle {
#Override
public void start(Future future) throws Exception {
System.out.println("[Worker] Starting in " + Thread.currentThread().getName());
vertx.eventBus().<String>consumer("sample.data", message -> {
System.out.println("[Worker] Consuming data in " + Thread.currentThread().getName());
String body = message.body();
message.reply(body.toUpperCase());
});
// this notifies that the verticle is deployed successfully.
future.complete();
}
}

How to use Retry rule along with Errorcollector rule in junit

I am using Error collector rule in my application( selenium web driver). I am able to thrown exception and continue next line of code with help of error collector rule. But right now i want to re run failed test again ( 3 times) to ensure they are really failed. hence i am using Retry rule. But this rule when applied individually it get executed ( Retry rule with Assert command) `but when written with error collector is doesn't get executed any reason....
Please help me with sample code.
TestBase.java:
public class TestBase {
#Rule
public ErrorCollector collector = new ErrorCollector();
private boolean fatal;
public TestBase() {
fatal=true;
}
public void assertEquals( String msg, Object expected, Object actual) {
if(getFatal()) {
Assert.assertEquals(msg,expected, actual);
} else {
collector.checkThat(msg, actual, CoreMatchers.is(expected));
}
}
public void setFatal(boolean fatalFlag) {
fatal = fatalFlag;
}
public boolean getFatal() {
return fatal;
}
}
BFMNew.java
public class BFMNew extends TestBase {
#Rule
public Retry retry = new Retry(3);
#Rule
public ErrorCollector errocol = new ErrorCollector();
#Before
public void setUp() throws Exception {
System.out.println(" in before");
}
// ===========Re run fail test custom====
public class Retry implements TestRule {
private int retryCount;
public Retry(int retryCount) {
this.retryCount = retryCount;
}
public Statement apply(Statement base, Description description) {
return statement(base, description);
}
private Statement statement(final Statement base,
final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
Throwable caughtThrowable = null;
// implement retry logic here
for (int i = 0; i < retryCount; i++) {
try {
base.evaluate();
return;
} catch (Throwable t) {
caughtThrowable = t;
System.err.println(description.getDisplayName()
+ ": run " + (i + 1) + " failed");
}
}
System.err.println(description.getDisplayName()
+ ": giving up after " + retryCount + " failures");
throw caughtThrowable;
}
};
}
}
#Test
public void one() {
setFatal(false);
Boolean IsLogin = true; //Here function will come for login
Boolean IsPost = null;
Boolean IsStnComment = null;
Boolean IsPhotoUpload = false;
if( IsLogin ) {
IsPost = false;
assertEquals("Failed to Insert Post", true, IsPost);
}
System.out.println(" After Post ");
assertEquals("Failed to upload photo", true, IsPhotoUpload);
if( IsPost ) {
IsStnComment = false;
//assertEquals("Failed to Insert Comment", true, IsStnComment);
}
System.out.println("After comment");
}
The problem is with rules ordering. You should make ErrorCollector to be outer rule and Retry inner rule. Starting from junit 4.10 use this
class YourTest {
private ErrorCollector collector = new ErrorCollector();
private Retry retry = Retry(3);
#Rule
public TestRule chain= RuleChain
.outerRule(collector)
.around(retry);
// tests using collector go here
}

Using java nio in java ee

I want to use java nio in java ee.
But I don't know how to do it right.
I need to after server has deploy java.nio.selector always listens the port and processing socket connection.
I try do it there:
#Singleton
#Lock(LockType.READ)
public class TaskManager {
private static final int LISTENINGPORT;
static {
LISTENINGPORT = ConfigurationSettings.getConfigureSettings().getListeningPort();
}
private ArrayList<ServerCalculationInfo> serverList;
public TaskManager() {
serverList = new ArrayList<ServerCalculationInfo>();
select();
}
#Asynchronous
public void select() {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
Selector selector = Selector.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(LISTENINGPORT));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
try {
selector.select();
} catch (IOException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
break;
}
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
it.remove();
try {
processSelectionKey(serverSocketChannel, selKey);
} catch (IOException e) {
serverList.remove(serverCalculationInfo);
}
}
}
} catch (IOException e) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, e);
} catch (Exception e) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, e);
}
}
}
It don't work correctly. The process hangs during deploy and redeploy application possible only after restart Glassfish.
How can I do right it?
It works correctly if invoke #Asynchronous method from the #PostConstructor:
#PostConstruct
public void postTaskManager() {
serverList = new ArrayList<ServerCalculationInfo>();
select();
}
instead of invoke it from constructor.
But class must be without #Startup annotation.