Run a Java class from Spring startup - java

I am using Java8 and Spring4.3.1.
I have a Java/Spring application hosting RESTfult services accessed by browser and mobile app clients. Second, I have written a Chat Server that listens for events (socket.io) from the clients. This Chat Server is running from the classes main method.
The Chat Server class has a main method that I want to run, and allow to listen for events when my Spring application starts. Is this possible?
If I run the main myself, it works, but I want it to start up when I start my Wildfly server that loads the Spring application.
Or is there a better approach? Should the Chat Server not be running from the main method?
I have the following code:
package com.jobs.spring.configuration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(servletContext);
Dynamic dynamic = servletContext.addServlet("rest", new DispatcherServlet(ctx));
dynamic.addMapping("/*");
dynamic.setLoadOnStartup(1);
try {
com.jobs.spring.chat.Server chatServer = new com.jobs.spring.chat.Server();
chatServer.run(null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
and
public class Server implements CommandLineRunner {
private static final String SERVER = "localhost";
private static final Integer PORT = 3700;
#Override
public void run(String... args) throws Exception {
main(args);
}
public static void main(String[] args) {
...
and get the following error:
18:47:08,142 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 66) MSC000001: Failed to start service jboss.undertow.deployment.default-server.default-host./jbosswildfly: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./jbosswildfly: java.lang.NoClassDefFoundError: Failed to link com/jobs/spring/chat/Server (Module "deployment.jbosswildfly.war:main" from Service Module Loader): org/springframework/boot/CommandLineRunner
Caused by: java.lang.NoClassDefFoundError: Failed to link com/jobs/spring/chat/Server (Module "deployment.jbosswildfly.war:main" from Service Module Loader): org/springframework/boot/CommandLineRunner

You could deploy your chat server in Wildfly, by extending SpringBootServletInitializer, instead of launching it from a main.
Documentation: howto-create-a-deployable-war-file
#SpringBootApplication
public class SpringBootApp extends SpringBootServletInitializer{
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringBootApp.class);
}
//public static void main(String[] args){
// new SpringApplicationBuilder()
// .sources(SpringBootApp.class)
// .run(args);
//}
}
Change the artifact produced to war, and deploy it normally in wildfly:
<project>
<packaging>war</packaging>
...
<project>
You may have to exclude tomcat, which is automatically imported with spring-boot-starter-web:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
Spring provided a Spring Boot example of a pom.xml for wildfly: spring-boot-deployment-test-wildfly

Related

Vaadin with Apache CXF SOAP service

I am new to Vaadin, just generated the application in Vaadin web site and built it locally. Then I added Apache CXF SOAP service to it, but I am unable to use the Tomcat that Vaadin is using, but instead I load SOAP in Jetty using:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
<scope>compile</scope>
</dependency>
My Vaadin application is:
#SpringBootApplication
#Theme(value = "iciclient", variant = Lumo.DARK)
#PWA(name = "ICI Client", shortName = "ICI Client", offlineResources = {"images/logo.png"})
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {
public static void main(String[] args) {
LaunchUtil.launchBrowserInDevelopmentMode(SpringApplication.run(Application.class, args));
try {
System.out.println("Starting IciEventClient");
Object implementor = new IciEventServiceSoap12Impl();
String address = "http://localhost:8081/ici/IciEventService";
Endpoint.publish(address, implementor);
// http://localhost:8081/ici/IciEventService?WSDL
} catch (Exception e) {
e.printStackTrace();
}
}
}
While this works, I would like to get rid of separate Jetty dependency and run the SOAP service in Vaadin Tomcat (localhost:8080).
Should be simple but I can't figure out how to do it.
I think that it needs a separate servlet and route, but I don't know how to add them.
There is no web.xml in the Vaadin application, for example.
I am not familiar with Apache CXF, but based on CXF docs and the sample project I think I got it to work.
I downloaded a new Vaadin 14/Java 8 project from start.vaadin.com, and did the following:
Added the dependency
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.4.3</version>
</dependency>
Created a web service
import javax.jws.WebMethod;
import javax.jws.WebService;
#WebService
public class Test {
#WebMethod
public String test() {
return "This works";
}
}
Exposed it as a bean in my Application class
import javax.xml.ws.Endpoint;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.vaadin.artur.helpers.LaunchUtil;
import org.vaadin.erik.endpoint.Test;
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
LaunchUtil.launchBrowserInDevelopmentMode(SpringApplication.run(Application.class, args));
}
#Bean
public Endpoint test(Bus bus) {
EndpointImpl endpoint = new EndpointImpl(bus, new Test());
endpoint.publish("/Test");
return endpoint;
}
}
That was it! At least I can now list the service definition at http://localhost:8080/services/Test?wsdl
The first documentation link lists some configurations you can do, for example to change the /services path. The example project shows how to configure Spring actuator metrics if that is something you need.
You might want to create a separate #Configuration-annotated class for all your service #Bean definitions.
If you don't want to use the starter dependency, this Baeldung article looks promising.

