Calling a non-static messaging function in java - java

I am trying to send messages from anywhere in my application using STOMP and websockets. However, I am having trouble because I cannot make the "greet" method static because of the "this.template" inside the method. Then I cannot make a call to the method. How can I fix this issue?
Here is my Controller class:
#Controller
public class HelloController {
#Autowired
private SimpMessagingTemplate template;
#Autowired
public HelloController(SimpMessagingTemplate template) {
this.template = template;
}
public HelloController() {
}
public static void replier(String reply) {
greet(reply);
}
#RequestMapping(value="/hello", method=RequestMethod.POST)
public void greet(String greeting) {
Greeting text = new Greeting("Goodbye, " + greeting + "!");
this.template.convertAndSend("/topic/greetings", text);
}
#RequestMapping(value="/", method=RequestMethod.GET)
public String index() {
return "index";
}
#MessageMapping("/hello")
#SendTo("/queue/greetings")
public static Greeting greeting(HelloMessage message) throws Exception {
System.out.println("Sending message...");
beginRoute(message.getName());
return new Greeting("Hello, " + message.getName() + "!");
}
#SendTo("/queue/informer")
public static Greeting beginRoute(String message) {
Application.startBody(message);
//System.out.println("Returning from second message!");
return new Greeting("So long, " + message + "!");
}
The call of greet(reply) in the replier method is invalid because I cannot make a static call to a non-static method. How can I call greet and get the message sent?

I don't understand why you think greeting needs to be static.
I found this on the websocket documentation:
#Controller
public class GreetingController {
#MessageMapping("/greeting") {
public String handle(String greeting) {
return "[" + getTimestamp() + ": " + greeting;
}
}
Try making greeting not static. If you have problems with a nonstatic method please let us know what they are.

Related

NullPointedException when using Spring RestTemplate in Java

I'm using the latest Springframework, and having issues trying to GET an int from my server. All code was writen in Java.
When I interact with the server throught browser everything is OK. And when interacting with the server through the client I'm getting a NullPointerException.
Keep in mind I am a beginner software student.
Server Code (I tried both, works fine when using browser):
public class RestController {
private GameSession gameSession = new GameSession();
#RequestMapping(value = "registerPlayer")
public int registerPlayer(#RequestParam("name") String name, #RequestParam("mode") boolean mode) {
return gameSession.registerPlayer(name, mode);
}
#RequestMapping(value = "registerPlayer/{name}/{mode}")
public int registerPlayer(#PathVariable String name, #PathVariable boolean mode) {
return gameSession.registerPlayer(name, mode);
}
}
Client Code (again tried both, with the same result):
#Component
public class GameSessionClient implements ISeaBattleGame{
#Autowired
private RestOperations restOperations;
private String url;
#Override
public int registerPlayer(String name, boolean singlePlayerMode) {
url = "http://localhost:8080/" + "registerPlayer?name=" + name + "&mode=" + (singlePlayerMode ? 1 : 0);
return restOperations.getForObject(url, int.class);
}
#Override
public int registerPlayer(String name, boolean singlePlayerMode) {
url = "http://localhost:8080/" + "registerPlayer/" + name + "/" + (singlePlayerMode ? 1 : 0);
return restOperations.getForObject(url, int.class);
}
}
RestConfig Code:
#Configuration
public class RestConfig {
#Bean
public RestOperations createRestTemplate(final ClientHttpRequestFactory clientHttpRequestFactory){
return new RestTemplate(clientHttpRequestFactory);
}
#Bean
public ClientHttpRequestFactory clientHttpRequestFactory(#Value("${connect.timeout}") final int connectTimeout, #Value("${read.timeout}") final int readTimeout){
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpComponentsClientHttpRequestFactory.setReadTimeout(readTimeout);
httpComponentsClientHttpRequestFactory.setConnectTimeout(connectTimeout);
return httpComponentsClientHttpRequestFactory;
}
}
App Code:
#SpringBootApplication
public class App implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
#Autowired
private GameSessionClient gameSessionClient;
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) throws Exception {
int playerNr = gameSessionClient.registerPlayer("test", true);
logger.info("Response: {}", playerNr);
}
}
The return restOperations.getForObject(url, int.class); results in a java.lang.NullPointerException
url: http://localhost:8080/registerPlayer/test/1 or http://localhost:8080/registerPlayer?name=test&mode=1 both result in 1 when using my browser
Any help would be much appreciated, as I'm getting pretty confused from this.
Update you code to below..will remove the NullPointer Exception your getting:
#Bean
public RestOperations restOperations(final ClientHttpRequestFactory clientHttpRequestFactory){
return new RestTemplate(clientHttpRequestFactory);
}
and do this , instead of "Application.class":
public static void main(String[] args){
SpringApplication.run(App.class, args);
}

