Developing web applications is quick and easy at the same moment, users just have to follow the steps below:
Let's add first the dependencies in the pom.xml file:
<dependencies> ... <dependency> <groupId>org.99soft.shs</groupId> <artifactId>shs-api</artifactId> <version>0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.99soft.shs</groupId> <artifactId>shs-core</artifactId> <version>0.1</version> </dependency> ... </dependencies>
We first need a ResponseBodyWriter implementation based on Velocity:
class VelocityResponseBodyWriter implements ResponseBodyWriter { private final VelocityContext velocityContext; private final Template template; public VelocityResponseBodyWriter( VelocityContext velocityContext, Template template ) { this.velocityContext = velocityContext; this.template = template; } @Override public String contentType() { return "text/html;charset=UTF-8"; } @Override public void write( WritableByteChannel output ) throws IOException { StringWriter stringWriter = new StringWriter(); template.merge( velocityContext, stringWriter ); output.write( utf8ByteBuffer( stringWriter.toString() ) ); } }
The we are ready to implement the RequestHandler:
class VelocityRequestHandler extends BaseRequestHandler { public VelocityRequestHandler( File baseDir ) { Properties properties = new Properties(); properties.setProperty( "file.resource.loader.path", baseDir.getAbsolutePath() ); Velocity.init( properties ); } @Override protected void get( Request request, Response response ) throws IOException { VelocityContext velocityContext = new VelocityContext(); velocityContext.put( "request", request ); Template template = Velocity.getTemplate( request.getPath() ); response.setStatus( OK ); response.setBody( new VelocityResponseBodyWriter( velocityContext, template ) ); } }
As you can read in the code below, the RequestHandler puts the Request instance in the VelocityContext, so we can play a little with data inside it to create a page:
<html> <head><title>Request from $request.getClientHost()</title></head> <body> <div> <p>HTTP Method: <code>$request.getMethod()</code></p> #foreach( $header in $request.getHeaders().getAllKeys() ) <p>$header:#foreach( $headerValue in $request.getHeaders().getValues( $header ) ) <code>$headerValue</code>#end</p> #end <p>Session ID: <code>$request.getSession().getId()</code></p> </div> </body> </html>
Now that all pieces have been set-up, all that is missing is a main entry point to launch the server
class Main { private static Logger logger = LoggerFactory.getLogger( Main.class ); /** * let's simplify and assume the *FromArgs( args ) method implemented somewhere else */ public static void main( String[] args ) { final File siteDir = siteDirFromArgs( args ); final HttpServer httpServer = new SimpleHttpServer(); try { httpServer.init( new AbstractHttpServerConfiguration() { @Override protected void configure() { bindServerToHost( hostFromArgs( args ) ); bindServerToPort( portFromArgs( args ) ); serveRequestsWithThreads( threadsFromArgs( args ) ); sessionsHaveMagAge( sessionMaxAgeFromArgs( args ) ); keepAliveConnectionsHaveTimeout( keepAliveTimeOutFromArgs( args ) ); serve( "*.vm" ).with( new VelocityRequestHandler( siteDir ) ); when( NOT_FOUND ).serve( new File( siteDir, "404.html" ) ); when( INTERNAL_SERVER_ERROR ).serve( new File( siteDir, "500.html" ) ); } } ); } catch ( Throwable cause ) { logger.error( "Server cannot be initialized", cause ); System.exit( 1 ); } Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { try { httpServer.stop(); } catch ( ShutdownException e ) { logger.error( "Execution terminated with errors", e ); } } } try { httpServer.start(); } catch ( RunException se ) { logger.error( "Server cannot be started", se ); System.exit( 1 ); } } }
That's all! You can now run your Apache Velocity based dynamic site! :)
Users that want to hack the original source code, need:
Once cloned the project:
git clone git@github.com:simonetripodi/shs.git
go to the clone location
cd shs
and launch the Maven packaging:
mvn package
Maven will build the three main modules: the APIs, the Core implementation and the Simple Demo
[INFO] Reactor Build Order: [INFO] [INFO] Simple HttpServer [INFO] Simple HttpServer :: APIs [INFO] Simple HttpServer :: Core implementation [INFO] Simple HttpServer :: Simple Demo [INFO]
The APIs and the Core implementation will be packaged in jar artifacts, the Simple Demo targets instead are tar.gz and zip assemblies that contain a self-contained application with the embedded Web server.