How can I register JSR-356 Websocket in PAX-Web? (In bundle, not WAR) - websocket

I have a problem with the PAX-Web. I've tried to register a Websocket service as declrarative, but it is unaccessible from web. I've tried the given websocket-jsr356-6.0.3.war and it works fine. As I see the WAR file handles differently the org.osgi.service.http.HttpContext. I've tried the following scenarios:
Scenario 1 - OSGi R6 Whiteboard HTTP method
Creating a ServletContextHelper:
package hu.blackbelt.judo.common.rest.regular;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.http.context.ServletContextHelper;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
#Component(immediate = true)
#Service(ServletContextHelper.class)
#Properties(value = {
#Property(name = HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, value = "chat"),
#Property(name = HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, value = "/test")
})
public class ChatServletContext extends ServletContextHelper {
}
And adding the Websocket Endpoint:
package hu.blackbelt.judo.common.rest.regular;
import lombok.extern.slf4j.Slf4j;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import javax.websocket.EncodeException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
#Component(immediate = true)
#Service(Object.class)
#Properties(value = {
#Property(name = HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT,
value = "=(" + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + "=chat)")
})
#Slf4j
public class ChatEndpoint {
public static final String ROOM = "room";
#OnOpen
public void onOpen(final Session session, #PathParam(ROOM) final String room) {
LOGGER.info("session openend and bound to room: " + room);
session.getUserProperties().put(ROOM, room);
}
#OnMessage
public void onMessage(final Session session, final ChatMessage chatMessage) {
String room = (String) session.getUserProperties().get(ROOM);
try {
for (Session s : session.getOpenSessions()) {
if (s.isOpen()
&& room.equals(s.getUserProperties().get(ROOM))) {
s.getBasicRemote().sendObject(chatMessage);
}
}
} catch (IOException | EncodeException e) {
LOGGER.warn("onMessage failed", e);
}
}
}
The logs show me that the Endpoint is catched. I've debugged and Pax-Web is registering it.
The log shows the following line:
2017-05-04 02:36:02,698 | INFO | Thread-70 | WebSocketTracker | 330 - org.ops4j.pax.web.pax-web-extender-whiteboard - 6.0.3 | found websocket endpoint!!
But the websocket is unaccessible with the following URL: ws://localost:8181/test/chat/testroom
Scenario 2 - Pax-Web properties on registered HttpContext (with JAX-RS it works)
Creating HttpContext instance: (Utilizing the OSGi given Helper abstract class):
package hu.blackbelt.judo.common.rest.regular;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.context.ServletContextHelper;
#Component(immediate = true)
#Service(HttpContext.class)
#Properties(value = {
#Property(name = "httpContext.id", value = "chat"),
#Property(name = "httpContext.path", value = "test")
})
public class ChatHttpContext extends ServletContextHelper implements HttpContext {
}
And the Websocket Endpoint:
package hu.blackbelt.judo.common.rest.regular;
import lombok.extern.slf4j.Slf4j;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
import javax.websocket.EncodeException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
#SuppressWarnings({"checkstyle:missingctor", "checkstyle:illegaltoken"})
#Component(immediate = true)
#Service(Object.class)
#Properties(value = {
#Property(name = "httpContext.id", value = "chat")
})
#ServerEndpoint(value = "/chat/{room}", encoders = ChatMessageEncoder.class, decoders = ChatMessageDecoder.class)
#Slf4j
public class ChatEndpoint {
public static final String ROOM = "room";
#OnOpen
public void onOpen(final Session session, #PathParam(ROOM) final String room) {
LOGGER.info("session openend and bound to room: " + room);
session.getUserProperties().put(ROOM, room);
}
#OnMessage
public void onMessage(final Session session, final ChatMessage chatMessage) {
String room = (String) session.getUserProperties().get(ROOM);
try {
for (Session s : session.getOpenSessions()) {
if (s.isOpen()
&& room.equals(s.getUserProperties().get(ROOM))) {
s.getBasicRemote().sendObject(chatMessage);
}
}
} catch (IOException | EncodeException e) {
LOGGER.warn("onMessage failed", e);
}
}
}
But the websocket is unaccessible with the following URL: ws://localost:8181/test/chat/testroom
How can I achive that webcsocket be available? I do not want to repackage my bundle as WAB. Is there any way?