ServletContextListener isn't invoked when using com.sun.net.httpserver.HttpServer

I use com.sun.net.httpserver.HttpServer in integration tests. It does its job but I've noticed that ServletContextListener's methods aren't invoked during tests.
When I deploy the app to the real Tomcat server I can see its methods being called.
Below is the listener class:
package abc;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class StartupListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("########################################");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("########################################");
}
}
Here is how I start the HttpServer in the test:
#BeforeClass
public static void startServer() {
URI uri = UriBuilder.fromUri("http://localhost/").port(8080).build();
// Create an HTTP server listening at port 8080
try {
server = HttpServer.create(new InetSocketAddress(uri.getPort()), 0);
} catch (IOException e) {
e.printStackTrace();
fail();
}
// Create a handler wrapping the JAX-RS application
HttpHandler handler = RuntimeDelegate.getInstance().createEndpoint(new ApplicationConfig(), HttpHandler.class);
// Map JAX-RS handler to the server root
server.createContext(uri.getPath(), handler);
// Start the server
server.start();
}
Maven dependency:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
I removed #WebListener and inserted
metadata-complete="false"
and
<listener>
<listener-class>abc.StartupListener</listener-class>
</listener>
in web.xml but it didn't help
What is the problem? Is there anything that needs to be setup?
What is the problem?
HttpServer is not a servlet container and does not know about servlet api.
Is there anything that needs to be setup?
You need to setup a servlet container like jetty, which is frequently used for unit testing java based web applications.

java.lang.NoClassDefFoundError: org/omg/CORBA/COMM_FAILURE on client while creating simple spring boor rmi app

