As part of my work, I am trying to update some of our services and one is being deployed with Jetty & Jersey. Unfortunately the code is very old (some dependencies are from 2014), and while it is compiling and server starts, whenever I run it from my IDE with mvn jetty:run
the root directory shows the Directory /
message correctly whereas for all other URLs I get the error 404 NOT FOUND
.
I don't get any warning/error messages on console and I can't find why it happens. I've searched a lot but the code seems correct, the only thing that is missing is the web.xml
but I think Jetty is embedded, and I need to mention that this code is already running in production as a JAR.
Below you can see some of the files:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>sample</artifactId>
<version>2.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.2.2.v20140723</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.2.3.v20140905</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.2.3.v20140905</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160212</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
The class below is referenced to start the server:
ApiService.java
import com.simple.api.restendpoint.*;
import org.apache.log4j.Logger;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.server.handler.IPAccessHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import java.util.HashSet;
import java.util.Set;
public class ApiService {
Logger log = Logger.getLogger(ApiService.class);
private static ApiService instance;
private final Server server;
private ApiService(){
//CREATE CONFIG
Set<Class<?>> s = new HashSet<>();
s.add(restEndpoint.class);
ResourceConfig config = new ResourceConfig(s);
//CREATE CONTAINER
ServletContainer container = new ServletContainer(config);
//CREATE CONTEXT
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.addServlet(new ServletHolder(container),"/*");
//CREATE RPC SERVER
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMaxThreads(50);
server = new Server(threadPool);
server.setHandler(context);
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("testkeystore");
sslContextFactory.setKeyStorePassword("testkeystore");
sslContextFactory.setKeyManagerPassword("testkeystore");
// SSL HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration();
https_config.addCustomizer(new SecureRequestCustomizer());
// SSL Connector
ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
sslConnector.setPort(Settings.getInstance().getRpcPort());
server.addConnector(sslConnector);
}
public static ApiService getInstance() {
if (instance==null) {
instance = new ApiService();
}
return instance;
}
public void start() {
try {
//START RPC
server.start();
server.join();
log.info("Server started");
}
catch (Exception e) {
//FAILED TO START RPC
log.error("Error starting server");
} finally {
server.destroy();
}
}
}
restEndpoint.java
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Context;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONObject;
@Path("/v4/restEndpoint")
@Produces({"application/json"})
public class restEndpoint {
Logger log = Logger.getLogger(restEndpoint.class);
private static final String VERSION = "v4";
private static final ExecutorService executors = Executors.newFixedThreadPool(20);
@Context
HttpServletRequest request;
@GET
@Path("/getsamplejson")
public void getSampleJson(@Suspended final AsyncResponse asyncResponse) {
executors.execute(new Runnable() {
@Override
public void run() {
String result = veryExpensiveOperation();
asyncResponse.resume(result);
}
private String veryExpensiveOperation() {
JSONObject sampleJson = new JSONObject().put("test", 0);
return sampleJson.toString();
}
});
}
}
Any idea why is it happening?
http://localhost:8080/v4/restEndpoint/getsamplejson
returns 404 NOT FOUND
http://localhost:8080/
shows Directory: /
Should I try to build it as a JAR and run it through that, instead of using the mvn jetty:run
command?
You have an embedded-jetty instance, started from code.
That is evidenced by the ApiService
source you have provided.
You cannot use the jetty-maven-plugin
to manage / start / run that class.
The jetty-maven-plugin
is exclusively for working with webapps, either as WAR packaged files, or as exploded webapp directories. (webapps will either have a WEB-INF/web.xml and / or Servlet annotated classes within it)
You'll need to start the server using other means that is unique to your project, likely some kind of main class, or testcase, that eventually instantiates the ApiService
and calls .start()
on it.