How to get the Message Id from a Spring Listener

I have the following code:
#JmsListener(destination = "myQueue", containerFactory = "myFactory")
public void receiveMessage(MyClass message) {
service.process(message);
}
Now, I want to obtain the jms message id. I know I can override the MappingJackson2MessageConverter class to do this, but is it possible to do it in a simpler way, like with a second argument on the method?
Use the #Header annotation:
#SpringBootApplication
public class So46794317Application {
public static void main(String[] args) {
SpringApplication.run(So46794317Application.class, args);
}
#Bean
public ApplicationRunner runner(JmsTemplate template) {
return args -> template.convertAndSend("foo", "bar");
}
#JmsListener(destination = "foo")
public void receive(String in, #Header(JmsHeaders.MESSAGE_ID) String messageId) {
System.out.println(in + ", id:" + messageId);
}
}
Result:
bar, id:ID:host.local-50513-1508260336349-4:2:1:1:1

Spring websocket - how to get number of sessions

I'm using this tutorial and I'm trying to figure out how to get the number of current sessions.
My WebSocketConfig looks like this (copy and paste from the tutorial) :
#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();
}
}
I'd like to know the number of sessions inside of this class (again copy and paste):
#Controller
public class GreetingController {
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
}
Is there an easy way to get the number of current sessions(users, connections) to the websocket?
Edit:
Here is my solution:
Set<String> mySet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
#EventListener
private void onSessionConnectedEvent(SessionConnectedEvent event) {
StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
mySet.add(sha.getSessionId());
}
#EventListener
private void onSessionDisconnectEvent(SessionDisconnectEvent event) {
StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
mySet.remove(sha.getSessionId());
}
I can now get the number of Sessions with mySet.size() .
You can use SimpUserRegistry and its getUserCount() method instead of handling connections manually.
Example:
#Autowired
private SimpUserRegistry simpUserRegistry;
public int getNumberOfSessions() {
return simpUserRegistry.getUserCount();
}
You can use ApplicationContext events. Every connection, subscription or other action will fire a special event: SessionConnectEvent, SessionConnectedEvent, SessionSubscribeEvent and so on.
Full doc is here. When one of these events fires, you can handle it with your own logic.
Sample code for reference:
#EventListener(SessionConnectEvent.class)
public void handleWebsocketConnectListner(SessionConnectEvent event) {
logger.info("Received a new web socket connection : " + now());
}
#EventListener(SessionDisconnectEvent.class)
public void handleWebsocketDisconnectListner(SessionDisconnectEvent event) {
logger.info("session closed : " + now());
}

Spring Boot AOP

