I am following the instructions in the official documentation of Play framework 2.5.x to Java Websockets, I created a controller with this function
public static LegacyWebSocket<String> socket() {
return WebSocket.withActor(MyWebSocketActor::props);
}
And an Actor class MyWebSocketActor:
public class MyWebSocketActor extends UntypedActor {
public static Props props(ActorRef out) {
return Props.create(MyWebSocketActor.class, out);
}
private final ActorRef out;
public MyWebSocketActor(ActorRef out) {
this.out = out;
}
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
out.tell("I received your message: " + message, self());
}
}
}
Then the app is started I try to connect at ws://localhost:9000 as is written in the official documentation:
Tip: You can test your WebSocket controller on
https://www.websocket.org/echo.html. Just set the location to
ws://localhost:9000.
But the web socket seems unreachable, how can I test it?
Thanks
In order to handle WebSocket connections, you also have to add a route in your routes file.
GET /ws controllers.Application.socket()
Then your WebSocket endpoint will be ws://localhost:9000/ws - use it for testing with the echo service.
Finally with the help of Anton I solved it!
First: remove static from socket() method
public LegacyWebSocket<String> socket() {
return WebSocket.withActor(MyWebSocketActor::props);
}
Then add an endpoint in routes file for the socket() method
GET /ws controllers.HomeController.socket()
At this point you have to start the application with SSL/TLS in this way, for example:
activator run -Dhttps.port=9443
In websocket.org/echo.html insert wss://localhost:9443/ws in Location field and it connects to websocket!
Furthermore if I visit https://localhost:9443/ws I continue to obtain the message
Upgrade to WebSocket required
Related
I am trying to set up server sent events in a Java server with the OutboundSseEvent class. I'm not sure why my code keeps throwing a null pointer exception. I am using these tutorials as reference.
https://www.baeldung.com/java-ee-jax-rs-sse and https://www.programcreek.com/java-api-examples/index.php?api=javax.ws.rs.sse.OutboundSseEvent
#Path("ssetest")
public class SSETestService extends SecureService {
private Sse sse;
#GET
#Path("/test")
#Produces("text/event-stream")
public void SSETestService(#Context Sse sse, SseEventSink sseEventSink)
throws InterruptedException, IllegalArgumentException {
OutboundSseEvent stringEvent = sse.newEventBuilder()
.name("ping")
.data("hello world").build();
sseEventSink.send(stringEvent);
}
}
On the client side...
testSSE() {
console.log("in testSSE()");
const evtSource = new EventSource(
"http://localhost:8081/api/ssetest/test"
);
evtSource.onmessage = function(event) {
console.log("received message");
console.log("event.data: " + event.data);
};
evtSource.addEventListener("ping", function(event) {
console.log("event.data: " + event.data);
console.log("received ping event");
});
evtSource.onerror = function(err) {
console.error("EventSource failed:", err);
};
}
Thanks for any pointers.
The instance sse is null. For litmus like test, you can print sse to see. If you using Spring framework private Sse sse; should be autowired as follows
#Autowired
private Sse sse;
I think the parameter #Context Sse sse should be removed as you have already defined in the class.
I'm not sure where exactly your null pointer occurs, but in my case it was because injection of the Sse and SseEventSink instances failed. In that case, an implementation of the SSE feature is missing on your classpath. You could use:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-sse</artifactId>
<version>3.4.5</version>
</dependency>
Furthermore, you need to make sure that your servlet allows asynchronous communication by enabling that setting, e.g.:
#WebServlet(... asyncSupported = true, ...)
...
public class MyServlet {
...
I'm using wiremock in to mock external operator response in integration test:
#ClassRule
public static WireMockClassRule zainWireMockStatic = new WireMockClassRule(9900);
and getting this exception
requesting to java.net.SocketTimeoutException: connect timed out timed out
This is my wiremock
private static void wireMockZainUnSubscriptionRequest() {
zainWireMockStatic.stubFor(get(urlPathMatching("/api/unsubscribe")).willReturn(
aResponse().withStatus(200).withHeader("Content-Type", "application/json")
.withBody(FileUtils.readFileFromClasspath(
"data/mocks/zain_unsubscribe_success_response.json"))));
}
and this is my test
#Test
public void unsubscribeUserWithSuccessResponse() {
wireMockZainUnSubscriptionRequest();
given().body(FileUtils.readFileFromClasspath("data/message/unsubscribe_request.json"))
.contentType(ContentType.JSON).post(UNSUBSCRIBE_API).then().statusCode(200)
.body("user_id", equalTo(USER_ID));
}
The problem is that the Spring Boot runner starts and stops its servlet container once per class. If you use the WireMock rule as you have it starts and stops once per test method. This means that the pooled connections in the Spring app are rendered invalid between test cases.
You have three options to fix this:
Switch to the Spring team's WireMock integration: http://cloud.spring.io/spring-cloud-static/spring-cloud-contract/1.1.2.RELEASE/#_spring_cloud_contract_wiremock
Switch to using #ClassRule so that WireMock starts and stops per test class.
Configure your Spring HTTP client to detect and discard dead pooled connections. An advantage of this option is that your app will be more resilient to failovers in the production system, as many load balancers/reverse proxies/floating IPs will exhibit similar behaviour.
Hi I had the same problem, and I followed the advice of bernyfox on the github and solve the problem.
My problem was with the http client it reports the SocketTimeout. The proposed solution is to tell the httpclient the connection will be close with an extension.
I made this one:
public class ConnectionCloseExtension extends ResponseTransformer {
#Override
public ResponseDefinition transform(Request request, ResponseDefinition response, FileSource files) {
HttpHeaders headersWithClose;
HttpHeader closeHeader = new HttpHeader("Connection", "Close");
if(response.getHeaders()!=null){
headersWithClose = HttpHeaders.copyOf(response.getHeaders())
.plus(closeHeader);
}else{
headersWithClose = new HttpHeaders(closeHeader);
}
response.setHeaders(headersWithClose);
return response;
}
#Override
public String name() {
return "ConnectionCloseExtension";
} }
and to apply it:
#Rule
public WireMockRule wireMockServer = new WireMockRule(wireMockConfig()
.extensions(new ConnectionCloseExtension()));
Environment
Spring Boot: 1.5.13.RELEASE
Cloud: Edgware.SR3
Cloud AWS: 1.2.2.RELEASE
Java 8
OSX 10.13.4
Problem
I am trying to write an integration test for SQS.
I have a local running localstack docker container with SQS running on TCP/4576
In my test code I define an SQS client with the endpoint set to local 4576 and can successfully connect and create a queue, send a message and delete a queue. I can also use the SQS client to receive messages and pick up the message that I sent.
My problem is that if I remove the code that is manually receiving the message in order to allow another component to get the message nothing seems to be happening. I have a spring component annotated as follows:
Listener
#Component
public class MyListener {
#SqsListener(value = "my_queue", deletionPolicy = ON_SUCCESS)
public void receive(final MyMsg msg) {
System.out.println("GOT THE MESSAGE: "+ msg.toString());
}
}
Test
#RunWith(SpringRunner.class)
#SpringBootTest(properties = "spring.profiles.active=test")
public class MyTest {
#Autowired
private AmazonSQSAsync amazonSQS;
#Autowired
private SimpleMessageListenerContainer container;
private String queueUrl;
#Before
public void setUp() {
queueUrl = amazonSQS.createQueue("my_queue").getQueueUrl();
}
#After
public void tearDown() {
amazonSQS.deleteQueue(queueUrl);
}
#Test
public void name() throws InterruptedException {
amazonSQS.sendMessage(new SendMessageRequest(queueUrl, "hello"));
System.out.println("isRunning:" + container.isRunning());
System.out.println("isActive:" + container.isActive());
System.out.println("isRunningOnQueue:" + container.isRunning("my_queue"));
Thread.sleep(30_000);
System.out.println("GOT MESSAGE: " + amazonSQS.receiveMessage(queueUrl).getMessages().size());
}
#TestConfiguration
#EnableSqs
public static class SQSConfiguration {
#Primary
#Bean(destroyMethod = "shutdown")
public AmazonSQSAsync amazonSQS() {
final AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration("http://127.0.0.1:4576", "eu-west-1");
return new AmazonSQSBufferedAsyncClient(AmazonSQSAsyncClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("key", "secret")))
.withEndpointConfiguration(endpoint)
.build());
}
}
}
In the test logs I see:
o.s.c.a.m.listener.QueueMessageHandler : 1 message handler methods found on class MyListener: {public void MyListener.receive(MyMsg)=org.springframework.cloud.aws.messaging.listener.QueueMessageHandler$MappingInformation#1cd4082a}
2018-05-31 22:50:39.582 INFO 16329 ---
o.s.c.a.m.listener.QueueMessageHandler : Mapped "org.springframework.cloud.aws.messaging.listener.QueueMessageHandler$MappingInformation#1cd4082a" onto public void MyListener.receive(MyMsg)
Followed by:
isRunning:true
isActive:true
isRunningOnQueue:false
GOT MESSAGE: 1
This demonstrates that in the 30 second pause between sending the message the container didn't pick it up and when I manually poll for the message it is there on the queue and I can consume it.
My question is, why isn't the listener being invoked and why is the isRunningOnQueue:false line suggesting that it's not auto started for that queue?
Note that I also tried setting my own SimpleMessageListenerContainer bean with autostart set to true explicitly (the default anyway) and observed no change in behaviour. I thought that the org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration#simpleMessageListenerContainer that is set up by #EnableSqs ought to configure an auto started SimpleMessageListenerContainer that should be polling for me message.
I have also set
logging.level.org.apache.http=DEBUG
logging.level.org.springframework.cloud=DEBUG
in my test properties and can see the HTTP calls create the queue, send a message and delete etc but no HTTP calls to receive (apart from my manual one at the end of the test).
I figured this out after some tinkering.
Even if the simple message container factory is set to not auto start, it seems to do its initialisation anyway, which involves determining whether the queue exists.
In this case, the queue is created in my test in the setup method - but sadly this is after the spring context is set up which means that an exception occurs.
I fixed this by simply moving the queue creation to the context creation of the SQS client (which happens before the message container is created). i.e.:
#Bean(destroyMethod = "shutdown")
public AmazonSQSAsync amazonSQS() {
final AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration("http://localhost:4576", "eu-west-1");
final AmazonSQSBufferedAsyncClient client = new AmazonSQSBufferedAsyncClient(AmazonSQSAsyncClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("dummyKey", "dummySecret")))
.withEndpointConfiguration(endpoint)
.build());
client.createQueue("test-queue");
return client;
}
I upgraded to camel 2.16 and one of my route Unit Tests started failing.
Here is my route definition:
public class Route extends RouteBuilder{
#Override
public void configure() throws Exception {
from(start).enrich("second");
from("direct:second")
.log(LoggingLevel.DEBUG, "foo", "Route [direct:second] started.");
}
}
Here is my test:
#RunWith(MockitoJUnitRunner.class)
public class RouteTest extends CamelTestSupport {
private Route builder;
#Produce(uri = "direct:start")
protected ProducerTemplate template;
#Before
public void config() {
BasicConfigurator.configure();
}
#Override
protected RouteBuilder createRouteBuilder() {
builder = new Route();
return builder;
}
#Override
protected CamelContext createCamelContext() throws Exception {
SimpleRegistry registry = new SimpleRegistry();
return new DefaultCamelContext(registry);
}
#Test
public void testPrimeRouteForSubscriptionId() {
Exchange exchange = ExchangeBuilder.anExchange(new DefaultCamelContext()).build();
exchange.getIn().setBody(new String("test"));
template.send(exchange);
}
}
The error I'm getting when I run the test is:
org.apache.camel.component.direct.DirectConsumerNotAvailableException: No consumers available on endpoint: Endpoint[direct://second]. Exchange[][Message: test]
Worthy of note is the following line in the camel 2.16 notes:
http://camel.apache.org/camel-2160-release.html
The resourceUri and resourceRef attributes on and has been removed as they now support a dynamic uris computed from an Expression.
Thanks in advance for any help.
Swap the order so the the direct route is started before the enrich.
http://camel.apache.org/configuring-route-startup-ordering-and-autostartup.html
Or use seda instead of direct in your unit test: http://camel.apache.org/seda
Or use ?block=true in the direct uri to tell Camel to block and wait for a consumer to be started and ready before it sends a message to it: http://camel.apache.org/direct
This is a somewhat old issue, but since i pulled out most of my hair out last night, trying to figure out why it was ok to use to("direct:myEndpoint") but not enrich("direct:myEndpoint"), I'll post the answer anyway - maybe it'll save somebody else from getting bald spots ;-)
It turns out to be a test-issue. In case of Direct endpoints, enrich checks whether there is a running route in the context before passing the Exchange to it, but it does so by looking at the CamelContext held by the Exchange it is currently handling. Since you passed your ProducerTemplate an Exchange what was created with a new DefaultCamelContext(), it has no "direct:second" route available.
Luckily there is a couple of simple solutions. Either create the Exchange using the CamelContext from CamelTestSupport, or use the ProducerTemplate sendBody(...) method instead:
#Test
public void testWithSendBody() {
template.sendBody(new String("test"));
}
#Test
public void testPrimeRouteForSubscriptionId() {
Exchange exchange = ExchangeBuilder.anExchange(context()).build();
exchange.getIn().setBody(new String("test"));
template.send(exchange);
}
The blueprint test keeps throwing exception, No Consumers available.
My scenario was that I have an osgi svc which exposes a method which can be called from any another osgi svc.
So the exposed svc method makes a call to a direct:
#EndpointInject(uri = "direct-vm:toRestCall")
ProducerTemplate toRestCall;
svcMethod(Exchange xch){
exchange.setOut(
toRestCall.send("seda:toDirectCall", xch -> {
try{
xch.getIn().setBody("abc");
}catch (Exception ex){
ex.getMessage();
}
}
}).getIn());
And when I tested the direct that it calls, Blueprint advice with JUnit used to keep throwing the following exception:
org.apache.camel.component.direct.DirectConsumerNotAvailableException:
No consumers available on endpoint: Endpoint. Exchange[Message: {..........
I'm rather new to programming in the Java EE environment, so this question will probably sound amateurish, but here goes:
I'm writing a simple JMS application for demonstration purposes. One of the features that has to be implemented is the ability to get messages from a topic after setting a message selector in a dynamic manner, menaing the user has to be able to set certain attributes that will determine whether he gets a message or not. The messages are sent from a different application that is running on the same local server as the application that is receiving the messages.
So, I'm using injected JMSContext components on both the sender side and on the receiver side to handle the messaging itself.
Here are the functions for sending
#Inject
#JMSConnectionFactory("jms/myConnectionFactory")
JMSContext context;
#Resource(lookup = "jms/myTopic")
private Topic topic;
//some more code
public void produceTopicForCreate(Object obj) {
ObjectMessage message = contextCreate.createObjectMessage(obj);
try {
//setting properties
} catch (JMSException ex) {
//logging
}
context.createProducer().send(topic, message)
}
And on the receiver side
#Inject
#JMSConnectionFactory("jms/myConnectionFactory")
private JMSContext context;
#Resource(lookup = "jms/myTopic")
private Topic topic
private JMSConsumer consumer;
private List<MyClass> listOfMessages;
//more code
public void subscribe(String selector) {
this.consumer = this.context.createDurableConsumer(topic, "durableClient", selector, false);
}
public void receiveMessage() {
try {
this.listOfMessages.add(this.consumer.receiveBody(MyClass.class));
} catch (Exception e) {
//logging
}
}
So, as you can see, I have created a durable consumer to consume messages from the topic. Now, whenever I try to invoke the receiveMessage method after a message has been sent to the topic, I get an exception, stating that the "Producer is closed". I looked all over the net, but found no indication as to what is the problem.
If anyone here could help in any way, I would greatly appreciate it! Thanks in advance!
Some important details:
the bean that is doing the sending is RequestScoped in app A
the bean that is doing the receiving is a Singleton the implements
the the environment is GlassFish 4.1/NetBeans 8.1