I am creating spring boot applicating using RmiServiceExporter on server and RmiProxyFactoryBean on client.When i start server everything seems ok, i get
[main] o.s.remoting.rmi.RmiServiceExporter: Binding service 'ServerServiceIF' to RMI registry: RegistryImpl[UnicastServerRef [liveRef: [endpoint:[localhost:1099](local),objID:[0:0:0, 0]]]]
Then i start my client which is also spring boot app and my service interface on client is connecting to the adress on localhost.
rmi://localhost:1099/ServerServiceIF
But when i try to call method of this interface i get
Exception in thread "main" java.lang.NoClassDefFoundError: org/omg/CORBA/COMM_FAILURE
at org.springframework.remoting.rmi.RmiClientInterceptorUtils.isCorbaConnectFailure(RmiClientInterceptorUtils.java:187)
at org.springframework.remoting.rmi.RmiClientInterceptorUtils.isConnectFailure(RmiClientInterceptorUtils.java:174)
at org.springframework.remoting.rmi.RmiClientInterceptor.isConnectFailure(RmiClientInterceptor.java:283)
at org.springframework.remoting.rmi.RmiClientInterceptor.doInvoke(RmiClientInterceptor.java:349)
at org.springframework.remoting.rmi.RmiClientInterceptor.invoke(RmiClientInterceptor.java:260)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy38.auth(Unknown Source)
at com.cw.client.ClientApplication.main(ClientApplication.java:29)
Caused by: java.lang.ClassNotFoundException: org.omg.CORBA.COMM_FAILURE
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
... 9 more
Here are my server and client:
ServerApplication.java
package com.cw.server;
import com.cw.appif.ServerServiceIF;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.remoting.rmi.RmiServiceExporter;
#SpringBootApplication
public class ServerApplication {
#Bean
ServerServiceIF serverServiceIF() {
return new ServerService();
}
#Bean
RmiServiceExporter exporter(ServerServiceIF implementation) {
// Expose a service via RMI. Remote object URL is:
// rmi://<HOST>:<PORT>/<SERVICE_NAME>
// 1099 is the default port
Class<ServerServiceIF> serviceInterface = ServerServiceIF.class;
RmiServiceExporter exporter = new RmiServiceExporter();
exporter.setServiceInterface(serviceInterface);
exporter.setService(implementation);
exporter.setServiceName(serviceInterface.getSimpleName());
exporter.setRegistryPort(1099);
return exporter;
}
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
ClientApplication.java
package com.cw.client;
import com.cw.appif.ServerServiceIF;
import com.cw.exceptions.AuthException;
import com.cw.models.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
#SpringBootApplication
public class ClientApplication {
private static User user;
#Bean
RmiProxyFactoryBean service() {
RmiProxyFactoryBean rmiProxyFactory = new RmiProxyFactoryBean();
rmiProxyFactory.setServiceUrl("rmi://localhost:1099/ServerServiceIF");
rmiProxyFactory.setServiceInterface(ServerServiceIF.class);
return rmiProxyFactory;
}
public static void main(String[] args) {
try {
ServerServiceIF service = SpringApplication.run(ClientApplication.class, args).
getBean(ServerServiceIF.class);
user = new User("Denis","1234","e#mail.co");
service.auth(user);
System.out.println("User authed");
} catch (AuthException e) {
e.printStackTrace();
}
}
}
My server service interface and implementation on server:
package com.cw.appif;
import com.cw.exceptions.AuthException;
import com.cw.models.User;
public interface ServerServiceIF{
boolean auth(User user) throws AuthException;
}
package com.cw.server;
import com.cw.appif.ServerServiceIF;
import com.cw.exceptions.AuthException;
import com.cw.models.User;
import java.util.List;
public class ServerService implements ServerServiceIF{
static List<User> clients;
#Override
public boolean auth(User user) throws AuthException {
clients.add(user);
System.out.println("hi");
return true;
}
}
Heres my thoughts:
1)Maybe its because interface which im using is exactly the same on client and server, but client cant find class, because path is different?
2)When im debugging my client service->h->advised->targetSource ->targetClass is null. Is it ok? I will upload screenshots of my project structure and this variable in debug below.
server structure
client structure
debugging client
Found the problem. After adding corba to classpath, I found out that class User has to be Serializable. Adding implements Serializable and serialVersionUID fixed the problem and now everything is working.

Vertx trying to launch embedded server

I am trying to launch an initial test of a Vertx.io server, but I get the following error message:
Exception in thread "main" java.lang.NoClassDefFoundError: org/vertx/java/core/Handler
Code:
package com.company;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vertx.java.core.Handler;
import org.vertx.java.core.Vertx;
import org.vertx.java.core.VertxFactory;
import org.vertx.java.core.http.HttpServerRequest;
import java.io.IOException;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
private Object shutdownLock = new Object();
public Main() throws IOException, InterruptedException {
start(1234);
keepServerFromShuttingDown();
}
private void keepServerFromShuttingDown() throws InterruptedException {
synchronized (shutdownLock) {
shutdownLock.wait();
}
log.info("Shutting down");
}
public void start(int port) {
Vertx vertx = VertxFactory.newVertx();
vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
#Override
public void handle(HttpServerRequest request) {
}
}).listen(port);
}
public static void main(String[] args) throws IOException, InterruptedException {
new Main();
}
}
pom.xml:
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-platform</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-hazelcast</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>
It looks like a basic CLASSPATH issue where it is not able to find Vertx classes while executing your program. Please check if the vertx libraries are indeed a part of your CLASSPATH.
Though unrelated, but if you are checking out Vertx for some new projects, I highly recommend version 3.0 and you could start with this simple maven project example

