Java: execute method when .war file is deployed - java

I want to execute some methods as soon as the .war file is deployed by Tomcat or JBoss, how can I do it?
I tried ServletContextListener but it's not working.
Thanks.

Have you tried adding your methods in a Servlet and then run it on startup
In your Web.xml:
<servlet>
<servlet-name>YourServlet</servlet-name>
<servlet-class>com.your.domain.YourServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

OK I resolved this, this works with JBoss:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Startup;
import javax.ejb.Singleton;
#Singleton
#Startup
public class InitializerEjb {
#PostConstruct
public void init() {
SMTPServer smtp_server = SMTPServer.getInstance();
smtp_server.start();
}
}
And this works with Tomcat:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class Initializer implements ServletContextListener {
#Override
public final void contextInitialized(final ServletContextEvent sce) {
SMTPServer smtp_server = SMTPServer.getInstance();
smtp_server.start();
}
}

Related

Deploying springboot war to tomcat throws 404

I am able to run this as spring boot war that uses embeded tc.
In another thread it said use tomcat 9. I am using 10. Still getting the error.
My Spring boot App class:
package pra.learn.tcjardemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#RestController
public class TcjardemoApplication extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(TcjardemoApplication.class);
}
#GetMapping("/show")
public static String getShow(){
return "Show is the problem";
}
// public static void main(String[] args) {
// SpringApplication.run(TcjardemoApplication.class, args);
// }
}
Not sure what am i missing.
So, I deployed it on tc9 and it worked. Why isn't the same war working on tc10?

Jersey 3 - Configuring binding with bindFactory

Using Jersey 3.0.1, I am struggling to get binding working.
I have this binding module with the factories below:
public static class MyBinder extends AbstractBinder {
#Override
protected void configure() {
LOG.info("Attempting to configure binder");
bindFactory(DataSourceFactory.class).to(HikariDataSource.class).in(Singleton.class);
bindFactory(JooqConfigFactory.class).to(Configuration.class).in(Singleton.class);
bindFactory(DSLContextFactory.class).to(DSLContext.class).in(Singleton.class);
LOG.info("Configured binder");
}
}
public static class DataSourceFactory implements Supplier<HikariDataSource> {
#Override
public HikariDataSource get() {
...
return new HikariDataSource(config);
}
}
public static class JooqConfigFactory implements Supplier<Configuration> {
#Inject
HikariDataSource dataSource;
#Override
public Configuration get() {
...
return conf;
}
}
public static class DSLContextFactory implements Supplier<DSLContext> {
#Inject
Configuration config;
#Override
public DSLContext get() {
return DSL.using(config);
}
}
Then I have the setup for my Servlet using embedded Jetty:
public void start() throws Exception {
int port = appConfig.getProperty("http.port", 9998);
Server server = new Server(port);
ServletContextHandler ctx =
new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
ctx.setContextPath("/");
server.setHandler(ctx);
ResourceConfig config = new JerseyConfig();
ServletHolder servlet = new ServletHolder(new ServletContainer(config));
servlet.setInitOrder(1);
ctx.addServlet(servlet, "/*");
server.start();
server.join();
}
public static class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
packages("com.sodonnell.jersey", "jersey.config.server.provider.packages");
register(new MyBinder());
}
}
And in my Rest service I simply try to inject a private instance variable:
public MyClass {
#Inject // javax.inject.Inject
private DSLContext dslContext;
}
However this dslContext is always null. I can see from the logs, that it prints the LOG.info("Configured binder"); message. However putting similar logs in my factory classes show they never get called.
Has anyone got any idea what I am missing?
EDIT
To make things simpler, I created this class:
public class SimpleClass {
private static Logger LOG = LoggerFactory.getLogger(SimpleClass.class);
public SimpleClass() {
LOG.info("Call the simple class constructor");
}
Changed my binder module:
import com.google.inject.Injector;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import org.jooq.impl.DefaultConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.util.Properties;
import java.util.function.Supplier;
...
// This is a nested class
public static class MyBinder extends AbstractBinder {
#Override
protected void configure() {
LOG.info("Attempting to configure binder");
bind(new SimpleClass()).to(SimpleClass.class);
}
}
Then attempted to inject just SimpleClass:
package com.sodonnell.hdfs3.rest;
import com.sodonnell.hdfs3.SimpleClass;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.HEAD;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import org.jooq.DSLContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
#Inject
private SimpleClass simpleClass;
...
But its still null, although I see both the log messages. There must be some fundamental setup I am missing.
Full cut down code with the SimpleClass example at:
github.com/sodonnel/jerseyBind
The answer is quite simple. You are using Jersey 3.0 which has switched to the new Jakarta naming. javax is thrown out the window - this includes javax.inject. All the javax package names have now been changed to jakarta. So to get the inject to work, the #Inject import should be
import jakarta.inject.Inject;
This change is part of the change of Java EE to Jakarta EE Starting from Jakarta EE 8 to Jakarta EE 9, all the namespacing has changed from javax to jakarta. So things like javax.servlet will now be jakarta.servlet. Weird, yes a huge breaking change with no backward compatibility.
In your case you have all the correct components to work with Jakarta (i.e. Jersey 3.0 and Jett 11), but you just need to make use of the new namespacing. Notice all the JAX-RS imports are now jakarta also.

Java Spring Boot - routing for access to static folder

I am working on a reactjs project and I just did a yarn build and moved the contents into the Java project.
my-project\complete\src\main\resources\static
but when I view the project from the Java site -- localhost:8080 -- I get a ton of 404 errors
logo.a67f8998.png:1 GET http://localhost:8080/static/media/logo.a67f8998.png
registerServiceWorker.js:77 GET http://localhost:8080/service-worker.js 404
-beefeater.78e4414b.jpg:1 GET http://localhost:8080/static/media/-beefeater.78e4414b.jpg 404 ()
For this project I am mostly acting as a frontend dev - Where do I make the required changes to get the routing correct for these files?
my Application.java file looks like this - when I uncomment the code I get told to remove the #overide?
//import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
/**
* Hello world!
*
*/
#SpringBootApplication
public class Application implements CommandLineRunner {
//#Autowired
//private AccountRepository accountRepository;
/**
* #param args
*/
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... arg0) throws Exception {
}
/*
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}*/
}
I've tried to add a config file to sort this out.. do I need to import it in the application.java?
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
//#Configuration
#EnableWebMvc
#WebAppConfiguration
public class Configuration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
}
You're missing #WebMvcAutoConfiguration annotation I think

