Skip to content

Commit

Permalink
Minimal skeleton for a Jetty web app
Browse files Browse the repository at this point in the history
  • Loading branch information
msteiger committed May 9, 2016
1 parent c1cee38 commit fce7c0e
Show file tree
Hide file tree
Showing 30 changed files with 7,969 additions and 0 deletions.
47 changes: 47 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Ignore general
*~
._*
*.bak


# Ignore generated version java file
/src/main/java/org/terasology/web/version/VersionInfo.java


# Ignore Eclipse
/.checkstyle
/.project
/.classpath
/.settings/
/bin/

# Ignore gradle
/build/

# Ignore IntelliJ
/*.iml
/*.ipr
/*.iws
/out/

# Ignore Linux
*.directory

#Ignore OSX
Icon
.DS_Store
.DS_Store?
.Spotlight-V100
.DocumentRevisions-V100
.TemporaryItems
.Trashes
.dbfseventsd
.fseventsd
.VolumeIcon.icns

#Ignore Windows
ehthumbs.db
Thumbs.db

# Ignore output
*.log
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ apply plugin: 'application'
apply plugin: 'eclipse'
apply plugin: 'idea'

apply from: 'config/gradle/versioning.gradle'

// Same repository configuration as root project
repositories {
// External libs - jcenter is Bintray and is supposed to be a superset of Maven Central, but do both just in case
Expand Down
18 changes: 18 additions & 0 deletions config/gradle/versioning.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

task createVersionJavaFile(type:Copy) {
description = 'Creates a java version file based on the template in the resources folder'

inputs.property('version', version) // the up-to-date flag depends on the version property

from('src/main/resources/VersionInfo.template')
into('src/main/java/org/terasology/web/version')
rename '(.*).template', '$1.java'

expand(VERSION: version)

doLast {
logger.lifecycle("Updated 'VersionInfo.java' to version $version");
}
}

compileJava.dependsOn createVersionJavaFile
112 changes: 112 additions & 0 deletions src/main/java/org/terasology/web/ServerMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright 2015 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.web;

import java.util.Locale;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.freemarker.FreemarkerMvcFeature;
import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.web.io.GsonMessageBodyHandler;
import org.terasology.web.servlet.AboutServlet;


/**
*/
public final class ServerMain {

private static final Logger logger = LoggerFactory.getLogger(ServerMain.class);

private ServerMain() {
// no instances
}

/**
* @param args ignored
* @throws Exception
*/
public static void main(String[] args) throws Exception {

String portEnv = System.getenv("PORT");
if (portEnv == null) {
portEnv = "8080";
logger.warn("Environment variable 'PORT' not defined - using default {}", portEnv);
}
Integer port = Integer.valueOf(portEnv);

// this is mostly for I18nMap, but can have an influence on other
// string formats. Note that metainfo.ftl explicitly sets the locale to
// define the date format.
Locale.setDefault(Locale.ENGLISH);

Server server = createServer(port.intValue(),
new AboutServlet());

server.start();
logger.info("Server started on port {}!", port);

server.join();
}

public static Server createServer(int port, Object... annotatedObjects) throws Exception {
Server server = new Server(port);

ResourceHandler logFileResourceHandler = new ResourceHandler();
logFileResourceHandler.setDirectoriesListed(true);
logFileResourceHandler.setResourceBase("logs");

ContextHandler logContext = new ContextHandler("/logs"); // the server uri path
logContext.setHandler(logFileResourceHandler);

ResourceHandler webResourceHandler = new ResourceHandler();
webResourceHandler.setDirectoriesListed(false);
webResourceHandler.setResourceBase("web");

ContextHandler webContext = new ContextHandler("/"); // the server uri path
webContext.setHandler(webResourceHandler);

ResourceConfig rc = new ResourceConfig();
rc.register(new GsonMessageBodyHandler()); // register JSON serializer
rc.register(FreemarkerMvcFeature.class);

for (Object servlet : annotatedObjects) {
rc.register(servlet);
}

ServletContextHandler jerseyContext = new ServletContextHandler(ServletContextHandler.GZIP);
jerseyContext.setContextPath("/");
jerseyContext.setResourceBase("templates");
jerseyContext.addServlet(new ServletHolder(new ServletContainer(rc)), "/*");

HandlerList handlers = new HandlerList();
handlers.addHandler(logContext);
handlers.addHandler(webContext);
handlers.addHandler(jerseyContext);

server.setHandler(handlers);

return server;
}
}
109 changes: 109 additions & 0 deletions src/main/java/org/terasology/web/io/GsonMessageBodyHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright 2015 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.web.io;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

import org.terasology.naming.Name;
import org.terasology.naming.Version;
import org.terasology.naming.gson.NameTypeAdapter;
import org.terasology.naming.gson.VersionTypeAdapter;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
* Adapted from
* http://eclipsesource.com/blogs/2012/11/02/integrating-gson-into-a-jax-rs-based-application/
*/
@Provider
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public final class GsonMessageBodyHandler implements MessageBodyWriter<Object>, MessageBodyReader<Object> {

private static final Gson GSON = new GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Version.class, new VersionTypeAdapter())
.registerTypeAdapter(Name.class, new NameTypeAdapter())
.create();

@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}

@Override
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException {

try (Reader streamReader = new InputStreamReader(entityStream, StandardCharsets.UTF_8)) {

Type jsonType;
if (type.equals(genericType)) {
jsonType = type;
} else {
jsonType = genericType;
}

return GSON.fromJson(streamReader, jsonType);
}
}

@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}

@Override
public long getSize(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return -1;
}

@Override
public void writeTo(Object object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {

try (Writer writer = new OutputStreamWriter(entityStream, StandardCharsets.UTF_8)) {

Type jsonType;
if (type.equals(genericType)) {
jsonType = type;
} else {
jsonType = genericType;
}

GSON.toJson(object, jsonType, writer);
}
}
}
49 changes: 49 additions & 0 deletions src/main/java/org/terasology/web/servlet/AboutServlet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2015 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.web.servlet;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.glassfish.jersey.server.mvc.Viewable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.web.version.VersionInfo;

import com.google.common.collect.ImmutableMap;

/**
* Show the about html page.
*/
@Path("/")
public class AboutServlet {

private static final Logger logger = LoggerFactory.getLogger(AboutServlet.class);

@GET
@Path("home")
@Produces(MediaType.TEXT_HTML)
public Viewable about() {
logger.info("Requested about as HTML");
ImmutableMap<Object, Object> dataModel = ImmutableMap.builder()
.put("version", VersionInfo.getVersion())
.build();
return new Viewable("/about.ftl", dataModel);
}
}
36 changes: 36 additions & 0 deletions src/main/resources/VersionInfo.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2014 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.web.version;

/**
* Do not modify this file! All changes will be overwritten.
* This file is auto-generated by the gradle task createVersionJavaFile
* See build.gradle for the task and for the definition of the version string
*/
public final class VersionInfo {

private VersionInfo() {
// no instances!
}

/**
* @return The version string
*/
public static String getVersion() {
return "${VERSION}";
}
}
Loading

0 comments on commit fce7c0e

Please sign in to comment.