com.sun.grizzly.http.embed.GrizzlyWebServer Maven / Gradle / Ivy
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the license at
* https://glassfish.dev.java.net/public/CDDLv1.0.html or
* glassfish/bootstrap/legal/CDDLv1.0.txt.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at glassfish/bootstrap/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* you own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
*/
package com.sun.grizzly.http.embed;
import com.sun.grizzly.arp.DefaultAsyncHandler;
import com.sun.grizzly.arp.AsyncFilter;
import com.sun.grizzly.arp.AsyncHandler;
import com.sun.grizzly.http.Management;
import com.sun.grizzly.http.SelectorThread;
import com.sun.grizzly.tcp.StaticResourcesAdapter;
import com.sun.grizzly.tcp.http11.GrizzlyAdapter;
import com.sun.grizzly.tcp.http11.GrizzlyAdapterChain;
import com.sun.grizzly.tcp.http11.GrizzlyRequest;
import com.sun.grizzly.tcp.http11.GrizzlyResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
/**
*
* This class creates a WebServer that listen for http request. By default,
* creating an instance of this class can be used as it is to synchronously serve resources located
* under {@link #webResourcesPath}. By default, the {@link StaticResourcesAdapter} is
* used when there is no {@link GrizzlyAdapter} specified. The {@link StaticResourcesAdapter}
* allow servicing of static resources like html files, images files, etc.
*
* The {@link GrizzlyAdapter} provides developpers with a simple and consistent mechanism for extending
* the functionality of the Grizzly WebServer and for bridging existing
* http based technology like JRuby-on-Rail, Servlet, Bayeux Protocol or any
* http based protocol.
*
You can extend the GrizzlyWebServer by adding one or serveral
* {@link GrizzlyAdapter}. If more that one are used, the {@link GrizzlyAdapterChain}
* will be used to invoke {@link GrizzlyAdapter}s one by one. As soon as one
* {@link GrizzlyAdapter} can serve the request, the chain will be stopped and
* the response will be sent back to the client. A {@link GrizzlyAdapter} gets invoked
* as soon as the http request has been parsed and
* decoded. The {@link GrizzlyAdapter#service(GrizzlyRequest,GrizzlyResponse} method is invoked with a
* {@link GrizzlyRequest} and {@link GrizzlyResponse} that can be used to extend the
* functionality of the Web Server. By default, all http requests are synchronously
* executed.
*
Asynchronous request processing is automatically enabled
* as soon as one or several {@link AsyncFilter} are added, using the
* {@link #addAsyncHandler} method. {@link AsyncFilter} can be used when
* asynchronous operation are required, like suspending the current http request,
* delaying the invokation of {@link GrizzlyAdapter} etc. The state of the
* request processing can be managed using {@link AsyncExecutor}, like resuming
* the process so {@link GrizzlyAdapter}s can be invoked.
*
* The following picture describes how {@link AsyncFilter} and {@link GrizzlyAdapter}
* are invoked.
*
* ----------------------------------------------------------------------------
* - AsyncFilter.doFilter() ---> AsyncExecutor.execute() -------| -
* - | -
* - | -
* - | -
* - AsyncFilter.doFilter() <-- GrizzlyAdapter2.service() <------| -
* ----------------------------------------------------------------------------
*
* Here is some examples:
* Synchronous Web Server servicing static resources
GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
try{
ws.start();
} catch (IOException ex){
// Something when wrong.
}
* Synchronous Web Server servicing customized resources
GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
try{
ws.addGrizzlyAdapter(new GrizzlyAdapter(){
public void service(GrizzlyRequest request, GrizzlyResponse response){
try {
response.getWriter().println("Grizzly is soon cool");
} catch (IOException ex) {
}
}
});
ws.start();
} catch (IOException ex){
// Something when wrong.
}
* 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.
}
* Synchronous Web Server servicing two 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);
ServletAdapter sa = new ServletAdapter();
sa.setRootFolder("/Path/To/Exploded/War2/File");
sa.setServlet(new MySecondServlet());
ws.addGrizzlyAdapter(sa);
ws.start();
} catch (IOException ex){
// Something when wrong.
}
*
* Asynchronous Web Server servicing customized resources
* The example below delay the request processing for 10 seconds, without holding
* a thread.
*
GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
try{
ws.addAsyncFilter(new AsyncFilter() {
private final ScheduledThreadPoolExecutor scheduler =
new ScheduledThreadPoolExecutor(1);
public boolean doFilter(final AsyncExecutor asyncExecutor) {
//Throttle the request
scheduler.schedule(new Callable() {
public Object call() throws Exception {
asyncExecutor.execute();
asyncExecutor.postExecute();
return null;
}
}, 10, TimeUnit.SECONDS);
// Call the next AsyncFilter
return true;
}
});
ws.addGrizzlyAdapter(new GrizzlyAdapter(){
public void service(GrizzlyRequest request, GrizzlyResponse response){
try {
response.getWriter().println("Grizzly is soon cool");
} catch (IOException ex) {
}
}
});
ws.start();
} catch (IOException ex){
// Something when wrong.
}
* Asynchronous Web Server servicing Servlet
* The example below delay the request processing for 10 seconds, without holding
* a thread.
*
GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
try{
ws.addAsyncFilter(new AsyncFilter() {
private final ScheduledThreadPoolExecutor scheduler =
new ScheduledThreadPoolExecutor(1);
public boolean doFilter(final AsyncExecutor asyncExecutor) {
//Throttle the request
scheduler.schedule(new Callable() {
public Object call() throws Exception {
asyncExecutor.execute();
asyncExecutor.postExecute();
return null;
}
}, 10, TimeUnit.SECONDS);
// Call the next AsyncFilter
return true;
}
});
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.
}
* Asynchronous Web Server servicing Servlet and supporting the Bayeux Protocol
GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
try{
// Add Comet Support
ws.addAsyncFilter(new CometAsyncFilter());
//Add Bayeux support
CometdAdapter cometdAdapter = new CometdAdapter();
ws.addGrizzlyAdapter(cometdAdapter);
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.
}
* Synchronous Web Server servicing static resources eand exposed using JMX Mbeans
GrizzlyWebServer ws = new GrizzlyWebServer(path);
ws.enableJMX(new Management() {
public void registerComponent(Object bean, ObjectName oname, String type)
throws Exception{
Registry.getRegistry().registerComponent(bean,oname,type);
}
public void unregisterComponent(ObjectName oname) throws Exception{
Registry.getRegistry().
unregisterComponent(oname);
}
});
ws.start();
}
}
*
* @author Jeanfrancois Arcand
*/
public class GrizzlyWebServer {
// The port
private int defaultPort = 8080;
// The underlying {@link SelectorThread}
private SelectorThread st;
// SelectorThread mBean
private ObjectInstance stMBean;
// The underlying {@link GrizzlyAdapterChain}
private GrizzlyAdapterChain adapterChains = new GrizzlyAdapterChain();
// List of {@link GrizzlyAdapter}
private ArrayList adapters = new ArrayList();
// Are we started?
private boolean isStarted = false;
// List of {@link AsyncFilter}
private ArrayList asyncFilters = new ArrayList();
// The path to static resource.
private String webResourcesPath = ".";
// The mBean default object name.
private String mBeanName = "com.sun.grizzly:type=GrizzlyWebServer,name=GrizzlyHttpEngine-"
+ defaultPort;
// The {@link Statistis} instance associated with this instance.
private Statistics statistics;
/**
* Create a default GrizzlyWebServer
*/
public GrizzlyWebServer(){
createSelectorThread(defaultPort,5);
}
/**
* Create a WebServer that listen on port
* @param port The port opened
*/
public GrizzlyWebServer(int port){
createSelectorThread(port,5);
}
/**
* Create a WebServer which server files from {@link #webResourcesPath}
* @param webResourcesPath the path to the web resource (ex: /var/www)
*/
public GrizzlyWebServer(String webResourcesPath){
createSelectorThread(defaultPort, 5);
this.webResourcesPath = webResourcesPath;
}
/**
* Create a WebServer that listen on port
* @param port The port opened
*/
public GrizzlyWebServer(int port, int maxThreads){
createSelectorThread(port, maxThreads);
}
/**
* Create a WebServer that listen on port
* @param port The port opened
* @param webResourcesPath the path to the web resource (ex: /var/www)
*/
public GrizzlyWebServer(int port, String webResourcesPath){
createSelectorThread(port, 5);
this.webResourcesPath = webResourcesPath;
}
/**
* Create a WebServer that listen on port
* @param port The port opened
* @param maxThreads The maximum number of Thread created
* @param webResourcesPath the path to the web resource (ex: /var/www)
*/
public GrizzlyWebServer(int port, int maxThreads, String webResourcesPath){
createSelectorThread(port, maxThreads);
this.webResourcesPath = webResourcesPath;
}
/**
* Create an underlying {@link SelectorThread}
* @param port The port to listen to.
* @param maxThreads the maximum number of Threads created.
*/
private void createSelectorThread(int port, int maxThreads){
st = new SelectorThread();
st.setPort(port);
st.setMaxThreads(maxThreads);
}
/**
* Return the underlying {@link SelectorThread}. Only advanced users
* should manipulate that class.
* @return {@link SelectorThread}
*/
public SelectorThread getSelectorThread(){
return st;
}
/**
* Add an {@link AsyncFilter}. Adding {@link AsyncFilter} automatically
* enable Grizzly Asynchronous Request Processing mode. {@link AsyncFilter}s
* are always invoked before {@link GrizzlyAdapter}
*
* @param asyncFilter An {@link AsyncFilter}
*/
public void addAsyncFilter(AsyncFilter asyncFilter){
asyncFilters.add(asyncFilter);
}
/**
* Add a {@link GrizzlyAdapter}. {@link GrizzlyAdapter} will be invoked by
* Grizzly in the order they are added, e.g the first added is always the
* first invoked. {@link GrizzlyAdapter}s
* are always invoked after {@link AsyncFilter}
* @param grizzlyAdapter a {@link GrizzlyAdapter}
*/
public void addGrizzlyAdapter(GrizzlyAdapter grizzlyAdapter){
adapters.add(grizzlyAdapter);
}
/**
* Start the GrizzlyWebServer and start listening for http requests. Calling
* this method several time has no effect once GrizzlyWebServer has been started.
* @throws java.io.IOException
*/
public void start() throws IOException{
if (isStarted) return;
isStarted = true;
// Use the default
if (adapters.size() == 0){
st.setAdapter(new StaticResourcesAdapter(webResourcesPath));
} if (adapters.size() == 1){
st.setAdapter(adapters.get(0));
} else {
for (GrizzlyAdapter adapter: adapters){
adapterChains.addGrizzlyAdapter(adapter);
}
st.setAdapter(adapterChains);
adapterChains.setHandleStaticResources(true);
adapterChains.setRootFolder(webResourcesPath);
}
if (asyncFilters.size() > 0){
st.setEnableAsyncExecution(true);
AsyncHandler asyncHandler = new DefaultAsyncHandler();
for (AsyncFilter asyncFilter: asyncFilters){
asyncHandler.addAsyncFilter(asyncFilter);
}
st.setAsyncHandler(asyncHandler);
}
try {
st.listen();
} catch (InstantiationException ex) {
throw new IOException(ex.getMessage());
}
}
/**
* Enable JMX Management by configuring the {@link Management}
* @param Management An instance of the {@link Management} interface
*/
public void enableJMX(Management jmxManagement){
if (jmxManagement == null) return;
st.setManagement(jmxManagement);
try {
ObjectName sname = new ObjectName(mBeanName);
jmxManagement.registerComponent(st, sname, null);
} catch (Exception ex) {
SelectorThread.logger().log(Level.SEVERE, "Enabling JMX failed", ex);
}
}
/**
* Return a {@link Statistics} instance that can be used to gather
* statistics. By default, the {@link Statistics} object is not
* gathering statistics. Invoking {@link Statistics#startGatheringStatistics}
* will do it.
*/
public Statistics getStatistics(){
if (statistics == null){
statistics = new Statistics(st);
}
return statistics;
}
/**
* Stop the GrizzlyWebServer.
*/
public void stop(){
if (!isStarted) return;
isStarted = false;
st.stopEndpoint();
}
/**
* Return an already configured {@link GrizzlyWebServer} that can serves
* static resources.
* @param path the directory to serve static resource from.
* @return a ready to use {@link GrizzlyWebServer} that listen on port 8080
*/
public final static GrizzlyWebServer newConfiguredInstance(String path){
GrizzlyWebServer ws = new GrizzlyWebServer(8080);
ws.addGrizzlyAdapter(new GrizzlyAdapter(path){
{
setHandleStaticResources(true);
}
@Override
public void service(GrizzlyRequest request, GrizzlyResponse response) {
try {
response.setStatus(404);
response.flushBuffer();
} catch (IOException ex) {
Logger.getLogger(GrizzlyWebServer.class.getName()).log(
Level.SEVERE, null, ex);
}
}
});
return ws;
}
}