Server
First of all it’s important to say that Pippo is based on Servlet 3.1 so, it needs a Servlet container to run properly.
Most server-side Java applications (e.g. web or service-oriented) are intended to run within a container.
The traditional way to package these apps for distribution is to bundle them as a WAR file.
Of course you can use the above model for your application development or you can use the simple way.
Rather than your application being deployed to a container, an embedded container is deployed within the application itself.
Pippo comes with Jetty as embedded web server. You can choose another container if you want (for example Tomcat).
See below the classic Hello World
in Pippo:
public class HelloWorld {
public static void main(String[] args) {
Pippo pippo = new Pippo();
pippo.GET("/", routeContext -> routeContext.send("Hello World!")); // add a route
pippo.start();
}
}
Sure, the number of lines can decrease considerable if you use variant:
public class HelloWorld {
public static void main(String[] args) {
Pippo.send("Hello World!");
}
}
if you consider that in first variant they are too many lines of code.
You can run HelloWorld class from your IDE (or command line) as a normal (desktop) application.
The default port
for embedded web server is 8338 so open your internet browser and type http://localhost:8338
to
see the result.
You can change some aspects (settings) of the embedded web server using:
new Pippo()
.setPort(8081) // change port to 8081
.start();
or
Pippo pippo = new Pippo();
WebServer server = pippo.getServer(); // if you want a fine tuning of the web server
server.getSettings().port(8081);
server.setPippoFilterPath("/pippo/*");
pippo.start();
Probably the best approach to specify the server port for an embedded server is via application settings.
Simple set the server.port
variable from your src\main\resources\main\conf\application.properties
with your value:
# Control the port that Pippo binds
server.port = 8081
Using the same application.properties
you can change other server parameters like
# Control the network ip address Pippo binds
# Specify 0.0.0.0 for all available interfaces
server.host = localhost
# Specify the context path of the application
server.contextPath = /
# HTTPS
#server.keystoreFile =
#server.keystorePassword =
#server.truststoreFile =
By default, Pippo use context path /
(root) but you can change it using
server.contextPath
property- programmatically
new Pippo() .setPort(8081) .setFilterPath("/pippo/*") // <<< .start();
Pippo detects automatically the web server using ServiceLoader.
If you want to use a web server in your application, you must add pippo-<server name>
as dependency for your project.
Other option is to set programmatically the desired web server using Pippo#setServer(WebServer server)
.
Pippo comes (out of the box) with some web servers (most popular):
To use one of these servers just add a dependency in your project:
<dependency>
<groupId>ro.pippo</groupId>
<artifactId>pippo-jetty</artifactId>
<version>${pippo.version}</version>
</dependency>
In Pippo, the web servers are plug and play and interchangeable (you can change the web server without to change your code).
You never work directly with classes from Jetty, Tomcat or other web server.
Are some situations (very rare) when the behavior provided by an WebServer
instance supplied automatically by Pippo need fine tuning.
You want to have access to some advanced settings.
In these situations you need to create a custom WebServer.
The idea is to create a custom WebServer if you want to override some aspects (methods) of that server or
if you want free access to the servlet container (Jetty, Tomcat, …).
Show below an concrete example of custom JettyServer
with persistent sessions
public class MyJettyServer extends JettyServer {
@Override
protected ServletContextHandler createPippoHandler() {
ServletContextHandler handler = super.createPippoHandler();
// set session manager with persistence
HashSessionManager sessionManager = new HashSessionManager();
try {
sessionManager.setStoreDirectory(new File("sessions-storage"));
} catch (IOException e) {
throw new PippoRuntimeException(e);
}
sessionManager.setLazyLoad(true); // other possible option
handler.setSessionHandler(new SessionHandler(sessionManager));
return handler;
}
}
public class Main {
public static void main(String[] args) {
// the routes are added via MyApplication class
new Pippo(new MyApplication()).setServer(new MyJettyServer()).start();
}
}
The WebServer
abstraction allows you to add a Servlet
or a Filter
.
Also, WebServer
allows you to add servlet listeners in any supported servlet container
via addListener(Class<? extends EventListener> listener)
method.
The Servlet’s listener supported are (the list is not complete):
- javax.servlet.ServletContextListener
- javax.servlet.ServletContextAttributeListener
- javax.servlet.ServletRequestListener
- javax.servlet.ServletRequestAttributeListener
- javax.servlet.http.HttpSessionListener
- javax.servlet.http.HttpSessionBindingListener
- javax.servlet.http.HttpSessionAttributeListener
- javax.servlet.http.HttpSessionActivationListener
For the same task but using a more generic approach you can use WebServerInitializer
.
Below I present you a code snippet that add a servlet to Pippo:
import org.kohsuke.MetaInfServices;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ro.pippo.core.WebServerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
@MetaInfServices
public class ServletAppender implements WebServerInitializer {
private static final Logger log = LoggerFactory.getLogger(ServletAppender.class);
@Override
public void init(ServletContext servletContext) {
ServletRegistration.Dynamic demoServlet = servletContext.addServlet("demo", DemoServlet.class);
demoServlet.setLoadOnStartup(1);
demoServlet.addMapping("/demo");
// other possible settings for demoServlet
log.debug("Added servlet '{}' to '{}'", demoServlet.getClassName(), demoServlet.getMappings().iterator().next());
}
@Override
public void destroy(ServletContext servletContext) {
// do nothing
}
}
import ro.pippo.core.Pippo;
import static ro.pippo.core.route.Route.GET;
public class ServletDemo {
public static void main(String[] args) {
Pippo pippo = new Pippo();
// set pippo filter path
pippo.getServer().setPippoFilterPath("/app/*");
// add route
pippo.GET("/", routeContext -> routeContext.send("Hello from Pippo route!"));
pippo.start();
}
}
DON’T forget to add @MetaInfServices
on your implementation of WebServerInitializer
! This annotation generates META-INF/services
files automatically.
The full code is available in pippo-demo-servlet project.
If you need to create support for another embedded web server that is not implemented in Pippo or third-party modules than all you need to do is to implement WebServer or to extends AbstractWebServer.
If you want to make your embedded server plugable for Pippo than you must add @MetaInfServices(WebServer.class)
annotation to
your class
@MetaInfServices(WebServer.class)
public class JettyServer extends AbstractWebServer<JettySettings> {
// attributes, methods, ...
}
A more complex demo project that shows you how to integrate Jersey is available in pippo-demo-jersey project.
This demo is the code source of the article Pippo and Jersey (JAX-RS): A Match Made in Heaven
that is availables on DZone.
Server Settings
Different Server settings can be added via application.properties
. Below are the settings that are supported:
Jetty
Currently, jetty.maxThreads
, jetty.minThreads
and jetty.idleTimeout
can be passed in application.properties
.
jetty.maxThreads
- maximum number of threads to be allocated with default value200
jetty.minThreads
- minimum number of threads to be allocated with default value8
jetty.idleTimeout
- idle timeout for each thread before it is stopped with default value30000
Note: Only when valid maxThreads is passed then, minThreads and idleTimeouts are consumed. In other cases, default values are used
For Detailed description about these settings, please refer here
Undertow
Currently, Pippo supports all UndertowOptions
. UndertowOptions can be categorized into 3 subcategories.
- Server Options - All the server options specified must start with
undertow.server.
- Worker Options - All the worker options specified must start with
undertow.worker.
- Socket Options - All the worker options specified must start with
undertow.socket.
Along with these configurations, all other supported settings are mentioned below:
undetow.ioThreads
- Number of IO threads that needs to be allocatedundertow.workerThreads
- Number of worker threads that needs to be allocatedundertow.bufferSize
,undertow.buffersPerRegion
andundertow.directBuffers
are the other supported settings.
For Detailed description about these settings, please refer here
Sample properties file with undertow settings
undertow.ioThreads=8
undertow.workerThreads=64
undertow.server.NO_REQUEST_TIMEOUT=20000
undertow.socket.TCP_NODELAY=true
Tomcat
Currently, tomcat.clientAuth
, tomcat.maxConnections
, tomcat.baseFolder
, tomcat.keyAlias
and tomcat.keyType
can be passed in application.properties
For Detailed description about these settings, please refer here