Embedding Jetty as a Servlet Container - java

I'm using Tomcat to serve my Java Servlets and it's kinda more for me. I just need to serve, Servlet Requests alone, no static content, neither JSP, etc. So I was looking for a Servlet container that can be embedded in my Application. I felt it if stripped Jetty and use it as a Servlet Container alone, it can be more scalable and occupying small memory footprint, [I don't need Jetty's 'Web Server' and other Parts]. So I've a few questions though,
How do I embed Jetty in my Application Code to serve Servlet Requests alone?
If I embed Jetty code in my Application Code, will I be able to easily upgrade Jetty Versions?
I got the Jetty code here, if I have to embed Jetty's Servlet Container in my App, which one should I use from the source,
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/snapshot/jetty-9.0.3.v20130506.tar.bz2 ,
jetty-9.0.3.v20130506/jetty-servlet or jetty-9.0.3.v20130506/jetty-servlets
I intend to serve API Requests with my Applications and I'm looking for Performance and Scalability as main constraints. And of course Servlet 3.0 support.

What you are looking for is running Jetty in an embedded scenario.
There's plenty of examples available showing how to tie together the various pieces you need to accomplish your goals.
Check out the embedded examples in the jetty source tree.
For the record, jetty standalone is really just jetty embedded with a few startup and classpath related bootstraps. It is the same code, and assembled in basically the same way.
Since you stated you want Servlet 3.0, have no interest in JSP, this is rather easy to setup. (JSP is trickier to setup, but possible).
For servlet 3.0 specific embedding, there's a complete example project hosted at github.
https://github.com/jetty-project/embedded-servlet-3.0
In short, you'll have the following initialization code.
package com.company.foo;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.TagLibConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
public class EmbedMe {
public static void main(String[] args) throws Exception {
int port = 8080;
Server server = new Server(port);
String wardir = "target/sample-webapp-1-SNAPSHOT";
WebAppContext context = new WebAppContext();
// This can be your own project's jar file, but the contents should
// conform to the WAR layout.
context.setResourceBase(wardir);
// A WEB-INF/web.xml is required for Servlet 3.0
context.setDescriptor(wardir + "WEB-INF/web.xml");
// Initialize the various configurations required to auto-wire up
// the Servlet 3.0 annotations, descriptors, and fragments
context.setConfigurations(new Configuration[] {
new AnnotationConfiguration(),
new WebXmlConfiguration(),
new WebInfConfiguration(),
new TagLibConfiguration(),
new PlusConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new EnvConfiguration() });
// Specify the context path that you want this webapp to show up as
context.setContextPath("/");
// Tell the classloader to use the "server" classpath over the
// webapp classpath. (this is so that jars and libs in your
// server classpath are used, requiring no WEB-INF/lib
// directory to exist)
context.setParentLoaderPriority(true);
// Add this webapp to the server
server.setHandler(context);
// Start the server thread
server.start();
// Wait for the server thread to stop (optional)
server.join();
}
}

Related

Deploy war file in a grizzly server

I have spent a few days on this and I still did not find an answer (i did find questions asking for this)
I am coding with java, using a grizzly server (2.3 version) and I've managed to work with many kind of resources (restful classes, java servlets etc).
URI uri = new URI("http://localhost....");
ResourceConfig rc = new ResourceConfig();
rc.registerClasses(aResource.class);
GrizzlyHttpServerFactory.createHttpServer(uri, rc);
My goal though, is to load a whole war file and not individual classes but i have not find a way to do it.
So the question is 'how can i deploy and run a war file inside a grizzly server?'
According to the Grizzly Javadoc you do it like this:
Synchronous Web Server servicing a Servlet
GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
try {
ServletAdapter sa = new ServletAdapter();
sa.setRootFolder("/Path/To/Exploded/War/File");
sa.setServlet(new MyServlet());
ws.addGrizzlyAdapter(sa);
ws.start();
} catch (IOException ex) {
// Something when wrong.
}
However, as you can see, you first have to "explode" the WAR file; i.e. unpack it into the file system.
You seem to be using the Jersey ResourceConfig class. To make your approach work, I think you would need to do the following:
Unpack the WAR file.
Create a URLClassloader instance that loads from "/WEB-INF/classes" the JARs etc in "/WEB-INF/lib".
Register it by calling ResourceConfig.setClassLoader
For the record, classloading from a packed WAR file is more effort, and apparently gives poor performance. (If you want to see how to do it, Tomcat has this functionality ... disabled by default.)
It's not possible to deploy WAR files to Grizzly 2.x at this point in time.

log4j2 Web Lookup not working

We have Spring java-based web deployments which use log4j2.xml for logging messages to files, etc.
We now need to update our log4j2.xml configs in order to be able to do a ${web:contextPath} web lookup inside them so that we can use a deployment's context name as part of the log file's name which the loggers log messages to. However, when we deploy the apps, the log4j2 configurations fail to recognise any web lookup related stuff. The file created to log messages to is simply created with the name ${web and no messages are actually logged in them.
I have read various docs online related to log4j2 web lookups when running in 3.0 servlets but I still can't see what the problem might be in our configurations. And I don't know what to look for in the log4j's trace logs in order to see what it is that we are missing.
Our Stack:
Windows and Linux OSes
Java 8
Tomcat 7.0.5x
log4j-xxx 2.2 (log4j-api, log4j-core, log4j-slf4j-impl, log4j-jcl, log4j-web all in classpath)
Any help on how to get web lookups to work is much appreciated.
Cheers,
PM
If you have a Spring 4 java annotation based web application, it is possible to have log4j-slf4j-impl jar in the classpath and still do a log4j2 web lookup by having your web initialization class extend Log4jServletContainerInitializer and calling super.onStartup() on it.
Example:
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.apache.logging.log4j.web.Log4jServletContainerInitializer;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
public class WebInitialiser extends Log4jServletContainerInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext)
throws ServletException {
super.onStartup(null, servletContext);
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(ApplicationConfig.class, IntegrationConfig.class,
JmsConfig.class, JmxConfig.class);
servletContext.addListener(new ContextLoaderListener(rootContext));
}
}
Note however that you still seem to need to have your web.xml include a <display-name> node in order for log4j2 web lookups to work on a Tomcat 7.0.5x container.
For more detail on all this, see the answers that I got in the log4j user mailing list thread:
log4j2 web lookup questions
Cheers,
PM.

