How do I configure jetty to use use log4j? I'm already using log4j in my application, while jetty logs to stderr...
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class Test {
static final Logger logger = Logger.getLogger(Test.class);
public static void main(String[] args) {
PropertyConfigurator.configure("log4j.properties");
logger.info("Started.");
Server server = new Server();
Connector connector = new SelectChannelConnector();
connector.setHost("127.0.0.1");
connector.setPort(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(new ServletHolder(new ServletHome()), "/");
// disable jettys default logger
//org.eclipse.jetty.util.log.Log.setLog(null);
server.addConnector(connector);
server.setHandler(context);
logger.debug("Starting jetty.");
try {
server.start();
server.join();
} catch (Exception e) {
logger.error("Ooops.");
}
logger.info("Finished.");
}
}
Jetty uses slf4j for logging. slf4j allows a unified logging API to connect to any supported logging framework. Of course log4j is supported too. All you have to do is put both the slf4j API and slf4j-log4j connector to your classpath. It should get wired automatically.
Related
I'm using java 11 and embedded jetty 9 foor my javaEE application,I'm trying to use #Websevlet annotation to publish my servlet but it doesn't work i don't know why.
My start class java
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.*;
public class Start {
public static void main(String[] args) throws Exception {
Server server = new Server(80);
WebAppContext wacHandler = new WebAppContext();
wacHandler.setConfigurations(new Configuration[]
{
new AnnotationConfiguration(),
new WebInfConfiguration(),
new WebXmlConfiguration(),
new MetaInfConfiguration(),
new FragmentConfiguration(),
new JettyWebXmlConfiguration()
});
server.setHandler(wacHandler);
server.start();
server.join();
}
}
My hello world class
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet( "/getservlet")
public class ServletX extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h1>Hi there..</h1>");
}
}
I don't have a web.xml configuration ,Should i do?
If ServletX is in the war file, meaning it's in WEB-INF/classes/ archive directory, then the configuration you have declared (specifically the AnnotationConfiguration) will perform a bytecode scan of the WAR file and load the #WebServlet annotation.
Also note that the WebAppContext will need point to this WAR file, which your code examples do not do.
WebAppContext wacHandler = new WebAppContext();
waxHandler.setWar("/path/to/myapp.war");
// ... more setup
But! if the ServletX is not in the WAR file, but is instead housed with your embedded-jetty Start class, then you'll need to expose the servlet container to be scanned by the bytecode scanning step.
You can always turn on DEBUG/FINE level logging for the named logger org.eclipse.jetty and see the activity being performed with regards to the deployment and bytecode scanning.
I cannot find examples of embedded jetty with my combination of handlers and filters. For some reason I cannot identify I do not get CORS headers. Here is my current source:
private static Server setupJetty(Properties prop) {
Server server = new Server(Integer.parseInt(prop.getProperty("port")));
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath(prop.getProperty("contextpath"));
ContextHandlerCollection contexts = new ContextHandlerCollection();
RequestLogHandler requestLogHandler= setupLogging(server, prop.getProperty("logslocn"));
ServletHolder jerseyServlet = context.addServlet(ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
// Tells the Jersey Servlet which REST service/class to load.
jerseyServlet.setInitParameter(ServerProperties.PROVIDER_PACKAGES, "org.example.pss.resources");
context.addServlet(jerseyServlet, prop.getProperty("servletpath"));
ServletHandler handler = new ServletHandler();
handler.addServletWithMapping(jerseyServlet, "/*");
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*"); // allowed origins comma separated
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,PUT,POST,DELETE,OPTIONS");
filterHolder.setInitParameter(CrossOriginFilter.PREFLIGHT_MAX_AGE_PARAM, "5184000"); // 2 months
filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
filterHolder.setName("cross-origin");
FilterMapping fm = new FilterMapping();
fm.setFilterName("cross-origin");
fm.setPathSpec("*");
handler.addFilter(filterHolder,fm);
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[]{context, handler, contexts,
new DefaultHandler(), requestLogHandler});
server.setHandler(handlers);
return server;
}
I also tried:
FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "/*"); // allowed origins comma separated
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,PUT,POST,DELETE,OPTIONS");
filterHolder.setInitParameter(CrossOriginFilter.PREFLIGHT_MAX_AGE_PARAM, "5184000"); // 2 months
filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
context.addFilter(filterHolder,"/*",EnumSet.allOf(DispatcherType.class));
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[]{context, contexts,
new DefaultHandler(), requestLogHandler});
server.setHandler(handlers);
With the same result, I never see the cross domain headers. What more do I need to do to get this filter to work?
Don't use ServletHandler directly, that's an internal class.
Filters are always part of the ServletContextHandler (or the more specialized WebAppContext)
Your configuration adds 2 servlets at the /* context path (that's a no-no)
Your configuration adds your RequestLogHandler after the DefaultHandler (which means the RequestLogHandler never runs)
DefaultHandler should be at the end of the main handler list
DefaultServlet needs to exist in your ServletContextHandler
You are missing a required resourceBase for your ServletContextHandler (this is a path or URL pointing to a valid location to make the ServletContext sane for finding resources)
A path spec of * is invalid. (remember, you can use prefix /a/b/*, suffix *.foo, exact /a/b/c, or default /)
So, to simplify ...
package org.eclipse.jetty.demo;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import org.eclipse.jetty.server.AsyncNCSARequestLog;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.servlet.ServletContainer;
public class JerseyWithCors
{
public static void main(String[] args)
{
try
{
new JerseyWithCors().exec();
}
catch (Throwable t)
{
t.printStackTrace(System.err);
}
}
public void exec() throws Exception
{
int port = 8080;
Server server = new Server(port);
HandlerList handlers = new HandlerList();
server.setHandler(handlers);
handlers.addHandler(getAccessLogHandler());
handlers.addHandler(getMainServletContext());
// DefaultHandler is always last for the main handler tree
// It's responsible for Error handling of all prior handlers.
// It will always respond (if the request reaches this far)
handlers.addHandler(new DefaultHandler());
server.start();
server.join();
}
public Handler getAccessLogHandler()
{
RequestLogHandler logHandler = new RequestLogHandler();
AsyncNCSARequestLog log = new AsyncNCSARequestLog();
log.setFilename("logs/access-yyyy_mm_dd.log");
logHandler.setRequestLog(log);
return logHandler;
}
public Handler getMainServletContext()
{
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
// always need a resource base
context.setResourceBase("path/to/webroot");
ServletHolder jerseyServlet = context.addServlet(ServletContainer.class,"/*");
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter(ServerProperties.PROVIDER_PACKAGES,"org.example.pss.resources");
FilterHolder filterHolder = context.addFilter(CrossOriginFilter.class,"/*",EnumSet.allOf(DispatcherType.class));
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM,"*");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM,"Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin");
filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM,"GET,PUT,POST,DELETE,OPTIONS");
filterHolder.setInitParameter(CrossOriginFilter.PREFLIGHT_MAX_AGE_PARAM,"5184000");
filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM,"true");
// DefaultServlet is always last for a ServletContext
context.addServlet(DefaultServlet.class,"/");
return context;
}
}
I am trying to write an integration test to spin up jetty server locally and then use client to communicate with the rest URI and call the business logic downstream. However, when I start my jetty server it does not relinquish the control, so my client is not executed. So I used threading to start my jetty in a different thread, however, the thread finishes before my client call, it says connection refused. Any approach I can take?
#Test
public void testPerform() {
final JettyServer jettyServer = JettyServer.create();
jettyServer.buildJettyServer(ServletContextHandler.SESSIONS, "/", 8080, TestResource.class);
Runnable runnable = new Runnable()
{
#Override
public void run()
{
jettyServer.start();
}
};
new Thread(runnable).start();
final javax.ws.rs.client.Client client = ClientBuilder.newClient();
final Response response = client.target("http://localhost:8080/test").request().post(Entity.text(""));
jettyServer.stop();
}
Skip the Runnable, skip the new Thread(runnable).start()
The call jettyServer.start() starts the server on its own thread (along with all of the other threads that the server needs.
For a basic example of junit and jetty ...
#Test
public void testGet() throws Exception
{
// Create Server
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
ServletHolder defaultServ = new ServletHolder("default", DefaultServlet.class);
defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir"));
defaultServ.setInitParameter("dirAllowed","true");
context.addServlet(defaultServ,"/");
server.setHandler(context);
// Start Server
server.start();
// Test GET
HttpURLConnection http = (HttpURLConnection)new URL("http://localhost:8080/").openConnection();
http.connect();
assertThat("Response Code", http.getResponseCode(), is(HttpStatus.OK_200));
// Stop Server
server.stop();
}
The #Before and #After junit annotations can also be used. This will start the server before each #Test and stop the server after.
package jetty;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.net.HttpURLConnection;
import java.net.URL;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class JUnitBeforeAfterJettyTest
{
private Server server;
#Before
public void startJetty() throws Exception
{
// Create Server
server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
ServletHolder defaultServ = new ServletHolder("default", DefaultServlet.class);
defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir"));
defaultServ.setInitParameter("dirAllowed","true");
context.addServlet(defaultServ,"/");
server.setHandler(context);
// Start Server
server.start();
}
#After
public void stopJetty()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Test
public void testGet() throws Exception
{
// Test GET
HttpURLConnection http = (HttpURLConnection)new URL("http://localhost:8080/").openConnection();
http.connect();
assertThat("Response Code", http.getResponseCode(), is(HttpStatus.OK_200));
}
}
For the best approach, you can also use the #BeforeClass and #AfterClass techniques, along with auto-binding to an open port. This will only start the server once, per Test Class, run all of the #Test methods, then stop the server once at the end.
package jetty;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class JUnitBeforeAfterClassJettyTest
{
private static Server server;
private static URI serverUri;
#BeforeClass
public static void startJetty() throws Exception
{
// Create Server
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0); // auto-bind to available port
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
ServletHolder defaultServ = new ServletHolder("default", DefaultServlet.class);
defaultServ.setInitParameter("resourceBase",System.getProperty("user.dir"));
defaultServ.setInitParameter("dirAllowed","true");
context.addServlet(defaultServ,"/");
server.setHandler(context);
// Start Server
server.start();
// Determine Base URI for Server
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
serverUri = new URI(String.format("http://%s:%d/",host,port));
}
#AfterClass
public static void stopJetty()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Test
public void testGet() throws Exception
{
// Test GET
HttpURLConnection http = (HttpURLConnection) serverUri.resolve("/").toURL().openConnection();
http.connect();
assertThat("Response Code", http.getResponseCode(), is(HttpStatus.OK_200));
}
}
I am trying to configure symmetric key cipher suite on embedded jetty v9 (using Java 8).
Test server class as follows:
import iaik.security.provider.IAIK;
import java.io.IOException;
import java.security.Security;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
public class TestJettyServer {
public static void main(String[] args) throws Exception {
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setIncludeProtocols(new String[] { "TLSv1" });
Security.addProvider(new IAIK()); // third party provider for cipher suite "TLS_PSK_WITH_AES_128_GCM_SHA256"
sslContextFactory.setIncludeCipherSuites(new String[] { "TLS_PSK_WITH_AES_128_GCM_SHA256" });
HttpConfiguration https = new HttpConfiguration();
https.addCustomizer(new SecureRequestCustomizer());
Server server = new Server();
ServerConnector sslConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"),
new HttpConnectionFactory(https));
sslConnector.setPort(9997);
Connector[] connectors = { sslConnector };
server.setConnectors(connectors);
ServletHandler handler = new ServletHandler();
server.setHandler(handler);
handler.addServletWithMapping(HelloServlet.class, "/*");
server.start();
server.join();
}
public static class HelloServlet extends HttpServlet {
/** The serialVersionUID. */
private static final long serialVersionUID = 1L;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("<h1>Hello SimpleServlet</h1>");
}
}
}
Test client class as follows:
import iaik.security.provider.IAIK;
import java.security.Security;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.ssl.SslContextFactory;
public class TestJettyClient {
public static void main(String[] args) throws Exception {
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setIncludeProtocols(new String[] { "TLSv1" });
Security.addProvider(new IAIK()); // third party provider for cipher suite "TLS_PSK_WITH_AES_128_GCM_SHA256"
sslContextFactory.setIncludeCipherSuites(new String[] { "TLS_PSK_WITH_AES_128_GCM_SHA256" });
HttpClient httpClient = new HttpClient(sslContextFactory);
httpClient.setFollowRedirects(false);
httpClient.start();
httpClient.GET("https://localhost:9997");
}
}
The logs on running server are:
2014-12-17 13:00:55.056:INFO:oejs.Server:main: jetty-9.2.1.v20140609
2014-12-17 13:00:55.275:INFO:oejs.ServerConnector:main: Started ServerConnector#3fee9989{SSL-http/1.1}{0.0.0.0:9997}
2014-12-17 13:00:55.275:INFO:oejs.Server:main: Started #598ms
On running client, the logs on server and client side are:
2014-12-17 13:01:01.509:WARN:oeji.SelectorManager:qtp94438417-19-selector-ServerConnectorManager#3131cfe0/0: Exception while notifying connection SslConnection#436b1df3{NEED_WRAP,eio=-1/-1,di=-1} -> HttpConnection#6a9d584{IDLE}
org.eclipse.jetty.io.RuntimeIOException: javax.net.ssl.SSLHandshakeException: No appropriate protocol
at org.eclipse.jetty.io.ssl.SslConnection.onOpen(SslConnection.java:151)
at org.eclipse.jetty.io.SelectorManager.connectionOpened(SelectorManager.java:259) ...
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol
at sun.security.ssl.Handshaker.activate(Handshaker.java:483) ...
Before I proceed with configuring symmetric key store I would like to get rid of this error - No appropriate protocol.
Is there any way to add handlers to a running embedded Jetty instance? We have migrated an old Jetty 6 based project to Jetty 9 and we need for our plugin system the possibility add and remove dynamically handlers...
See the example below...
Server server = new Server();
[...]
server.start();
[...]
Handler[] existingHandler = server.getHandlers();
// There is no more
server.addHandler(newHandler);
// only this you can do, but only if the server is stopped
server.setHandler(newHandler)
Note: newHandler is a HandlerCollection...
Here a complete code sample. Next to using HandlerCollection(true), it is also important to start the new context handler explicitly.
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
public class DynamicContextHandlers {
public static void main(String[] args) throws Exception {
new DynamicContextHandlers().run();
}
public void run() throws Exception {
int port = 8080;
Server server = new Server(port);
ContextHandler contextHandler = new ContextHandler();
contextHandler.setContextPath("/hello");
contextHandler.setResourceBase(".");
contextHandler.setClassLoader(Thread.currentThread().getContextClassLoader());
contextHandler.setHandler(new HelloHandler(""));
HandlerCollection contextHandlerCollection = new HandlerCollection(true); // important! use parameter
// mutableWhenRunning==true
// add context handler before starting server (started implicitly)
contextHandlerCollection.addHandler(contextHandler);
server.setHandler(contextHandlerCollection);
server.start();
System.out.println("Server started at port " + port + " with context handler for /hello");
System.out.println("Press enter to add context handler for /hello2");
System.in.read();
ContextHandler contextHandler2 = new ContextHandler();
contextHandler2.setContextPath("/hello2");
contextHandler2.setResourceBase(".");
contextHandler2.setClassLoader(Thread.currentThread().getContextClassLoader());
contextHandler2.setHandler(new HelloHandler("2"));
// add handler after starting server.
contextHandlerCollection.addHandler(contextHandler2);
// important! start context explicitly.
contextHandler2.start();
System.out.println("Press enter to exit.");
System.in.read();
server.stop();
}
public class HelloHandler extends AbstractHandler {
String string;
public HelloHandler(String string) {
this.string = string;
}
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(true);
response.getWriter().println("<h1>Hello World" + string + "</h1>");
}
}
}
With Jetty 9.1.0.v20131115 you can use the mutableWhenRunning flag on HandlerCollection constructor ...
HandlerCollection coll = new HandlerCollection(true);
This will ignore the isStarted() tests on the collection itself during .setHandlers(Handlers[]) and .addHandler(Handler) calls.
This behavior is only available for the HandlerCollection itself, you can add individual handlers, or set the entire handler tree without regards to the LifeCycle of the HandlerCollection.
Eg:
Server server = new Server(8080);
HandlerCollection myhandlers = new HandlerCollection(true);
server.setHandler(myhandlers);
// add some initial handlers
myhandlers.setHandlers(new Handlers[] { helloHandler, indexHandler });
// start server
server.start();
// ... at some point later, during runtime
FooHandler fooHandler = new FooHandler();
fooHandler.start();
myhandlers.addHandler(fooHandler);
BarHandler barHandler = new BarHandler();
barHandler.start();
myhandlers.addHandler(barHandler);