Related

send data from spring boot to client with stomp websocket

I want to send data from Boot(Server) to client!
I am using stomp websocket!
WebSocketClient doesn't work with error that the HTTP response from the server [200] did not permit the HTTP upgrade to WebSocket!
It's my Java Stomp WebSocket client code!
In this code, I tried to config handShakeHeader.... but it doesn't work!
package refill.station.websocket;
import org.junit.jupiter.api.Test;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandler;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class WebSocketTest {
#Test
public void WebSocketTest() {
WebSocketClient webSocketClient = new StandardWebSocketClient();
WebSocketStompClient stompClient = new WebSocketStompClient(webSocketClient);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
stompClient.setTaskScheduler(new ConcurrentTaskScheduler());
String url = "ws://localhost:8080/ws/websocket";
StompSessionHandler sessionHandler = new StompSessionHandlerAdapter() {};
List<String> protocols = new ArrayList<>();
protocols.add("v10.stomp");
protocols.add("v11.stomp");
WebSocketHttpHeaders handSahkeHeaders = new WebSocketHttpHeaders();
handSahkeHeaders.setUpgrade("websocket");
handSahkeHeaders.setConnection("Upgrade");
handSahkeHeaders.setSecWebSocketVersion("13");
handSahkeHeaders.setSecWebSocketKey("4hb9p5/JjeKLed5aXlBqnw==");
handSahkeHeaders.setSecWebSocketProtocol(protocols);
StompHeaders stompHeaders = new StompHeaders();
StompSession stompSession = null;
try {
stompSession = stompClient.connect(URI.create(url), handSahkeHeaders, stompHeaders, sessionHandler).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
stompSession.send("/app/control/complete", "msg");
// StompSession stompSession = stompClient.connect(url, sessionHandler).get();
}
}
I checked my WebSocket server with javascript and it works correctly!
This is my WebSocket server configuration!
package refill.station.config.websocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.server.RequestUpgradeStrategy;
import org.springframework.web.socket.server.standard.TomcatRequestUpgradeStrategy;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
RequestUpgradeStrategy upgradeStrategy = new TomcatRequestUpgradeStrategy();
registry.addEndpoint("/ws")
.withSockJS();
registry.addEndpoint("/ws")
.setHandshakeHandler(new DefaultHandshakeHandler(upgradeStrategy))
.setAllowedOrigins("*");
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/control");
}
}
last, it's my controller for websocket!
package refill.station.controller.websocket;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
#RequiredArgsConstructor
#RestController
#Slf4j
public class RefillerCommunicateController {
#MessageMapping("/control/complete")
#SendTo("/control/operate")
public String test(#Payload String data) {
log.info("RefillerCommunicateController-test method");
return "test";
}
}

Hystrix Command property ignoreExceptions is not working expectedly

