22

I want to connect to a Sonic Broker Topic and Listen for any incoming XML message. I did something like below;

Application.java

@SpringBootApplication
@ComponentScan({"com.mainpack", "com.msgpack.jms"})
@EnableJms
public class Application extends SpringBootServletInitializer {

@Autowired
private JmsTopicListener jmsTopicListener;

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(Application.class);
}

@Override
public void onStartup(final ServletContext servletContext) throws ServletException {
    try {
        LogService.info(Application.class.getName(), "Starting Service...");
        super.onStartup(servletContext);
        jmsTopicListener.listenMessage();
        LogService.info(Application.class.getName(), "Service Started");
    } catch (Exception ex) {
        LogService.error(this.getClass().getName(), ex);
    }
}

public static void main(String[] args) {
    ApplicationContext context = SpringApplication.run(Application.class, args);
    LogService.info(Application.class.getName(), "Service Started...");
 }
}

JmsTopicListener.java

@Component
public class JmsTopicListener {

@Autowired
private ApplicationProperties properties;

@Autowired
private MsgListener msgListener;

public void listenMessage() {
    TopicConnectionFactory factory;
    TopicConnection connection = null;
    LogService.info(this.getClass().getName(), "Registering Broker Connection");
    try {
        factory = new progress.message.jclient.TopicConnectionFactory(properties.getBrokerURL());
        connection = factory.createTopicConnection(properties.getUserName(), properties.getPass());

        javax.jms.TopicSession subSession = (TopicSession) connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

        javax.jms.Topic topic = subSession.createTopic(properties.getTopicName());
        MessageConsumer subscriber = subSession.createSubscriber(topic);
        subscriber.setMessageListener(msgListener);
        connection.start();
        LogService.info(this.getClass().getName(), "Broker connected");
    } catch (Exception ex) {
        LogService.error(this.getClass().getName(), ex);
    }
 }
}

MsgListener.java

@Component
public class MsgListener implements MessageListener {

@Override
public void onMessage(Message msg) {
    if (msg instanceof XMLMessage) {
        try {
            XMLMessage m = (XMLMessage) msg;
            if (m.getText().contains("Applications")) {
                LogService.info(this.getClass().getName(), "Recieved A Applications Message");
            } else {
                LogService.info(this.getClass().getName(), "Recieved Message Does not contain Applications Tag");
            }
        } catch (Exception ex) {
            LogService.info(this.getClass().getName(), "Exception: " + ex.getMessage());
        }
    }
 }
}

When, i run this code i get nullPointer at line jmsTopicListener.listenMessage() in Application.java.

What mistake i have made here? Is there a way i can improve this (I mean get the work done in less code maybe)?.

NOTE: com.mainpack have classes Application.java and ApplicationProp.java com.msgpack.jms have JmsTopicListener.java and MsgListner.java

Error From Logger:

ERROR [2015-07-14 14:34:52] [com.mainpack.Application] [localhost-startStop-1] - [Exception: ]java.lang.NullPointerException
    at com.mainpack.Application.onStartup(Application.java:33)
    at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5156)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:945)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1768)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Rajkishan Swami
  • 3,569
  • 10
  • 48
  • 68
  • can you print the full stack trace here – kuhajeyan Jul 14 '15 at 08:23
  • 1
    @kbird : Added the stack trace. Please see updated post. I get this in logger when i start the service in tomcat. Then nothing happens. Service doesn't run further. – Rajkishan Swami Jul 14 '15 at 09:08
  • As `@SpringBootApplication` is just a shortcut for `@Configuration`, `@EnableAutoConfiguration` and `@ComponentScan` this might already be your issue. You are trying to access an `@Autowired` resource in your Application class which is neither `@Component`, `@Service`, ... that would qualify for management by Spring and inject dependencies, afair. You should double check by running in --debug mode. – daniel.eichten Jul 14 '15 at 10:54
  • @hrrgttnchml : I have checked removing `@SpringBootApplication`, and adding `@Configuration`, `@EnableAutoConfiguration`. Same Exception. I dont understand why spring cannot `Autowire` that bean, cause `JmsTopicListener` is annotated with `@Component` already. – Rajkishan Swami Jul 14 '15 at 10:58
  • @Rajkishan: Yes, it is nice that you do have JmsTopicListener annotated with `@Component` but you also need to make the Application.class be aware that dependencies should be injected. `@Configuration` is as far as I remember not sufficient. You should also annotate it with `@Component`. But be aware of side effects. – daniel.eichten Jul 14 '15 at 11:01

2 Answers2

40

onStartup is called by the servlet container very early in your application's lifecycle and is called on an instance of the class that was created by the servlet container, not Spring Boot. This is why jmsTopicListener is null.

Rather than overriding onStartup you could use a method annotated with @PostConstruct. It will be called by Spring once it's created an instance of Application and injected any dependencies:

@SpringBootApplication
@ComponentScan({"com.mainpack", "com.msgpack.jms"})
@EnableJms
public class Application extends SpringBootServletInitializer {

    @Autowired
    private JmsTopicListener jmsTopicListener;

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    @PostConstruct
    public void listen() { 
        jmsTopicListener.listenMessage();
    }

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Application.class, args);
        LogService.info(Application.class.getName(), "Service Started...");
    }
}
Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • When i deploy the application on tomcat, it doesnot use the `main()`. So i used the `onStartUp()` to give the `"Application Service Started Message"` on tomcat. If i dont use `onStartUp()`, is there a way i can give the message like `"My Service Name" starting/started (successfully)` or something similar? – Rajkishan Swami Jul 14 '15 at 12:13
  • 2
    Thank You. It works fine after i added the `@PostConstruct`. – Rajkishan Swami Jul 14 '15 at 12:59
  • Various events are published when the application starts. See the [javadoc](http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/event/package-summary.html) for some more details. You could listen for one (or more) of those. Doing so would work for either way of starting your application. – Andy Wilkinson Jul 14 '15 at 15:07
  • Thank you. It helped me a lot – Kiran Kulkarni Dec 28 '15 at 06:36
  • I added @PostConstruct it prints my value to console but when I open up local host I receive a null value? – JayC Dec 07 '16 at 16:20
2

Just add

@PostConstruct

method, and run the code from this method, it will work.

Ziaullhaq Savanur
  • 1,848
  • 2
  • 17
  • 20