Simple, freemarker based textual UI
authorJaroslav Tulach <jtulach@netbeans.org>
Tue, 11 Aug 2009 14:26:49 +0200
changeset 41c94f68ddef59
parent 40 e45bc8ad2eaf
child 42 c5726abc1218
Simple, freemarker based textual UI
freemarkerdor/pom.xml
freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/FreemarkerProcessor.java
freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java
freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt
freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/index.fmt
pom.xml
webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Quoridor.java
webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/freemarkerdor/pom.xml	Tue Aug 11 14:26:49 2009 +0200
     1.3 @@ -0,0 +1,59 @@
     1.4 +<?xml version="1.0" encoding="UTF-8"?>
     1.5 +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
     1.6 +    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     1.7 +  <modelVersion>4.0.0</modelVersion>
     1.8 +  <parent>
     1.9 +    <artifactId>all-quoridor</artifactId>
    1.10 +    <groupId>org.apidesign</groupId>
    1.11 +    <version>1.0</version>
    1.12 +  </parent>
    1.13 +  <groupId>org.apidesign</groupId>
    1.14 +  <artifactId>freemarkerdor</artifactId>
    1.15 +  <version>1.0-SNAPSHOT</version>
    1.16 +  <name>freemarkerdor</name>
    1.17 +  <url>http://maven.apache.org</url>
    1.18 +  <dependencies>
    1.19 +    <dependency>
    1.20 +      <groupId>junit</groupId>
    1.21 +      <artifactId>junit</artifactId>
    1.22 +      <version>3.8.1</version>
    1.23 +      <scope>test</scope>
    1.24 +    </dependency>
    1.25 +    <dependency>
    1.26 +      <groupId>${project.groupId}</groupId>
    1.27 +      <artifactId>webidor</artifactId>
    1.28 +      <version>1.0</version>
    1.29 +    </dependency>
    1.30 +    <dependency>
    1.31 +      <groupId>org.netbeans.modules</groupId>
    1.32 +      <artifactId>org-netbeans-libs-freemarker</artifactId>
    1.33 +      <version>RELEASE67</version>
    1.34 +    </dependency>
    1.35 +    <dependency>
    1.36 +      <groupId>org.netbeans.external</groupId>
    1.37 +      <artifactId>freemarker-2.3.8</artifactId>
    1.38 +      <version>RELEASE67</version>
    1.39 +    </dependency>
    1.40 +    <dependency>
    1.41 +      <groupId>com.sun.jersey</groupId>
    1.42 +      <artifactId>jersey-client</artifactId>
    1.43 +      <version>1.1.0-ea</version>
    1.44 +    </dependency>
    1.45 +  </dependencies>
    1.46 +  <build>
    1.47 +    <plugins>
    1.48 +      <plugin>
    1.49 +        <groupId>org.apache.maven.plugins</groupId>
    1.50 +        <artifactId>maven-compiler-plugin</artifactId>
    1.51 +        <version>2.0.2</version>
    1.52 +        <configuration>
    1.53 +          <source>1.5</source>
    1.54 +          <target>1.5</target>
    1.55 +        </configuration>
    1.56 +      </plugin>
    1.57 +    </plugins>
    1.58 +  </build>
    1.59 +</project>
    1.60 +
    1.61 +
    1.62 +
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/FreemarkerProcessor.java	Tue Aug 11 14:26:49 2009 +0200
     2.3 @@ -0,0 +1,95 @@
     2.4 +/*
     2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     2.6 + *
     2.7 + * The contents of this file are subject to the terms of either the GNU
     2.8 + * General Public License Version 2 only ("GPL") or the Common
     2.9 + * Development and Distribution License("CDDL") (collectively, the
    2.10 + * "License"). You may not use this file except in compliance with the
    2.11 + * License. You can obtain a copy of the License at
    2.12 + * http://www.netbeans.org/cddl-gplv2.html
    2.13 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    2.14 + * specific language governing permissions and limitations under the
    2.15 + * License.  When distributing the software, include this License Header
    2.16 + * Notice in each file and include the License file at
    2.17 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    2.18 + * particular file as subject to the "Classpath" exception as provided
    2.19 + * by Sun in the GPL Version 2 section of the License file that
    2.20 + * accompanied this code. If applicable, add the following below the
    2.21 + * License Header, with the fields enclosed by brackets [] replaced by
    2.22 + * your own identifying information:
    2.23 + * "Portions Copyrighted [year] [name of copyright owner]"
    2.24 + *
    2.25 + * Contributor(s):
    2.26 + *
    2.27 + * Portions Copyrighted 2009 Jaroslav Tulach
    2.28 + */
    2.29 +
    2.30 +package cz.xelfi.quoridor.freemarkerdor;
    2.31 +
    2.32 +import com.sun.jersey.spi.template.TemplateProcessor;
    2.33 +import java.io.IOException;
    2.34 +import java.io.InputStream;
    2.35 +import java.io.InputStreamReader;
    2.36 +import java.io.OutputStream;
    2.37 +import java.io.OutputStreamWriter;
    2.38 +import java.io.Writer;
    2.39 +import java.util.Map;
    2.40 +import java.util.logging.Level;
    2.41 +import java.util.logging.Logger;
    2.42 +import javax.script.Bindings;
    2.43 +import javax.script.ScriptContext;
    2.44 +import javax.script.ScriptEngine;
    2.45 +import javax.script.ScriptEngineManager;
    2.46 +import javax.script.ScriptException;
    2.47 +import javax.ws.rs.ext.Provider;
    2.48 +import org.openide.filesystems.FileUtil;
    2.49 +
    2.50 +/**
    2.51 + *
    2.52 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    2.53 + */
    2.54 +@Provider
    2.55 +public class FreemarkerProcessor implements TemplateProcessor {
    2.56 +    private ScriptEngineManager manager;
    2.57 +
    2.58 +    public String resolve(String name) {
    2.59 +        return name;
    2.60 +    }
    2.61 +
    2.62 +    public void writeTo(String fqn, Object model, OutputStream out) throws IOException {
    2.63 +        synchronized (this) {
    2.64 +            if (manager == null) {
    2.65 +                manager = new ScriptEngineManager();
    2.66 +            }
    2.67 +        }
    2.68 +        ScriptEngine eng = manager.getEngineByName("freemarker");
    2.69 +        if (eng == null) {
    2.70 +            throw new IOException("freemarker not found!");
    2.71 +        }
    2.72 +        Bindings bind = eng.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
    2.73 +        if (model instanceof Map) {
    2.74 +            bind.putAll((Map<? extends String, ? extends Object>)model);
    2.75 +        }
    2.76 +        bind.put("model", model);
    2.77 +
    2.78 +        Writer w = new OutputStreamWriter(out);
    2.79 +
    2.80 +        eng.getContext().setWriter(w);
    2.81 +        eng.getContext().setAttribute(ScriptEngine.FILENAME, fqn, ScriptContext.ENGINE_SCOPE);
    2.82 +        // silly workaround for
    2.83 +        // http://openide.netbeans.org/issues/show_bug.cgi?id=170177
    2.84 +        eng.getContext().setAttribute("org.openide.filesystems.FileObject", FileUtil.createData(FileUtil.getConfigRoot(), fqn), ScriptContext.ENGINE_SCOPE);
    2.85 +
    2.86 +        InputStream is = FreemarkerProcessor.class.getResourceAsStream(fqn);
    2.87 +        if (is == null) {
    2.88 +            throw new IOException("Not found " + fqn); // NOI18N
    2.89 +        }
    2.90 +        InputStreamReader r = new InputStreamReader(is, "UTF-8");
    2.91 +        try {
    2.92 +            eng.eval(r);
    2.93 +        } catch (ScriptException ex) {
    2.94 +            ex.printStackTrace();
    2.95 +            throw new IOException(ex);
    2.96 +        }
    2.97 +    }
    2.98 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java	Tue Aug 11 14:26:49 2009 +0200
     3.3 @@ -0,0 +1,133 @@
     3.4 +/*
     3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 + *
     3.7 + * The contents of this file are subject to the terms of either the GNU
     3.8 + * General Public License Version 2 only ("GPL") or the Common
     3.9 + * Development and Distribution License("CDDL") (collectively, the
    3.10 + * "License"). You may not use this file except in compliance with the
    3.11 + * License. You can obtain a copy of the License at
    3.12 + * http://www.netbeans.org/cddl-gplv2.html
    3.13 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    3.14 + * specific language governing permissions and limitations under the
    3.15 + * License.  When distributing the software, include this License Header
    3.16 + * Notice in each file and include the License file at
    3.17 + * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    3.18 + * particular file as subject to the "Classpath" exception as provided
    3.19 + * by Sun in the GPL Version 2 section of the License file that
    3.20 + * accompanied this code. If applicable, add the following below the
    3.21 + * License Header, with the fields enclosed by brackets [] replaced by
    3.22 + * your own identifying information:
    3.23 + * "Portions Copyrighted [year] [name of copyright owner]"
    3.24 + *
    3.25 + * Contributor(s):
    3.26 + *
    3.27 + * Portions Copyrighted 2009 Jaroslav Tulach
    3.28 + */
    3.29 +
    3.30 +package cz.xelfi.quoridor.freemarkerdor;
    3.31 +
    3.32 +import com.sun.jersey.api.client.Client;
    3.33 +import com.sun.jersey.api.client.WebResource;
    3.34 +import com.sun.jersey.api.container.httpserver.HttpServerFactory;
    3.35 +import com.sun.jersey.api.core.PackagesResourceConfig;
    3.36 +import com.sun.jersey.api.core.ResourceConfig;
    3.37 +import com.sun.jersey.api.view.Viewable;
    3.38 +import com.sun.jersey.spi.resource.Singleton;
    3.39 +import com.sun.net.httpserver.HttpServer;
    3.40 +import cz.xelfi.quoridor.webidor.resources.Quoridor;
    3.41 +import java.io.IOException;
    3.42 +import java.net.URI;
    3.43 +import java.util.ArrayList;
    3.44 +import java.util.HashMap;
    3.45 +import java.util.Iterator;
    3.46 +import java.util.List;
    3.47 +import java.util.Map;
    3.48 +import javax.ws.rs.GET;
    3.49 +import javax.ws.rs.Path;
    3.50 +import javax.ws.rs.PathParam;
    3.51 +import javax.ws.rs.core.MediaType;
    3.52 +import org.codehaus.jettison.json.JSONArray;
    3.53 +import org.codehaus.jettison.json.JSONException;
    3.54 +import org.codehaus.jettison.json.JSONObject;
    3.55 +
    3.56 +/**
    3.57 + *
    3.58 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    3.59 + */
    3.60 +@Path("/")
    3.61 +@Singleton
    3.62 +public final class UI {
    3.63 +    private static WebResource base;
    3.64 +    public UI() {
    3.65 +    }
    3.66 +
    3.67 +    @GET
    3.68 +    @Path("/")
    3.69 +    public Viewable welcome() throws JSONException {
    3.70 +        Object obj = getJson(base.path("games"));
    3.71 +        return new Viewable("index.fmt", obj);
    3.72 +    }
    3.73 +
    3.74 +    @GET
    3.75 +    @Path("games/{id}")
    3.76 +    public Viewable board(@PathParam("id") String id) throws JSONException {
    3.77 +        Object obj = convert(base.path("games").path(id).accept(MediaType.TEXT_PLAIN_TYPE).get(String.class));
    3.78 +
    3.79 +        System.err.println("obj: " + obj);
    3.80 +        return new Viewable("game.fmt", obj);
    3.81 +    }
    3.82 +
    3.83 +
    3.84 +    private static Object getJson(WebResource res) throws JSONException {
    3.85 +        return convert(res.accept(MediaType.APPLICATION_JSON_TYPE).get(JSONArray.class));
    3.86 +    }
    3.87 +
    3.88 +    private static Object convert(Object obj) throws JSONException {
    3.89 +        if (obj instanceof JSONArray) {
    3.90 +            JSONArray arr = (JSONArray)obj;
    3.91 +            final int length = arr.length();
    3.92 +            List<Object> res = new ArrayList<Object>(length);
    3.93 +            for (int i = 0; i < length; i++) {
    3.94 +                res.add(convert(arr.get(i)));
    3.95 +            }
    3.96 +            return res;
    3.97 +        } else if (obj instanceof JSONObject) {
    3.98 +            JSONObject json = (JSONObject)obj;
    3.99 +            Map<Object,Object> map = new HashMap<Object,Object>(json.length() * 2 / 3);
   3.100 +            for (Iterator it = json.keys(); it.hasNext();) {
   3.101 +                String key = (String)it.next();
   3.102 +                map.put(key, convert(json.get(key)));
   3.103 +            }
   3.104 +            return map;
   3.105 +        } else {
   3.106 +            return obj;
   3.107 +        }
   3.108 +    }
   3.109 +
   3.110 +    //
   3.111 +    // start the server
   3.112 +    //
   3.113 +
   3.114 +    public static void main(String[] args) throws Exception {
   3.115 +        HttpServer api = Quoridor.start(9998);
   3.116 +        Client client = new Client();
   3.117 +        base = client.resource(new URI("http://localhost:9998/api/"));
   3.118 +
   3.119 +        HttpServer s = start(9997);
   3.120 +        System.out.println(
   3.121 +            "Quoridor started at port 9997\n" + "Hit enter to stop it..."
   3.122 +        );
   3.123 +        System.in.read();
   3.124 +        s.stop(0);
   3.125 +        System.exit(0);
   3.126 +    }
   3.127 +
   3.128 +    static HttpServer start(int port) throws IOException {
   3.129 +        final String baseUri = "http://localhost:" + port + "/";
   3.130 +        ResourceConfig rc = new PackagesResourceConfig("cz.xelfi.quoridor.freemarkerdor");
   3.131 +        HttpServer server = HttpServerFactory.create(baseUri, rc);
   3.132 +        server.start();
   3.133 +        return server;
   3.134 +    }
   3.135 +
   3.136 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt	Tue Aug 11 14:26:49 2009 +0200
     4.3 @@ -0,0 +1,11 @@
     4.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
     4.5 +<html>
     4.6 +  <head>
     4.7 +    <title></title>
     4.8 +    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     4.9 +  </head>
    4.10 +  <body>
    4.11 +      <h1>Game</h1>
    4.12 +      <pre>${model}</pre>
    4.13 +  </body>
    4.14 +</html>
    4.15 \ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/index.fmt	Tue Aug 11 14:26:49 2009 +0200
     5.3 @@ -0,0 +1,16 @@
     5.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
     5.5 +<html>
     5.6 +  <head>
     5.7 +    <title></title>
     5.8 +    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     5.9 +  </head>
    5.10 +  <body>
    5.11 +      <h1>Quoridor Community Server</h1>
    5.12 +
    5.13 +      <ol>
    5.14 +      <#list model as item>
    5.15 +        <li>${item.white} vs. ${item.black} <a href="games/${item.id}">board</a></li>
    5.16 +      </#list>
    5.17 +      </ol>
    5.18 +  </body>
    5.19 +</html>
    5.20 \ No newline at end of file
     6.1 --- a/pom.xml	Wed Jul 29 21:35:04 2009 +0200
     6.2 +++ b/pom.xml	Tue Aug 11 14:26:49 2009 +0200
     6.3 @@ -37,6 +37,7 @@
     6.4      <module>quoridor</module>
     6.5      <module>visidor</module>
     6.6      <module>webidor</module>
     6.7 +    <module>freemarkerdor</module>
     6.8    </modules>
     6.9      <name>Quoridor related projects</name>
    6.10      <description>Master project that agregates all quoridor related functionality.
     7.1 --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Quoridor.java	Wed Jul 29 21:35:04 2009 +0200
     7.2 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Quoridor.java	Tue Aug 11 14:26:49 2009 +0200
     7.3 @@ -41,7 +41,7 @@
     7.4   *
     7.5   * @author Jaroslav Tulach <jtulach@netbeans.org>
     7.6   */
     7.7 -@Path("/")
     7.8 +@Path("/api")
     7.9  @Singleton
    7.10  public final class Quoridor {
    7.11      private final File path;
    7.12 @@ -69,28 +69,27 @@
    7.13      //
    7.14  
    7.15      public static void main(String[] args) throws IOException {
    7.16 +        HttpServer s = start(9998);
    7.17 +        System.out.println(
    7.18 +            "Quoridor started at port 9998\n" + "Hit enter to stop it..."
    7.19 +        );
    7.20 +        System.in.read();
    7.21 +        s.stop(0);
    7.22 +        System.exit(0);
    7.23 +    }
    7.24  
    7.25 -        final String baseUri = "http://localhost:9998/";
    7.26 -        final Map<String, String> initParams = new HashMap<String, String>();
    7.27 +    public static HttpServer start(int port) throws IOException {
    7.28 +        final String baseUri = "http://localhost:" + port + "/";
    7.29  
    7.30          File home = new File(System.getProperty("user.home"));
    7.31          File quoridor = new File(home, ".quoridor");
    7.32  
    7.33          System.setProperty("quoridor.dir", quoridor.getPath());
    7.34  
    7.35 -        initParams.put("com.sun.jersey.config.property.packages",
    7.36 -                "cz.xelfi.quoridor.webidor.resources");
    7.37 -
    7.38 -        System.out.println("Starting Quoridor...");
    7.39          ResourceConfig rc = new PackagesResourceConfig("cz.xelfi.quoridor.webidor");
    7.40 -        HttpServer threadSelector = HttpServerFactory.create(baseUri, rc);
    7.41 -        threadSelector.start();
    7.42 -        System.out.println(String.format(
    7.43 -                    "Quoridor started with WADL available at %sapplication.wadl\n" +
    7.44 -            "Hit enter to stop it...", baseUri, baseUri));
    7.45 -            System.in.read();
    7.46 -            threadSelector.stop(0);
    7.47 -            System.exit(0);
    7.48 +        HttpServer server = HttpServerFactory.create(baseUri, rc);
    7.49 +        server.start();
    7.50 +        return server;
    7.51      }
    7.52  
    7.53  }
     8.1 --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java	Wed Jul 29 21:35:04 2009 +0200
     8.2 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java	Tue Aug 11 14:26:49 2009 +0200
     8.3 @@ -90,6 +90,7 @@
     8.4      }
     8.5  
     8.6      @Test public void testCreateAGame() throws Exception {
     8.7 +        webResource = webResource.path("api");
     8.8          Game s = webResource.path("games").queryParam("white", "Jarda")
     8.9                  .queryParam("black", "Jirka").post(Game.class);
    8.10