Using Hystrix command to invoke a default functionality and also have an API exception handler which is handling the exceptions and letting user/client know about the error that happened but while my server is UP, #HystrixCommand function is still getting called while my custom exception handler is being ignored instead of using ignoreExceptions property of #HystrixCommand annotation.
Please guide me how to make this work.
package com.example.demo.controller;
import java.util.List;
import javax.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.exception.FactorNotCreatedException;
import com.example.demo.exception.NotFoundException;
import com.example.demo.feignClient.ConversionFactorProxyClient;
import com.example.demo.model.ConversionFactor;
import com.example.demo.model.CurrencyConversion;
import com.example.demo.model.FactorResponse;
import com.example.demo.service.ConvertService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixException;
import feign.FeignException;
#RestController
public class ConvertCurrencyController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private ConversionFactorProxyClient cnvFacCl;
#Autowired
private ConvertService convertServ;
#GetMapping(value = "/currency-converter/from/{from}/to/{to}/quantity/{quantity}")
#HystrixCommand(fallbackMethod = "fallbackConvertCurrency")
public ResponseEntity<?> convertCurrency(#PathVariable String from, #PathVariable String to,
#PathVariable double quantity) {
logger.info("Inside convertCurrency() :: get Conversion factor ");
FactorResponse fr = cnvFacCl.getConversionFactor(from, to).getBody();
logger.info("{}", fr);
return ResponseEntity.ok(convertServ.getCurrencyConverted(from, to, fr, quantity));
}
#PostMapping(value = "/add_exchange_detail")
#HystrixCommand(fallbackMethod = "fallbackAddConversionFactor",
ignoreExceptions = { FactorNotCreatedException.class,
HttpMessageNotReadableException.class, MissingPathVariableException.class,
TypeMismatchException.class, MethodArgumentNotValidException.class,
ConstraintViolationException.class,
HttpRequestMethodNotSupportedException.class, NotFoundException.class,
FeignException.class},
raiseHystrixExceptions =
{HystrixException.RUNTIME_EXCEPTION} )
public ResponseEntity<?> addConversionFactor(#RequestBody ConversionFactor cf) {
;
logger.info("Inside addConversionFactor() :: add conversion factory for a country ");
List<ConversionFactor> list = cnvFacCl.addConversionFactor(cf).getBody();
return ResponseEntity.ok(list);
}
// ******************************FALLBACK Methods*****************************************
#SuppressWarnings("unused")
private ResponseEntity<?> fallbackConvertCurrency(#PathVariable String from, #PathVariable String to, #PathVariable double quantity) {
return ResponseEntity.ok(new CurrencyConversion(from, to, 0.00, quantity, 0.00));
}
#SuppressWarnings("unused")
private ResponseEntity<?> fallbackAddConversionFactor(#RequestBody ConversionFactor cf){
return ResponseEntity.ok(new ConversionFactor(0000l, "US", "IN", 75.64));
}
} /*
inside exception handler class */
package com.example.demo.exception;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.example.demo.feignClient.model.ApiException;
import feign.FeignException;
//import feign.Response;
#RestControllerAdvice
public class GlobalExceptionHandler {
//incase content is not created due to some internal error
#ExceptionHandler(value = {FactorNotCreatedException.class})
public ResponseEntity<Object> handleFactorNotCreatedException(FactorNotCreatedException ex){
HttpStatus error = HttpStatus.INTERNAL_SERVER_ERROR;
int status = error.value();
ApiException apiException = new ApiException
(
ZonedDateTime.now(ZoneId.of("Asia/Kolkata")),
status,
error,
ex.getMessage()
);
return new ResponseEntity<>(apiException, error);
}
//incase content not found
#ExceptionHandler(value = {NotFoundException.class})
public ResponseEntity<Object> handleNotFoundException(NotFoundException ex){
HttpStatus error = HttpStatus.NOT_FOUND;
int status = error.value();
ApiException apiException = new ApiException
(
ZonedDateTime.now(ZoneId.of("Asia/Kolkata")),
status,
error,
ex.getMessage()
);
return new ResponseEntity<>(apiException, error);
}
#ExceptionHandler(FeignException.class)
public ResponseEntity<Object> handleFeignStatusException(FeignException e, HttpServletResponse response) {
// response.setStatus(e.status());
int status = e.status();
HttpStatus error = HttpStatus.resolve(status);
ApiException apiException = new ApiException
(
ZonedDateTime.now(ZoneId.of("Asia/Kolkata")),
status,
error,
e.getMessage()
);
return new ResponseEntity<>(apiException, error);
}
//incase of updation, constraint voilation (i.e. #PathVariable and #Requestbody)
#ExceptionHandler({
HttpMessageNotReadableException.class,
MissingPathVariableException.class,
TypeMismatchException.class,
MethodArgumentNotValidException.class,
ConstraintViolationException.class,
HttpRequestMethodNotSupportedException.class
})
public ResponseEntity<Object> handleBadRequestException(Exception ex){
HttpStatus error = null;
if(ex instanceof HttpRequestMethodNotSupportedException) {
error = HttpStatus.METHOD_NOT_ALLOWED;
}
else {
error = HttpStatus.BAD_REQUEST;
}
int status = error.value();
ApiException apiException = new ApiException
(
ZonedDateTime.now(ZoneId.of("Asia/Kolkata")),
status,
error,
ex.getMessage()
);
return new ResponseEntity<>(apiException, error);
}
}

