/*
* Databinder: a simple bridge from Wicket to Hibernate
* Copyright (C) 2007 Nathan Hamblen nathan@technically.us
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.databinder.web;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.wicket.util.string.Strings;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.ajp.Ajp13SocketConnector;
import org.mortbay.jetty.handler.MovedContextHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Optional starter class for embedded Jetty. Client applications may pass
* this classname to the Java runtime to serve with no other configuration. The webroot
* defaults to src/main/webapp, and the server to a context named after the project directory
* with HTTP on port 8080. <tt>jetty.warpath</tt>, <tt>jetty.contextpath</tt>,
* <tt>jetty.port</tt>, and <tt>jetty.ajp.port</tt> system properties
* may be used to override (e.g. <tt>-Djetty.port=80</tt> as a command line parameter). AJP
* is enabled by specifying a port, and HTTP disabled by setting jetty.port to 0.
*
* <p>Some customization can be accomplished by extending this class and overriding
* the {@link DataServer#configure(Server, WebAppContext)} method. The subclass
* will need a static main(args) method that constructs an instance of itself, similar
* to {@link DataServer#main(String[])}
* @author Nathan Hamblen
*/
public class DataServer {
private static final Logger log = LoggerFactory.getLogger(DataServer.class);
/** Constructs DataServer, kicking off server. */
public static void main(String[] args)
{
new DataServer();
}
/** Starts web sever using any parameters supplied. Calls
* {DataServer{@link #configure(Server, WebAppContext)} immediately before
* starting server.
*/
public DataServer() {
try {
Server server = new Server();
WebAppContext web = new WebAppContext();
URL classes = null;
String projectDir = null;
try {
// look for project's classes directory
URL[] urls = ((URLClassLoader)DataServer.class.getClassLoader()).getURLs();
for (URL url : urls)
if (url.getPath().endsWith("classes/")) {
classes = url;
break;
}
} catch (Exception e) {
log.info("unable to find project path by classloader", e);
}
if (classes == null) {
projectDir = new File(".").getCanonicalPath();
log.info("project path fram current directory: " + projectDir);
} else {
projectDir = classes.toURI().resolve("../..").getPath();
log.info("project path as found by classloader: " + projectDir);
}
String contextPath = System.getProperty("jetty.contextpath",
System.getProperty("jetty.contextPath"));
if (Strings.isEmpty(contextPath)) {
Matcher m = Pattern.compile("(\\/[^\\/]+)/?$").matcher(projectDir);
if (!m.find())
throw new RuntimeException("Project path not as expected: " + projectDir);
contextPath = m.group(1);
log.info("context path by project directory: " + contextPath);
}
else
log.info("jetty.contextPath property: " + contextPath);
web.setContextPath(contextPath);
String warPath = System.getProperty("jetty.warpath",
System.getProperty("jetty.warPath"));
if (Strings.isEmpty(warPath)) warPath = projectDir + "/src/main/webapp";
if (!new File(warPath).isDirectory()) {
log.error("Unable to find webapps path: " + warPath +
" \nPlease ensure that this project is the first on its " +
"classpath, or set a valid jetty.warpath JVM property.");
return;
}
else log.info("jetty.warPath property: " + warPath);
web.setWar(warPath);
server.addHandler(web);
if (!contextPath.equals("/"))
server.addHandler(new MovedContextHandler(server, "/", contextPath));
List<Connector> conns = new ArrayList<Connector>(2);
int httpPort = 8080;
try {
httpPort = Integer.valueOf(System.getProperty("jetty.port"));
log.info("jetty.port property: " + httpPort);
} catch (NumberFormatException e) { }
if (httpPort != 0) {
SelectChannelConnector httpConn = new SelectChannelConnector();
httpConn.setPort(httpPort);
conns.add(httpConn);
}
int ajpPort = 0;
try {
ajpPort = Integer.valueOf(System.getProperty("jetty.ajp.port"));
log.info("jetty.ajp.port property: " + ajpPort);
} catch (NumberFormatException e) { }
if (ajpPort != 0) {
Ajp13SocketConnector ajpConn = new Ajp13SocketConnector();
ajpConn.setPort(ajpPort);
conns.add(ajpConn);
}
server.setConnectors(conns.toArray(new Connector[conns.size()]));
server.setStopAtShutdown(true);
configure(server, web);
server.start();
if (httpPort != 0)
log.info("Ready at http://localhost:" + httpPort + contextPath);
if (ajpPort != 0)
log.info("Ready at ajp://localhost:" + ajpPort + contextPath);
server.join();
stopped(server, web);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Override to customize the server and context objects.
* @see DataServer#DataServer()
*/
protected void configure(Server server, WebAppContext context) throws Exception { }
/**
* Override to perform action after server stops
* @see DataServer#DataServer()
*/
protected void stopped(Server server, WebAppContext context) throws Exception { }
}