Joey Cote
Joey Cote

Reputation: 362

How to launch CommandLineRunner from Spring Controller

I have a main Spring Boot application in the top-level package that I launch, with different controllers in the children packages:

i.e.

ca.example.batch.MainBatchApplication
ca.example.batch.job1.Job1Controller (/batch/startJob1)
ca.example.batch.job2.Job2Controller (/batch/startJob2)

I am able to start the Spring Batches by going to the URL: http://localhost:8080/batch/startJob1 or http://localhost:8080/batch/startJob2.

However, in another package I have:

ca.example.batch.job3.Job3Controller
ca.example.batch.job3.Job3Application

... which is not a Spring Batch, but a Spring CommandLineRunner. I want to know if there is a way to launch MainBatchApplication without starting that CommandLineRunner automatically, but run it through the controller, i.e. http://localhost:8080/batch/startJob3.

The controller code I am looking at is:

package ca.example.batch.job3;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class Job3Controller {

    @RequestMapping("/batch/startJob3")
    public String handle() throws Exception {

        Job3Application app = new Job3Application();

        Logger logger = LoggerFactory.getLogger(this.getClass());

        logger.info("app: " + app);

        String args = "";
        app.run(args);

        return "COMPLETE";
    }
}

Job3Application is:

package ca.example.batch.job3;

import static java.lang.System.exit;
import java.util.List;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Import;
import ca.example.batch.common.CommonLibraryReference;
import ca.example.batch.common.domain.WasHost;
import ca.example.batch.common.svc.WasHostService;

@SpringBootApplication
@Import(CommonLibraryReference.class)
public class Job3Application implements CommandLineRunner {

    private final Logger logger = LoggerFactory.getLogger(Job3Application.class);

    @Autowired
    public DataSource dataSource;

    @Autowired
    public WasHostService wasHostService;

    public Job3Application() {
    }

    public static void main(String[] args) throws Exception {
        new SpringApplicationBuilder(Job3Application.class)
        .web(WebApplicationType.NONE)
        .bannerMode(Banner.Mode.OFF)
        .run(args);
    }

    @Override
    public void run(String... strings) throws Exception {
        logger.info("Loading data...");

        logger.info("wasHostService: " + wasHostService);
        List<WasHost> hostList = wasHostService.findAll();
        if (!hostList.isEmpty()) {
            for (WasHost host : hostList) {
                logger.info("hostname: " + host.getHostname());
            }
        } else {
            logger.info("No hosts found in database. Aborting data collection.");
            exit(0);
        }
    }
}

The error I get in the log is:

""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring FrameworkServlet 'dispatcherServlet'
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO  c.e.b.job3.Job3Controller - app: ca.example.batch.job3.Job3Application@472d7ac
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO  c.e.b.job3.Job3Application - Loading data...
""2018-07-07 12:56:09 [http-nio-9191-exec-1] INFO  c.e.b.job3.Job3Application - wasHostService: null
""2018-07-07 12:56:09 [http-nio-9191-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
"java.lang.NullPointerException: null
    at ca.example.batch.job3.Job3Application.run(Job3Application.java:47)
    at ca.example.batch.job3.Job3Controller.handle(Job3Controller.java:21)

... when I launch the controller request.

If this isn't the right way, please advise.

Basically, what I am trying to do is launch a main() from within a controller but use the MainBatchApplication runtime to run it (if that makes sense?). When the program is done, it send the return code back to the controller and shows in the browser.

Thank you, Joey

Upvotes: 1

Views: 2031

Answers (1)

Dirk Deyne
Dirk Deyne

Reputation: 6936

ca.example.batch.MainBatchApplication is the main appliction you start. So it scans all Components in package ca.example.batch. That means it should detect ca.example.batch.job3.Job3Application so you should be able to @Autowireit in the Job3Controller

this should work:

@Controller
public class Job3Controller {
  private final Job3Application job3Application;      

  public Job3Controller (Job3Application job3Application){
     this.job3Application = job3Application;
  }

  @RequestMapping("/batch/startJob3")
  public String handle() throws Exception {
    String[] args = ...
    this.job3Application.run(args);
    return "COMPLETE";
  }

  ....
}

Upvotes: 1

Related Questions