Spring Cloud Stream Processor Unit Testing - #Autowire not working

I am trying to write a spring cloud stream processor class that takes an XML in through using the #StreamListener(Processor.INPUT) annotation.
The processor then extracts smaller XML messages and sends them to the output via this.processor.output().send(message);
I have not yet deployed this to dataflow because I wanted to test it with junit. When I run this with junit I can not seem to get my Processor object to instantiate.
I have tried using #Autowired which is how I have seen it done in may examples but I can't seem to get it to work. Any ideas would be appreciated.
My code is below.
package io.spring.dataflow.sample.usagecostprocessor;
import java.io.File;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import lombok.AllArgsConstructor;
#AllArgsConstructor
#EnableBinding(Processor.class)
public class REDACTXMLSplitter {
private Processor processor;
//#Autowired
//private SendingBean sendingBean;
#SuppressWarnings("unchecked")
#StreamListener(Processor.INPUT)
public void parseForREDACTApplications(String redactXML) {
InputSource doc = new InputSource( new StringReader( redactXML ) );
try
{
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
XPathFactory xfactory = XPathFactory.newInstance();
XPath xpath = xfactory.newXPath();
String xpathQuery = "//REDACT/Application";
xpath = xfactory.newXPath();
XPathExpression query = xpath.compile(xpathQuery);
NodeList productNodesFiltered = (NodeList) query.evaluate(doc, XPathConstants.NODESET);
for (int i=0; i<productNodesFiltered.getLength(); ++i)
{
Document suppXml = dBuilder.newDocument();
//we have to recreate the root node <products>
Element root = suppXml.createElement("REDACT");
Node productNode = productNodesFiltered.item(i);
//we append a product (cloned) to the new file
Node clonedNode = productNode.cloneNode(true);
suppXml.adoptNode(clonedNode); //We adopt the orphan :)
root.appendChild(clonedNode);
suppXml.appendChild(root);
//write out files
//At the end, we save the file XML on disk
// TransformerFactory transformerFactory = TransformerFactory.newInstance();
// Transformer transformer = transformerFactory.newTransformer();
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// DOMSource source = new DOMSource(suppXml);
// StreamResult result = new StreamResult(new File("test_" + i + ".xml"));
// transformer.transform(source, result);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(suppXml), new StreamResult(writer));
String output = writer.getBuffer().toString().replaceAll("\n|\r", "");
System.out.println(output);
Message<String> message = (Message<String>) suppXml;
this.processor.output().send(message);
}
}
catch (XPathExpressionException | ParserConfigurationException | TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package io.spring.dataflow.sample.usagecostprocessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class REDACTXMLSplitterApplication {
public static void main(String[] args) {
SpringApplication.run(REDACTXMLSplitterApplication.class, args);
}
}
package io.spring.dataflow.sample.usagecostprocessor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.ResourceUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#DirtiesContext
public class MAIPXMLSplitterApplicationTests {
#Autowired
private Processor myProcessor;
#Test
public void contextLoads() {
}
#Test
public void parseXML() {
try {
String cmErrorPayloadXML = readFile(ResourceUtils.getFile(this.getClass().getResource("/XMLSamples/REDACTApplicationXMLSamples/redact.xml")));
REDACTXMLSplitter redactXMLSplitter = new REDACTXMLSplitter(myProcessor);
redactXMLSplitter.parseForREDACTApplications(cmErrorPayloadXML);
} catch (IOException e) {
e.printStackTrace();
}
}
public String readFile(File file) {
StringBuffer stringBuffer = new StringBuffer();
if (file.exists())
try {
//read data from file
FileInputStream fileInputStream = new FileInputStream(file);
int c;
while ((c = fileInputStream.read()) != -1){
stringBuffer.append((char) c);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuffer.toString();
}
}
Update,
I tried this but myProcessor is still null
package io.spring.dataflow.sample.usagecostprocessor;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ResourceUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MAIPXMLSplitterApplicationTests.TestProcessor.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MAIPXMLSplitterApplicationTests {
#Autowired
private Processor myProcessor;
#Test
public void contextLoads() {
}
#Test
public void parseXML() {
try {
String cmErrorPayloadXML = readFile(ResourceUtils.getFile(this.getClass().getResource("/XMLSamples/MAIPApplicationXMLSamples/354_20191126_MAIP.xml")));
MAIPXMLSplitter maipXMLSplitter = new MAIPXMLSplitter(myProcessor);
maipXMLSplitter.parseForMAIPApplications(cmErrorPayloadXML);
} catch (IOException e) {
e.printStackTrace();
}
}
public String readFile(File file) {
StringBuffer stringBuffer = new StringBuffer();
if (file.exists())
try {
//read data from file
FileInputStream fileInputStream = new FileInputStream(file);
int c;
while ((c = fileInputStream.read()) != -1){
stringBuffer.append((char) c);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuffer.toString();
}
#EnableBinding(Processor.class)
#EnableAutoConfiguration
public static class TestProcessor {
}
}
You need to have #EnableBinding(Processor.class) in one of the configuration classes used by the Test class.
Typically, you can have a simple #Configuration subclass and have it part of the #SpringBootTest classes list. You can see an example here

Atmosphere Resource Per Session

I am unable to establish an Atmosphere Broadcaster per user session for an Atmosphere resource. All I can gather from the documentation is how to build "chat" applications that broadcast the same message to every user.
Is it possible to have the Atmosphere framework establish a channel per user session or do I have to do something and handle these connections myself with an in-memory map?
This is the resource I want:
/websockets/notifications
I want user's A and B to connect to this channel from different browsers and then have the ability to stream them messages independently. I should be able to use their session ID's to have atmosphere understand which person to send the response to.
Does Atmosphere support this?
Relevant POM.xml
<spring-boot-starter-web.version>1.3.3.RELEASE</spring-boot-starter-web.version>
<atmosphere-runtime.version>2.4.4</atmosphere-runtime.version>
<atmosphere-javascript.version>2.3.0</atmosphere-javascript.version>
Atmosphere Configuration
package com.hello;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.atmosphere.cache.UUIDBroadcasterCache;
import org.atmosphere.cpr.ApplicationConfig;
import org.atmosphere.cpr.AtmosphereFramework;
import org.atmosphere.cpr.AtmosphereServlet;
import org.atmosphere.cpr.MetaBroadcaster;
import org.springframework.boot.context.embedded.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class AtmosphereConfiguration implements ServletContextInitializer {
#Bean
public AtmosphereServlet atmosphereServlet() {
return new AtmosphereServlet();
}
#Bean
public AtmosphereFramework atmosphereFramework() {
return atmosphereServlet().framework();
}
#Bean
public MetaBroadcaster metaBroadcaster() {
AtmosphereFramework framework = atmosphereFramework();
return framework.metaBroadcaster();
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
configureAthmosphere(atmosphereServlet(), servletContext);
}
private void configureAthmosphere(AtmosphereServlet servlet, ServletContext servletContext) {
ServletRegistration.Dynamic atmosphereServlet = servletContext.addServlet("atmosphereServlet", servlet);
atmosphereServlet.setInitParameter(ApplicationConfig.ANNOTATION_PACKAGE, "com.hello");
atmosphereServlet.setInitParameter(ApplicationConfig.BROADCASTER_CACHE, UUIDBroadcasterCache.class.getName());
atmosphereServlet.setInitParameter(ApplicationConfig.BROADCASTER_SHARABLE_THREAD_POOLS, "true");
atmosphereServlet.setInitParameter(ApplicationConfig.BROADCASTER_MESSAGE_PROCESSING_THREADPOOL_MAXSIZE, "10");
atmosphereServlet.setInitParameter(ApplicationConfig.BROADCASTER_ASYNC_WRITE_THREADPOOL_MAXSIZE, "10");
servletContext.addListener(new org.atmosphere.cpr.SessionSupport());
atmosphereServlet.addMapping("/websocket/*");
atmosphereServlet.setLoadOnStartup(0);
atmosphereServlet.setAsyncSupported(true);
}
}
Atmosphere Resource
package com.hello;
import java.nio.charset.StandardCharsets;
import org.atmosphere.config.service.Get;
import org.atmosphere.config.service.Disconnect;
import org.atmosphere.config.service.ManagedService;
import org.atmosphere.config.service.Ready;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#ManagedService(path = NotificationAtmosphereResource.PATH)
public class NotificationAtmosphereResource {
public static final String PATH = "/websocket/notifications";
private Logger logger = LoggerFactory.getLogger(NotificationAtmosphereResource.class);
#Get
public void init(AtmosphereResource resource){
resource.getResponse().setCharacterEncoding(StandardCharsets.UTF_8.name());
}
#Ready
public void onReady(final AtmosphereResource resource) {
logger.info("Connected {}", resource.uuid());
}
#Disconnect
public void onDisconnect(AtmosphereResourceEvent event) {
logger.info("Client {} disconnected [{}]", event.getResource().uuid(),
(event.isCancelled() ? "cancelled" : "closed"));
}
}
Service from which I emit Messages
package com.hello;
import org.atmosphere.cpr.MetaBroadcaster;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class NotificationEmitterBean implements NotificationEmitter {
private Logger logger = LoggerFactory.getLogger(NotificationEmitterBean.class);
#Autowired
private MetaBroadcaster metaBroadcaster;
#Autowired
private NotificationService notificationService;
#Autowired
private JsonMapper jsonMapper;
#Override
public void emitNotification(String sessionId, String msg) {
// This will broadcast to all users on /websocket/notifications
// How can I use sessionId to broadcast to the respective browser?
metaBroadcaster.broadcastTo(NotificationAtmosphereResource.PATH,
jsonMapper.toJson(msg));
}
}
}
The only way I was able to get this working was to create my own session based broadcaster. I used ExcludeSessionBroadcaster written by Jeanfrancois Arcand as my baseline.
IncludeSessionBroadcaster.java
package com.hello;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Future;
import org.atmosphere.cpr.AtmosphereConfig;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.Broadcaster;
import org.atmosphere.cpr.BroadcasterFuture;
import org.atmosphere.cpr.DefaultBroadcaster;
import org.atmosphere.cpr.Deliver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An implementation of {#link DefaultBroadcaster} that include one or more {#link AtmosphereResource}
*
* Based on ExcludeSessionBroadcaster written by Jeanfrancois Arcand
*
* #author Steven Zgaljic
*/
public class IncludeSessionBroadcaster extends DefaultBroadcaster {
private static final Logger logger = LoggerFactory.getLogger(IncludeSessionBroadcaster.class);
public IncludeSessionBroadcaster(){}
public Broadcaster initialize(String id, AtmosphereConfig config) {
return super.initialize(id, config);
}
/**
* the AtmosphereResource r will be include for this broadcast
*
* #param msg
* #param r
* #return
*/
#Override
public Future<Object> broadcast(Object msg, AtmosphereResource r) {
if (destroyed.get()) {
throw new IllegalStateException("This Broadcaster has been destroyed and cannot be used");
}
Set<AtmosphereResource> sub = new HashSet<AtmosphereResource>();
sub.removeAll(resources);
sub.add(r);
start();
Object newMsg = filter(msg);
if (newMsg == null) {
return null;
}
BroadcasterFuture<Object> f = new BroadcasterFuture<Object>(newMsg, sub.size());
dispatchMessages(new Deliver(newMsg, sub, f, msg));
return f;
}
/**
* the AtmosphereResources subset will be include for this broadcast
*
* #param msg
* #param subset
* #return
*/
#Override
public Future<Object> broadcast(Object msg, Set<AtmosphereResource> subset) {
if (destroyed.get()) {
return futureDone(msg);
}
subset.retainAll(resources);
start();
Object newMsg = filter(msg);
if (newMsg == null) {
return futureDone(msg);
}
BroadcasterFuture<Object> f = new BroadcasterFuture<Object>(newMsg, subset.size());
dispatchMessages(new Deliver(newMsg, subset, f, msg));
return f;
}
/**
* session will be include for this broadcast
*
* #param msg
* #param s
* #return
*/
public Future<Object> broadcast(Object msg, String sessionId) {
if (destroyed.get()) {
return futureDone(msg);
}
Set<AtmosphereResource> subset = new HashSet<AtmosphereResource>();
for (AtmosphereResource r : resources) {
if (!r.getAtmosphereResourceEvent().isCancelled() &&
sessionId.equals(r.getRequest().getSession().getId())) {
subset.add(r);
break;
}
}
start();
Object newMsg = filter(msg);
if (newMsg == null) {
return futureDone(msg);
}
BroadcasterFuture<Object> f = new BroadcasterFuture<Object>(newMsg, subset.size());
dispatchMessages(new Deliver(newMsg, subset, f, msg));
return f;
}
}
Then I assigned this broadcaster to the Atmosphere resource.
NotificationAtmosphereResource.java
package com.hello;
import java.nio.charset.StandardCharsets;
import org.atmosphere.config.service.Get;
import org.atmosphere.config.service.Disconnect;
import org.atmosphere.config.service.ManagedService;
import org.atmosphere.config.service.Ready;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#ManagedService(path = NotificationAtmosphereResource.PATH,
broadcaster=IncludeSessionBroadcaster.class)
public class NotificationAtmosphereResource {
public static final String PATH = "/websocket/notifications";
private Logger logger = LoggerFactory.getLogger(NotificationAtmosphereResource.class);
#Get
public void init(AtmosphereResource resource){
resource.getResponse().setCharacterEncoding(StandardCharsets.UTF_8.name());
}
#Ready
public void onReady(final AtmosphereResource resource) {
logger.info("Connected {}", resource.uuid());
}
#Disconnect
public void onDisconnect(AtmosphereResourceEvent event) {
logger.info("Client {} disconnected [{}]", event.getResource().uuid(),
(event.isCancelled() ? "cancelled" : "closed"));
}
}
Then I could send message to only the browser (sessionId) that I want.
NotificationEmitterBean.java
package com.hello;
import org.atmosphere.cpr.MetaBroadcaster;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class NotificationEmitterBean implements NotificationEmitter {
private Logger logger = LoggerFactory.getLogger(NotificationEmitterBean.class);
#Autowired
private BroadcasterFactory factory;
#Override
public void emitNotification(String sessionId, String msg) {
((IncludeSessionBroadcaster)factory.lookup(NotificationAtmosphereResource.PATH)).broadcast(msg, sessionId);
}
}
}

How to call a webservice in spring from the jersey client program

I have written the client program using the jersey framework but my webservice is of different project which uses spring framework. So I want to write the webservice using spring . When I wrote it something is going wrong .The webservice is not getting called.
Here is my code
ModelerServiceClient.java is written using jersey
ModelerServiceClient.java
package com.tcs.DataShare.Client;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
//import com.tcs.srl.smart.utility.PropertyReader;
import com.tcs.ngps.sip.modeler.utils.ProductConfiguration;
public class ModelerServiceClient {
static final Logger LOGGER = LoggerFactory
.getLogger(DataShareServiceClient.class);
private WebResource service;
private ClientResponse response;
private String serviceName;
private String vmAddress;
private String portNumber;
private String WAR_FILE_NAME_DATASHARE;
public ModelerServiceClient() {
try {
serviceName = "BPIngestorAppaaS";
vmAddress = ProductConfiguration
.getStringValueForProductProperty("vmAddress");
portNumber = ProductConfiguration
.getStringValueForProductProperty("portNumber");
System.out
.println("vm address:" + vmAddress + "port:" + portNumber);
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WAR_FILE_NAME_DATASHARE = ProductConfiguration
.getStringValueForProductProperty("WAR_FILE_NAME_DATASHARE");
service = client.resource(UriBuilder.fromUri(
"http://" + vmAddress + ":" + portNumber + "/"
+ WAR_FILE_NAME_DATASHARE).build());
System.out.println("war name is: "+WAR_FILE_NAME_DATASHARE);
System.out.println("URL is: "+service);
} catch (NullPointerException nullex) {
LOGGER.error("Error occured - " + nullex.getMessage());
} catch (Exception ex) {
LOGGER.error("" + ex);
}
}
public ModelerServiceClient(String localhost, String port,
String serviceName) {
this.vmAddress = localhost;
this.portNumber = port;
this.serviceName = serviceName;
System.out.println("vm address:" + vmAddress + "port:" + portNumber);
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WAR_FILE_NAME_DATASHARE = ProductConfiguration
.getStringValueForProductProperty("WAR_FILE_NAME_DATASHARE");
service = client.resource(UriBuilder.fromUri(
"http://" + vmAddress + ":" + portNumber + "/" + WAR_FILE_NAME_DATASHARE)
.build());
LOGGER.debug("WAR_FILE_NAME in the client program"+WAR_FILE_NAME_DATASHARE);
System.out.println("In the data share constructor"+WAR_FILE_NAME_DATASHARE);
System.out.println("service is" + service);
}
public HashMap createTable(String folderToBeZipped) {
LOGGER.debug("DataShareServiceClient :: zipFolder() : Calling zipFolderWithSubsequestFolder Service -> folderToBeZipped: "
+ folderToBeZipped);
HashMap map=new HashMap();
LOGGER.debug("before webservice ");
System.out.println("in the create table method in modelerServiceClient class");
response = service.path("dataModeler").path("ModelerService")
.path("createTablesFromEntity")
.type(MediaType.APPLICATION_JSON)
.post(ClientResponse.class, folderToBeZipped);
System.out.println("After calling response,in the create table method in modelerServiceClient class");
LOGGER.debug("INSIDE THE ZIP METHOD FOR CHECKING ZIP METHOD");
LOGGER.debug("after webservice ");
// InputStream inputStream = response.getEntityInputStream();
LOGGER.debug("DataShareServiceClient :: createTable() : Calling createTable() Service done");
return map;
}
}
DataShareCentralController.java is in spring
DataShareCentralController.java
package com.tcs.ngps.sip.restservices.controllers;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import org.apache.log4j.Logger;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import com.tcs.ngps.sip.model.ModelerResponse;
import com.tcs.ngps.sip.modeler.Services.DataIngestionServices;
import com.tcs.ngps.sip.modeler.constants.IngesterConstants;
import com.tcs.ngps.sip.modeler.constants.ModelerConstants;
import com.tcs.ngps.sip.modeler.enumeration.TechnologyServices;
import com.tcs.ngps.sip.modeler.ingester.CreateTableUsingEntityJson;
import com.tcs.ngps.sip.modeler.tracker.StatusActivityTracker;
import com.tcs.ngps.sip.modeler.utils.Utilities;
import com.tcs.ngps.sip.restservices.viewmodels.AnalysisInputModel;
//import com.tcs.ngps.sip.Services.CIServices;
/*
import com.tcs.ngps.sip.Services.SearchServices;
import com.tcs.ngps.sip.commonUtitlities.CommonUtilities;
import com.tcs.ngps.sip.constants.RequestConstants;
import com.tcs.ngps.sip.model.RequestModel;
import com.tcs.ngps.sip.model.ResponceModel;
*/
import com.tcs.ngps.sip.restservices.viewmodels.ResponseModel;
//#Path("/ModelerService")
#RestController
#EnableWebMvc
public class DataShareCentralController {
static Logger logger = Logger.getLogger(ModelerCentralController.class);
DataShareCentralController()
{
System.out.println("In the DataShareCentralController ");
}
// #Path("/createTablesFromEntity")
//#POST
//#Produces("application/json")
#ResponseBody
#RequestMapping(value="/ModelerService/createTablesFromEntity", method= RequestMethod.GET,produces = APPLICATION_JSON_VALUE)
public void CreateTableFromEntity(#Context HttpServletRequest requestObj,String serviceData )
{
System.out.println("done dana done");
JSONParser parser = new JSONParser();
JSONObject object = new JSONObject();
try {
System.out.println("in the controller");
JSONObject serviceJSON = (JSONObject) parser.parse(serviceData);
String datashareURL = (String) serviceJSON
.get(ModelerConstants.DATASHARE_URL);
CreateTableUsingEntityJson createTableUsingEntityJson=new CreateTableUsingEntityJson();
createTableUsingEntityJson.getData();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Please help me in resolving the issue....

Resources