Add web services functionality to current working java application

I'm trying to create web services functionality linked to my current working java application and struggling to do it. Any ides ?
At line:
TopUpApp application = new TopUpApp();
I'm creating a new instance from the other class , but it doesn't seem to work when I test web service. Giving false as a return where it should be true.
Below is the code for web service.
package org.me;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.ejb.Stateless;
/**
*
* #author KS
*/
#WebService(serviceName = "DOAws")
#Stateless()
public class DOAws {
/**
* Web service operation
*/
#WebMethod(operationName = "login")
public boolean login(#WebParam(name = "username") int username, #WebParam(name = "password") String password) {
TopUpApp application = new TopUpApp();
return application.authenticate(username, password);
}
}
It works fine and I get true as a response when I run it in new main class this way (not a web service):
public class NewClass {
public static void main(String []args){
TopUpApp application = new TopUpApp();
System.out.println(application.authenticate(12345, "12345"));
}
}
To deploy your application as a web service, you need to do a little bit more than what is necessary for a normal java application.
I short, what you need to do is to deploy your application on a web server that is also able to deploy java web applications. Many such web servers exists, a couple of popular alternatives are Tomcat and Jetty.
The normal thing to do is to install the web server on the machine that is supposed to handle the requests. Next you need to deploy your application on that server. To do that, you will need to do a couple of things:
Package your application as a war (web archive). How to do this is quite straightforward, but involves a few steps. You should be able to figure this out by yourself using google.
Deploy your application to the web server. This is usually done by copying the war file to the web applications directory of your web server. E.g. the webapps directory under the tomcat installation directory.
When this is done, you just need to make sure that your web server is up and running, and you should be able to access your web services.

Embedded Jetty 8 hot deploy classes (using Maven)

I have a standard Maven webapp structure defined, and it uses Spring MVC.
I am using an embedded Jetty server (java class) for testing the application in development.
The code used to create the Jetty server is outlined below. If I make changes to any JSP files, the changes are immediately visible in the browser.
However if I change any class files, e.g Controllers, the changes are not hot deployed?
What do I have to do get this to work?
I have searched this and I think I need to use the class org.eclipse.jetty.util.Scanner and specifically the setScanInterval method, but not sure how to wire this up?
Here is the code to create the Server
String webAppDir = "src/main/webapp/";
Server server = new Server(8080);
WebAppContext webApp = new WebAppContext();
webApp.setContextPath("/");
webApp.setDescriptor(webAppDir + "/WEB-INF/web.xml");
webApp.setResourceBase(webAppDir);
webApp.setParentLoaderPriority(true);
HandlerCollection hc = new HandlerCollection();
ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
hc.setHandlers(new Handler[] { contextHandlerCollection });
hc.addHandler(webApp);
server.setHandler(hc);
return server;
Thanks in advance
For hot deployment you need to use the WebAppProvider and the DeploymentManager. Those you can configure to manage the scanning for changes and the reloading of the webapp. So it is clear, the WebappContext is not what manages the deployment of a webapp, it is merely the container class that is gets deployed so there is another mechanism that works outside of that which can handle the concepts of deploy/redeploy.
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-deploy/src/test/resources/jetty-deploy-wars.xml
You can take that chunk of xml there and convert into the java calls you need to do this embedded.
Or use something like the jrebel jvm plugin which provides for automatic class reloading.

Serving jetty webapp from two directories simultaneously

In development I use jetty as the servlet container. I have the following development configuration:
master project which has wabapp directory
derived project which overrides some of the files in webapp directory
The master project webapp can be started in development mode thanks to providing appropriate WebAppContext to jetty.
Now I want to start derived project analogously, assuming that when request is made, there is an attempt to:
get resource from webapp directory of derived project
if it does not exists, get it from webapp directory of master project
I know that it is possible to override WebAppContext#getResource() method, however some libraries we use in the project seem to perform IO operations on wabapp directory on their own. For example by calling ServletContext#getRealPath("/"), and then reading files without use of ServletContext#getResource() method. The problem could be solved on lower level by some virtual file system on top of File, however it does not seem to be supported in JDK 1.6, any suggestions?
It seems that using something like ResourceCollection is sufficient:
http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/util/resource/ResourceCollection.html
Unfortunately the GWT's DevMode which I use is based on jetty 6, where ResourceCollection is unavailable. I extended the Resource class myself, and together with own GWT JettyLauncher, and thanks to small trick with setting resourceBase on DefaultServlet via reflection, I was able to serve webapp from two directories simultaneously.
protected void doStart() throws Exception {
setClassLoader(new LauncherWebAppClassLoader());
super.doStart();
ServletHolder holder = getServletHandler().getServlet("default");
Servlet servlet = holder.getServlet();
Field field = servlet.getClass().getDeclaredField("_resourceBase");
field.setAccessible(true);
field.set(servlet, combinedResourceBase);
}

Categories

Resources