How to enable neo4j webadmin when using spring-data-neo4j?

I am bootstrapping a new project from the Accessing Neo4j Data with REST example. The example uses an embedded database rather than a standalone neo4j server, but I would like to use the Neo4J webadmin interface for visualisation of my data. How do I enable the webadmin interface starting from this configuration?
(They got WrappingNeoServerBootstrapper working in use WrappingNeoServerBootstrapper with spring-data-neo4j but a lot of knowledge is omitted from the answer, e.g. it is not even mentioned where to place to the configuration. Being new to POMs, Spring Boot and Neo4j I therefore can't make use of that answer.)
The example you are using needs some tweaking to enable the Neo4j browser. I started from a different example, the Accessing Data with Neo4j example and it worked well.
You will need to do the following:
Change the version on your spring boot pom to 1.2.1.Release:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.1.RELEASE</version>
</parent>
Add dependencies for Neo4jServer:
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
<version>2.1.5</version>
<classifier>static-web</classifier>
</dependency>
Implement the Spring Boot command line runner in your Application.class:
public class Application extends Neo4jConfiguration implements CommandLineRunner{
Autowire a reference to your GraphDatabaseService in your Application.class:
#Autowired
GraphDatabaseService db;
#Override the run method from CommanLineRunner in your Application.class:
#Override
public void run(String... strings) throws Exception {
// used for Neo4j browser
try {
WrappingNeoServerBootstrapper neoServerBootstrapper;
GraphDatabaseAPI api = (GraphDatabaseAPI) db;
ServerConfigurator config = new ServerConfigurator(api);
config.configuration()
.addProperty(Configurator.WEBSERVER_ADDRESS_PROPERTY_KEY, "127.0.0.1");
config.configuration()
.addProperty(Configurator.WEBSERVER_PORT_PROPERTY_KEY, "8686");
neoServerBootstrapper = new WrappingNeoServerBootstrapper(api, config);
neoServerBootstrapper.start();
} catch(Exception e) {
//handle appropriately
}
// end of Neo4j browser config
}
When you are all done, your Application.class should look like this:
package hello;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.kernel.GraphDatabaseAPI;
import org.neo4j.server.WrappingNeoServerBootstrapper;
import org.neo4j.server.configuration.Configurator;
import org.neo4j.server.configuration.ServerConfigurator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
#Configuration
#EnableNeo4jRepositories
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
public class Application extends Neo4jConfiguration implements CommandLineRunner{
public Application() {
setBasePackage("hello");
}
#Bean(destroyMethod = "shutdown")
public GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("target/hello.db");
}
#Autowired
GraphDatabaseService db;
#Override
public void run(String... strings) throws Exception {
// used for Neo4j browser
try {
WrappingNeoServerBootstrapper neoServerBootstrapper;
GraphDatabaseAPI api = (GraphDatabaseAPI) db;
ServerConfigurator config = new ServerConfigurator(api);
config.configuration()
.addProperty(Configurator.WEBSERVER_ADDRESS_PROPERTY_KEY, "127.0. 0.1");
config.configuration()
.addProperty(Configurator.WEBSERVER_PORT_PROPERTY_KEY, "8686");
neoServerBootstrapper = new WrappingNeoServerBootstrapper(api, config);
neoServerBootstrapper.start();
} catch(Exception e) {
//handle appropriately
}
// end of Neo4j browser config
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The Neo4j browser will be available on the host and port configured in your run() method.

Categories

Resources