Spring on Wildfly not rendering index.html when root URL hit

Due to project requirements I have to deploy a Spring application to a server incapable of running Tomcat and only capable of running WildFly. When I had a very simple project running on Tomcat and the root URL was hit (localhost:8080) it rendered my index.html. Since migrating to WildFly and refactoring the structure of my project, localhost:8080 no longer renders the index.html but I can still reach other URLs.
I've tried to implement a jboss-web.xml file under BrassDucks/src/main/webapp/WEB-INF/jboss-web.xml like this:
<jboss-web>
<context-root>Brass-Ducks</context-root>
</jboss-web>
Where Brass-Ducks is the artifactID but to no avail.
Consider my ApplicationConfig.java
package brass.ducks;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class ApplicationConfig extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<ApplicationConfig> applicationClass = ApplicationConfig.class;
}
#RestController
class GreetingController {
#RequestMapping("/hello/{name}")
String hello(#PathVariable String name) {
return "Hello, " + name + "!";
}
}
and consider my Controller.java
package brass.ducks.application;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/")
public class Controller {
#RequestMapping("/greet")
#ResponseBody
public String greeting() {
return "Hello, there.";
}
}
And finally should it be relevant, my folder structure:
localhost:8080/greet returns "Hello, there" and localhost:8080/hello/name returns "Hello name". How can I fix this?
Depending on your exact configuration something along the lines of this should work:
#Controller
public class LandingPageController {
#RequestMapping({"/","/home"})
public String showHomePage(Map<String, Object> model) {
return "/WEB-INF/index.html";
}
}
This is going to explicitly map / to index.html.

Share variables between JAX-RS requests

I have what I think is a very basic question about JAX-RS but I somehow can't easily find the answer.
I am trying to refactor a REST service which uses a "standard" Javax servlet -- routing requests to methods by hand -- into an "cleaner" JAX-RS implementation. The current application sets some variables during the servlet init(). It assigns those as attributes of the HttpServlet class so they are available during each doGet() and can be passed as parameters to request processing methods. For clarity, one of these is a ConcurentHashMap that acts as a cache.
Now, with JAX-RS, I can extend Application to set my resource classes. I can also use the #Context annotation in each resource implementation to inject things like ServletContext when processing a request. But I do not know how to similarly inject variables set during application initialization.
I am using the Apache Wink 1.3.0 implementation of JAX-RS.
You can use a listener for init the cache and set to the context as attribute before the web application start. something like the following:
package org.paulvargas.shared;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class CacheListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
Map<String, String> dummyCache = new HashMap<String, String>();
dummyCache.put("greeting", "Hello Word!");
ServletContext context = sce.getServletContext();
context.setAttribute("dummyCache", dummyCache);
}
public void contextDestroyed(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
context.removeAttribute("dummyCache");
}
}
This listener is configured in the web.xml.
<listener>
<listener-class>org.paulvargas.shared.CacheListener</listener-class>
</listener>
<servlet>
<servlet-name>restSdkService</servlet-name>
<servlet-class>
org.apache.wink.server.internal.servlet.RestServlet
</servlet-class>
<init-param>
<param-name>applicationConfigLocation</param-name>
<param-value>/WEB-INF/application</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>restSdkService</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
You can use the #Context annotation for inject the ServletContext and retrieving the attribute.
package org.apache.wink.example.helloworld;
import java.util.*;
import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import org.apache.wink.common.model.synd.*;
#Path("/world")
public class HelloWorld {
#Context
private ServletContext context;
public static final String ID = "helloworld:1";
#GET
#Produces(MediaType.APPLICATION_ATOM_XML)
public SyndEntry getGreeting() {
Map<String, String> dummyCache =
(Map<String, String>) context.getAttribute("dummyCache");
String text = dummyCache.get("greeting");
SyndEntry synd = new SyndEntry(new SyndText(text), ID, new Date());
return synd;
}
}

Categories