I am having some issues trying to get my advice to execute. I tried several different pointcuts to no avail. The "#EnableAspectJProxy" seems to be working and detects my aspect. Any advice is appreciated.
I am using spring-boot-aop-starter.
#Aspect
#Component
public class ExecutionTimeLogger {
private Logger logger;
public ExecutionTimeLogger() {
logger = LoggerFactory.getLogger(getClass());
logger.info("HEY");
}
#Pointcut("within(#org.springframework.stereotype.Controller *)")
public void controller() {}
#Pointcut("execution(* edu.x.y.z.server.web.controller.*.*(*))")
public void methodPointcut() {}
#Pointcut("within(#org.springframework.web.bind.annotation.RequestMapping *)")
public void requestMapping() {}
#Around("controller() && methodPointcut() && requestMapping()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
StopWatch sw = new StopWatch();
String name = pjp.getSignature().getName();
try {
sw.start();
return pjp.proceed();
} finally {
sw.stop();
logger.info("STOPWATCH: " + sw.getTime() + " - " + name);
}
}
}
I am trying to match any method that is within my package and is annotated with the #RequestMapping annotation. I have tried the very generic match any and all methods without any luck too.
Here is a sample of a method that the advice should be applied to:
#RequestMapping(value = "/analysis", method = RequestMethod.GET)
#ApiOperation(value = "Get analyses available for the current user")
JsonModelAndView getAllAnalyses(HttpServletRequest request)
I managed to get this resolved. I ended up creating a small spring application to test the use case with the specific pointcuts to remove other potential barriers. I found that my pointcuts needed some adjusting.
#Aspect
#Component
public class ExecutionTimeLogger {
private Logger logger;
public ExecutionTimeLogger() {
logger = LoggerFactory.getLogger(getClass());
logger.info("HEY");
}
#Pointcut("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void requestMapping() {}
#Pointcut("execution(* edu.x.y.z.server.web.controller.*Controller.*(..))")
public void methodPointcut() {}
#Around("requestMapping() && methodPointcut()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
StopWatch sw = new StopWatch();
String name = pjp.getSignature().getName();
try {
sw.start();
return pjp.proceed();
} finally {
sw.stop();
logger.info("STOPWATCH: " + sw.getTime() + " - " + name);
}
}
}
As you can see the big difference was the annotation pointcut.
You might want to set proxyTargetClass=true (assuming your controllers do not have an interface). Use your own #EnableASpectJAutoProxy or set spring.aop.proxyTargetClass=true.

How to pass object in arguments in RMI method?

I am trying to add arguments in RMI method. When I add e.g. String everything works fine. But I am not sure if I can pass an object I created. I am new to RMI so my code is very simple:
HelloIF
public interface HelloIF extends Remote {
String greeting(Context c) throws RemoteException;
}
Hello
public class Hello extends UnicastRemoteObject implements HelloIF {
public Hello() throws RemoteException {
}
public String greeting(Context c) throws RemoteException {
addToContext(c);
report(c);
return "greeting";
}
void addToContext(Context c) {
c.addID(Thread.currentThread().getId());
}
void report(Context c) {
System.out.println("Hello.greeting() thread : "
+ Thread.currentThread().getName() + " "
+ Thread.currentThread().getId());
System.out.println("Hello.greeting() context : "
+ c.getDistributedThreadName() + " " + c.getRequestType());
}
}
RMIServer
public class RMIServer {
public static void main(String[] args) throws RemoteException, MalformedURLException {
LocateRegistry.createRegistry(1099);
HelloIF hello = new Hello();
Naming.rebind("server.Hello", hello);
System.out.println("server.RMI Server is ready.");
System.out.println("RMIServer.main() thread : " + Thread.currentThread().getName()
+ " " + Thread.currentThread().getId());
}
}
RMIClient
public class RMIClient {
public static void main(String[] args) throws RemoteException, MalformedURLException, NotBoundException {
Context context = new Context("request1", Thread.currentThread().getName()+System.currentTimeMillis());
Registry registry = LocateRegistry.getRegistry("localhost");
HelloIF hello = (HelloIF) registry.lookup("server.Hello");
System.out.println(hello.greeting(context));
System.out.println("RMIClient.mian() thread : " + Thread.currentThread().getName()
+ " " + Thread.currentThread().getId());
}
}
and finally my class Context
public class Context
{
private String requestType;
private String distributedThreadName;
private List<Long> IDList;
(...) getters/setters
}
What should I do to make passing Context possible?
Your object should implement Serializable. As I can see this would be one problem. It is needed because the communication between both parts is done using serialization, so each object that needs to be sent to the other part, needs to be an instance of class implementing Serializable.
public class Context implements Serializable
{
private String requestType;
private String distributedThreadName;
private List<Long> IDList;
(...) getters/setters
}
and please add a serialVersionUID as a good practice. Something like:
private static final long serialVersionUID = 20120731125400L;

Categories