I made a simple REST application using the Vert.x framework server side and Angular 2 (v6.0.9) client side. What I want to do is make the server display the received data. However I can not figure out how to retrieve the HTTP request body: both routingContext.getBodyAsString() and routingContext.getBodyAsJson() returns null. As a temporary solution, I managed to display all the sent data through the path parameters using getParam("data") method. What am I doing wrong?
Server code
package test.post;
import java.util.HashSet;
import java.util.Set;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.Json;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.CorsHandler;
import io.vertx.ext.web.handler.StaticHandler;
public class Server extends AbstractVerticle {
#Override
public void start() throws Exception {
Router router = Router.router(vertx);
Set<String> allowedHeaders = new HashSet<>();
allowedHeaders.add("x-requested-with");
allowedHeaders.add("Access-Control-Allow-Origin");
allowedHeaders.add("origin");
allowedHeaders.add("Content-Type");
allowedHeaders.add("accept");
allowedHeaders.add("X-PINGARUNER");
Set<HttpMethod> allowedMethods = new HashSet<>();
allowedMethods.add(HttpMethod.GET);
allowedMethods.add(HttpMethod.POST);
allowedMethods.add(HttpMethod.OPTIONS);
allowedMethods.add(HttpMethod.DELETE);
allowedMethods.add(HttpMethod.PATCH);
allowedMethods.add(HttpMethod.PUT);
router.route().handler(CorsHandler.create("*").allowedHeaders(allowedHeaders).allowedMethods(allowedMethods));
router.post("/test/post/handler/:data").handler(this::receive);
// Serve the static pages
router.route().handler(StaticHandler.create());
vertx.createHttpServer().requestHandler(router::accept).listen(8080);
System.out.println("Service running");
}
private void receive(RoutingContext routingContext) {
System.out.println("received post request");
System.out.println(routingContext.getBodyAsString());
System.out.println(routingContext.getBodyAsJson());
System.out.println(routingContext.request().getParam("data"));
routingContext.response().putHeader("Content-Type", "application/json").end(Json.encodePrettily("ok"));
}
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
Server service = new Server();
vertx.deployVerticle(service);
}
}
Client app.component.ts code
import { Component } from '#angular/core';
import { RequestService } from './request.service';
#Component({
selector: 'app-root',
template: `
<h2>Click to send post request</h2>
<button type="submit" (click)=makePostRequest()>Send Post Request</button>
`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private requestService: RequestService) { }
makePostRequest() {
this.requestService.sendRequest().subscribe(response => console.log(response));
}
}
Client request.service.ts code
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from "#angular/common/http";
import { catchError, tap } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
export class User {
email: string;
password: string;
address: string;
username: string;
}
#Injectable({
providedIn: 'root'
})
export class RequestService {
constructor(private http: HttpClient) { }
sendRequest(): Observable<any> {
let user = new User();
user.username = 'Admin';
user.email = 'admin#gmail.com';
user.password = 'admin';
user.address = 'somewhere';
console.log(user);
let url = 'http://127.0.0.1:8080/test/post/handler/' + JSON.stringify(user);
let headers = new HttpHeaders({ 'Content-Type': 'application/json' });
let options: { headers, responseType: 'json' };
return this.http.post(url, JSON.stringify(user), options).pipe(
tap(response => console.log(response))
);
}
}
You need to enable body handler in order to read request body, e.g:
router.route("/test/post*").handler(BodyHandler.create());
router.post("/test/post/handler/:data").handler(this::receive);
or enable it globally:
router.route().handler(BodyHandler.create())
Related
I want to add a test for the following e2e scenario:
My app is making a web request to an external service through an internal proxy server, the proxy server manipulates the request body, forwards the request to the desination host and returns the response returned.
Say for example
I do a post request to external.service/an/endpoint (through my-proxy-server) the body
{
"card_number": "<proxy server pls fill the cc details>"
}
The proxy server modifies the request to fill the cc details and forwards it to external.service/an/endpoint with body
{
"card_number": "372735466563005"
}
The external.service returns status OK. proxy server returns the response without modifying.
How do I test this workflow with wiremock? I can do WireMock.stubFor() for external.service, But I don't know how to make wiremock proxy work with the proxy setting of my Webclient.
See the test, actually, Rest Template test, restTemplateWithWireMockAsProxyServer works as expected, routing my requests through the proxy, but the webClientWithWireMockAsProxyServer errors out with my RCA:
20:06:59.165 [qtp105751207-24] DEBUG wiremock.org.eclipse.jetty.server.HttpChannel - REQUEST for //localhost:58978localhost:58978 on HttpChannelOverHttp#4a71ab50{r=1,c=false,c=false/false,a=IDLE,uri=//localhost:58978localhost:58978,age=0}
CONNECT //localhost:58978localhost:58978 HTTP/1.1
Host: localhost:58978
These Calls over wiremock proxy are not possible as mentioned here. But all my urls are like http://localhost:<port>, meaning I am not making any https call.
package com.spotnana.obt.supplier.services;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.http.RequestMethod;
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHeaders;
import org.apache.http.conn.HttpHostConnectException;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.util.SocketUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.ProxyProvider;
#Slf4j
public class SimpleWiremockProxyServerTest {
private final String HOST = "localhost";
private final String MOCK_ENDPOINT = "/my/endpoint";
private WireMockServer targetServer;
private WireMockServer proxyServer;
private WireMock targetWireMock;
private WireMock proxyWireMock;
private String targetBaseUrl;
#Before
public void setup() {
final int targetPort = SocketUtils.findAvailableTcpPort();
this.targetServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(targetPort));
this.targetServer.start();
this.targetWireMock = new WireMock(targetPort);
this.targetWireMock.resetMappings();
this.targetBaseUrl = "http://" + HOST + ":" + targetPort;
final int proxyPort = SocketUtils.findAvailableTcpPort();
this.proxyServer =
new WireMockServer(
WireMockConfiguration.wireMockConfig().port(proxyPort).enableBrowserProxying(true));
this.proxyServer.start();
this.proxyWireMock = new WireMock(proxyPort);
this.proxyWireMock.resetMappings();
}
#After
public void tearDown() throws HttpHostConnectException {
this.targetWireMock.shutdown();
this.targetServer.stop();
try {
this.proxyWireMock.shutdown();
this.proxyServer.stop();
} catch (final Exception ex) {
log.warn("Proxy server is shutdown already");
}
}
#Test
public void restTemplateWithWireMockAsProxyServer() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, this.proxyServer.port()));
requestFactory.setProxy(proxy);
final var reqPatternBuilder =
RequestPatternBuilder.newRequestPattern(
RequestMethod.GET, WireMock.urlEqualTo(MOCK_ENDPOINT));
final var mappingBuilder =
WireMock.get(WireMock.urlEqualTo(reqPatternBuilder.build().getUrl()));
reqPatternBuilder
.withHeader(HttpHeaders.ACCEPT, WireMock.containing(MediaType.APPLICATION_JSON_VALUE))
.withHeader(
HttpHeaders.ACCEPT_CHARSET,
WireMock.containing(StandardCharsets.UTF_8.name().toUpperCase()));
mappingBuilder.willReturn(
WireMock.aResponse()
.withStatus(HttpStatus.OK.value())
.withBody("{ \"success\": true }")
.withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
this.targetWireMock.register(mappingBuilder);
ResponseEntity<String> responseEntity =
new RestTemplate(requestFactory)
.getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, String.class);
Assert.assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
System.out.println("responseEntity: " + responseEntity.getBody());
}
#Test
public void webClientWithWireMockAsProxyServer() {
var client = HttpClient.create()
.tcpConfiguration(
tcpClient ->
tcpClient.proxy(
proxy -> {
proxy
.type(ProxyProvider.Proxy.HTTP)
.host(HOST)
.port(this.proxyServer.port());
}));
var webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(client))
.build();
final var reqPatternBuilder =
RequestPatternBuilder.newRequestPattern(
RequestMethod.GET, WireMock.urlEqualTo(MOCK_ENDPOINT));
final var mappingBuilder =
WireMock.get(WireMock.urlEqualTo(reqPatternBuilder.build().getUrl()));
reqPatternBuilder
.withHeader(HttpHeaders.ACCEPT, WireMock.containing(MediaType.APPLICATION_JSON_VALUE))
.withHeader(
HttpHeaders.ACCEPT_CHARSET,
WireMock.containing(StandardCharsets.UTF_8.name().toUpperCase()));
mappingBuilder.willReturn(
WireMock.aResponse()
.withStatus(HttpStatus.OK.value())
.withBody("{ \"success\": true }")
.withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
this.targetWireMock.register(mappingBuilder);
var response =
webClient.get().uri(this.targetBaseUrl + MOCK_ENDPOINT).exchange().block().bodyToMono(String.class);
response.subscribe(x -> System.out.println("x:" + x));
}
}
I complains with error java.net.UnknownHostException: <proxy server>: nodename nor servname provided, or not known. Is there a way to mock the wiremock proxy server, rather than running an actual server for this. I also want to put validations in the proxy server for request-responses.
Wiremock doesn't support HTTP CONNECT method. You can try Hoverfly as an alternative to Wiremock. There is a github issue if you're interested in details.
I am using Vertx 3.6.3. I am trying to run an HTTPS server verticle, but unfortunately, verticle is not getting deployed. Could you please let me know where I am doing it wrong?
Here is my verticle:
HTTPSVerticle:
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.PfxOptions;
public class HTTPSVerticle extends AbstractVerticle {
#Override
public void start(Future<Void> httpsServerStarted) throws Exception {
int port = config().getJsonObject("http", new JsonObject()).getInteger("port", 8000);
boolean useSsl = config().getJsonObject("http", new JsonObject()).getBoolean("useSsl", false);
String sslCertPath = config().getJsonObject("http", new JsonObject()).getString("sslCertPath", "");
String sslCertPassword = config().getJsonObject("http", new JsonObject()).getString("sslCertPassword", "");
HttpServerOptions httpServerOptions = new HttpServerOptions();
System.out.println(useSsl);
if (useSsl)
httpServerOptions
.setSsl(true)
//.setClientAuth(ClientAuth.REQUIRED)
.setPfxTrustOptions(
new PfxOptions().setPath(sslCertPath).setPassword(sslCertPassword)
);
vertx.createHttpServer(httpServerOptions).requestHandler(httpReq -> {
httpReq.response().end("Hello encrypted world");
}).listen(port, fut -> {
if (fut.succeeded()) {
System.out.println("Verticle now listening on port: " + port);
httpsServerStarted.complete();
}
else {
httpsServerStarted.fail(fut.cause());
System.out.println("Error while starting HTTP server");
}
});
}
}
Here is my test case:
TestHTTPSVerticle:
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.unit.Async;
import io.vertx.ext.unit.TestContext;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(VertxUnitRunner.class)
public class TestHTTPSVerticle {
private static Vertx vertx;
#BeforeClass
public static void setUp(TestContext context) {
DeploymentOptions opts = new DeploymentOptions()
.setConfig(new JsonObject().put("http", new JsonObject()
.put("useSsl", true)
.put("sslCertPath", "test.pfx")
.put("sslCertPassword", "abcd")));
vertx = Vertx.vertx();
vertx.deployVerticle(HTTPSVerticle.class.getName(), opts, context.asyncAssertSuccess());
}
#AfterClass
public static void tearDown(TestContext context) {
vertx.close(context.asyncAssertSuccess());
}
#Test
public void testHttpsServerMessage(TestContext context) {
Async async = context.async();
System.out.println("Connecting to server...");
vertx.createHttpClient().get(8000, "localhost", "/loremipsum", respHandler -> respHandler.bodyHandler(respBody -> {
System.out.println(respBody);
context.assertTrue(respBody.toString().equals("Hello encrypted world"));
async.complete();
})).end();
}
}
Its not letting me submit it without elaborating, so redundant elaboration follows:
I am using vertx config mechanism to fetch port, useSsl, sslCertPath and sslCertPassword
I am using HttpServerOptions for configuring SSL settings for http server
When server is started successfully, it should print Verticle now listening on port: 8000
In case, server fails to start, it should print Error while starting HTTP server
But, It never invokes listen's handler with AsyncResult.
I'm trying to confirm the value of an HTTP response header with Spring 5 WebClient, but only if the web call responds with an HTTP 200 status code. In this use case if authentication is not successful, the API call returns with an HTTP 401 without the response header present. I have the following code below which functionally works, but it is making the web call twice (because I'm blocking twice). Short of just blocking on the HTTP response header only, and putting a try/catch for an NPE when the header isn't present, is there any "cleaner" way to do this?
import java.net.URI;
import java.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import org.springframework.web.reactive.function.client.ExchangeFunctions;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#SpringBootApplication
public class ContentCheckerApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(ContentCheckerApplication.class);
private ExchangeFunction exchange = ExchangeFunctions.create(new ReactorClientHttpConnector());
public static void main(String[] args) {
SpringApplication app = new SpringApplication(ContentCheckerApplication.class);
// prevent SpringBoot from starting a web server
app.setWebApplicationType(WebApplicationType.NONE);
app.run(args);
}
#Bean
public CommandLineRunner myCommandLineRunner() {
return args -> {
// Our reactive code will be declared here
LinkedMultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("username", args[2]);
formData.add("password", args[3]);
ClientRequest request = ClientRequest.method(HttpMethod.POST, new URI(args[0]+"/api/token"))
.body(BodyInserters.fromFormData(formData)).build();
Mono<ClientResponse> mresponse = exchange.exchange(request);
Mono<String> mnewToken = mresponse.map(response -> response.headers().asHttpHeaders().getFirst("WSToken"));
LOGGER.info("Blocking for status code...");
HttpStatus statusCode = mresponse.block(Duration.ofMillis(1500)).statusCode();
LOGGER.info("Got status code!");
if (statusCode.value() == 200) {
String newToken = mnewToken.block(Duration.ofMillis(1500));
LOGGER.info("Auth token is: " + newToken);
} else {
LOGGER.info("Unable to authenticate successfully! Status code: "+statusCode.value());
}
};
}
}
Thanks to comments from #M. Deinum to guide me, I have the following code which is workable now.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import org.springframework.web.reactive.function.client.ExchangeFunctions;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
#SpringBootApplication
public class ContentCheckerApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(ContentCheckerApplication.class);
private ExchangeFunction exchange = ExchangeFunctions.create(new ReactorClientHttpConnector());
public static void main(String[] args) {
SpringApplication app = new SpringApplication(ContentCheckerApplication.class);
// prevent SpringBoot from starting a web server
app.setWebApplicationType(WebApplicationType.NONE);
app.run(args);
}
#Bean
public CommandLineRunner myCommandLineRunner() {
return args -> {
// Change some Netty defaults
ReactorClientHttpConnector connector = new ReactorClientHttpConnector(
options -> options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000)
.compression(true)
.afterNettyContextInit(ctx -> {
ctx.addHandlerLast(new ReadTimeoutHandler(1500, TimeUnit.MILLISECONDS));
}));
LinkedMultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("username", args[2]);
formData.add("password", args[3]);
WebClient webClient = WebClient.builder().clientConnector(connector).build();
Mono<String> tokenResult = webClient.post()
.uri( args[0] + "/api/token" )
.body( BodyInserters.fromFormData(formData))
.exchange()
.onErrorMap(ContentCheckerApplication::handleAuthTokenError)
.map(response -> {
if (HttpStatus.OK.equals(response.statusCode())) {
return response.headers().asHttpHeaders().getFirst("WSToken");
} else {
return "";
}
});
LOGGER.info("Subscribing for the result and then going to sleep");
tokenResult.subscribe(ContentCheckerApplication::handleAuthTokenResponse);
Thread.sleep(3600000);
};
}
private static Throwable handleAuthTokenError(Throwable e) {
LOGGER.error("Exception caught trying to process authentication token. ",e);
ContentCheckerApplication.handleAuthTokenResponse("");
return null;
}
private static void handleAuthTokenResponse(String newToken) {
LOGGER.info("Got status code!");
if (!newToken.isEmpty()) {
LOGGER.info("Auth token is: " + newToken);
} else {
LOGGER.info("Unable to authenticate successfully!");
}
System.exit(0);
}
}
im trying to make an application who cominicates with a server made in spring-boot with websocket.
My server side configuration is the tutorial of spring-boot websocket
package ar.com.sourcesistemas.armController.websocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
}
This is my welcome controller:
package ar.com.sourcesistemas.armController;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class WelcomeController {
// inject via application.properties
#Value("${welcome.message:test}")
private String message = "Hello World";
#RequestMapping("/")
public String welcome(Map<String, Object> model) {
model.put("message", this.message);
return "welcome";
}
}
and this is the broadcaster:
package ar.com.sourcesistemas.armController;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import ar.com.sourcesistemas.armController.pruebas.Greeting;
import ar.com.sourcesistemas.armController.pruebas.HelloMessage;
#Controller
public class ArmController {
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
}
to connect to this websocket im using org.asynchttpclient, and my code is this:
AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
String url = "ws://192.168.0.23:8080/gs-guide-websocket/app/topic/greetings";
AsyncHttpClient c = new DefaultAsyncHttpClient();
WebSocket websocket = c.prepareGet(url)
.execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() {
public void onMessage(String message) {
System.out.println(message);
}
public void onOpen(WebSocket websocket) {
System.out.println("impĀ“rimo websocket");
}
public void onClose(WebSocket websocket) {
System.out.println("ni idea");
}
public void onError(Throwable t) {
}
}).build()).get();
Here i have 2 problems , the first one is :
when i run this program i have an error message in the server side it says "Origin cgeck enabled but transport 'greetings' does not support it".
The second one is:
To made a websocket you have 1 endpoint , in this case is "/gs-guide-websocket", and a broker you can subscribe. All data published in that broker will be broadcasted to all programs subscribed to it. In this case that channel to subscribe will be /app/toppic.
I cant figure out how to subscribe my java desktop application to this message broker.
MORE INFO
I can do this with jquery with this code :
<script src="jquery-3.1.1.min.js"></script>
<script src="sockjs.min.js"></script>
<script src="stomp.min.js"></script>
<script type="text/javascript">
var stompClient = null;
function connect() {
var socket = new SockJS('http://192.168.0.23:8080/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
console.log(JSON.parse(greeting.body).content);
});
});
}
function showGreeting(message) {
$("#greetings").append("<tr><td>" + message + "</td></tr>");
}
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
$( document ).ready(function() {
connect();
});
but i cant reply this in a java desktop class.
As per the documentation of activemq we need to set the http://activemq.apache.org/stomp client-id header to have durable subscriptions.
I set the client-id in connect headers and activemq.subscriptionName in subscription headers as shown below, however I am not seeing the desired behavior. Do we need to set anything on the web socket configuration and message side too?
Here is the subscription code
var headers = {
// additional header
'client-id': 'my-client-id'
};
var subscription_headers = {
// additional header
'activemq.subscriptionName': 'my-client-id'
};
var connect = function () {
var socket = new SockJS( webSocketUrl );
stompClient = Stomp.over( socket );
stompClient.connect( headers, function ( frame ) {
console.log( 'Connected: ' + frame );
stompClient.subscribe( topic, function ( message ) {
.....
.....
}, subscription_headers);
}, function(frame) {
console.log("Web socket disconnected");
});
}
Websocket configuration
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
#Autowired
#Value("${spring.websocket.activemq.relay.host}")
private String relayHost;
#Autowired
#Value("${spring.websocket.activemq.relay.port}")
private int relayPort;
#Autowired
#Value("${spring.activemq.user}")
private String activeMqLogin;
#Autowired
#Value("${spring.activemq.password}")
private String activeMqPassword;
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/queue/", "/topic/")
.setRelayHost(relayHost)
.setRelayPort(relayPort)
.setSystemLogin(activeMqLogin)
.setSystemPasscode(activeMqPassword);
registry.setApplicationDestinationPrefixes("/testbrkr");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/exWs").withSockJS();
}
}
This worked, passing the headers directly in the function as shown
var connect = function () {
var socket = new SockJS( webSocketUrl );
stompClient = Stomp.over( socket );
stompClient.connect( {"client-id": "my-client-id"},, function ( frame ) {
console.log( 'Connected: ' + frame );
stompClient.subscribe( topic, function ( message ) {
.....
.....
}, {"activemq.subscriptionName": "my-client-id"});
}, function(frame) {
console.log("Web socket disconnected");
});
}