Removing anything related to JSON from the HTML layer, using natural freemarker's W3C DOM processing capabilities
authorJaroslav Tulach <jtulach@netbeans.org>
Mon, 31 Aug 2009 22:44:47 +0200
changeset 54f041b6570ff9
parent 53 ccc325a936cc
child 55 830e0ba29c04
Removing anything related to JSON from the HTML layer, using natural freemarker's W3C DOM processing capabilities
.hgignore
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
freemarkerdor/src/test/java/cz/xelfi/quoridor/freemarkerdor/UITest.java
webidor/src/main/java/cz/xelfi/quoridor/webidor/Game.java
webidor/src/main/java/cz/xelfi/quoridor/webidor/GameId.java
webidor/src/main/java/cz/xelfi/quoridor/webidor/W3CDocumentReader.java
webidor/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyReader
webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java
     1.1 --- a/.hgignore	Sun Aug 30 16:15:37 2009 +0200
     1.2 +++ b/.hgignore	Mon Aug 31 22:44:47 2009 +0200
     1.3 @@ -1,3 +1,4 @@
     1.4 +target/.*
     1.5  .*/target/.*
     1.6  .*orig$
     1.7  .*~$
     2.1 --- a/freemarkerdor/pom.xml	Sun Aug 30 16:15:37 2009 +0200
     2.2 +++ b/freemarkerdor/pom.xml	Mon Aug 31 22:44:47 2009 +0200
     2.3 @@ -46,6 +46,11 @@
     2.4        <version>4.5</version>
     2.5        <scope>test</scope>
     2.6      </dependency>
     2.7 +    <dependency>
     2.8 +      <groupId>freemarker</groupId>
     2.9 +      <artifactId>freemarker</artifactId>
    2.10 +      <version>2.3.8</version>
    2.11 +    </dependency>
    2.12    </dependencies>
    2.13    <build>
    2.14      <plugins>
    2.15 @@ -65,3 +70,8 @@
    2.16  
    2.17  
    2.18  
    2.19 +
    2.20 +
    2.21 +
    2.22 +
    2.23 +
     3.1 --- a/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/FreemarkerProcessor.java	Sun Aug 30 16:15:37 2009 +0200
     3.2 +++ b/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/FreemarkerProcessor.java	Mon Aug 31 22:44:47 2009 +0200
     3.3 @@ -41,6 +41,7 @@
     3.4  import javax.script.ScriptException;
     3.5  import javax.ws.rs.ext.Provider;
     3.6  import org.openide.filesystems.FileUtil;
     3.7 +import org.w3c.dom.Document;
     3.8  
     3.9  /**
    3.10   *
    3.11 @@ -68,7 +69,11 @@
    3.12          if (model instanceof Map) {
    3.13              bind.putAll((Map<? extends String, ? extends Object>)model);
    3.14          }
    3.15 -        bind.put("model", model);
    3.16 +        if (model instanceof Document) {
    3.17 +            bind.put("doc", model);
    3.18 +        } else {
    3.19 +            bind.put("model", model);
    3.20 +        }
    3.21  
    3.22          Writer w = new OutputStreamWriter(out);
    3.23  
     4.1 --- a/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java	Sun Aug 30 16:15:37 2009 +0200
     4.2 +++ b/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java	Mon Aug 31 22:44:47 2009 +0200
     4.3 @@ -38,11 +38,6 @@
     4.4  import java.io.FileInputStream;
     4.5  import java.io.IOException;
     4.6  import java.net.URI;
     4.7 -import java.util.ArrayList;
     4.8 -import java.util.HashMap;
     4.9 -import java.util.Iterator;
    4.10 -import java.util.List;
    4.11 -import java.util.Map;
    4.12  import java.util.Properties;
    4.13  import java.util.concurrent.Callable;
    4.14  import javax.ws.rs.DefaultValue;
    4.15 @@ -58,9 +53,6 @@
    4.16  import javax.ws.rs.core.MediaType;
    4.17  import javax.ws.rs.core.NewCookie;
    4.18  import javax.ws.rs.core.Response;
    4.19 -import org.codehaus.jettison.json.JSONArray;
    4.20 -import org.codehaus.jettison.json.JSONException;
    4.21 -import org.codehaus.jettison.json.JSONObject;
    4.22  import org.w3c.dom.Document;
    4.23  
    4.24  /**
    4.25 @@ -94,7 +86,11 @@
    4.26      ) throws Exception {
    4.27          File f = new File(new File(new File(System.getProperty("user.home")), ".quoridor"), "passwd");
    4.28          Properties p = new Properties();
    4.29 -        p.load(new FileInputStream(f));
    4.30 +        try {
    4.31 +            p.load(new FileInputStream(f));
    4.32 +        } catch (IOException ex) {
    4.33 +            ex.printStackTrace();
    4.34 +        }
    4.35          if (name != null && password.equals(p.getProperty(name))) {
    4.36              return Response.seeOther(new URI("/")).cookie(new NewCookie("login", name)).entity(welcomeImpl()).build();
    4.37          } else {
    4.38 @@ -105,7 +101,7 @@
    4.39  
    4.40      @GET
    4.41      @Produces(MediaType.TEXT_HTML)
    4.42 -    public Viewable welcome() throws JSONException {
    4.43 +    public Viewable welcome() {
    4.44          Viewable v = checkLogin();
    4.45          if (v != null) {
    4.46              return v;
    4.47 @@ -116,15 +112,13 @@
    4.48      @GET
    4.49      @Path("games/{id}/")
    4.50      @Produces(MediaType.TEXT_HTML)
    4.51 -    public Viewable board(@PathParam("id") String id) throws JSONException {
    4.52 +    public Viewable board(@PathParam("id") String id) {
    4.53          Viewable v = checkLogin();
    4.54          if (v != null) {
    4.55              return v;
    4.56          }
    4.57 -        Map<?,?> obj = (Map<?,?>)convert(base.path("games").path(id).accept(MediaType.APPLICATION_JSON_TYPE).get(JSONObject.class));
    4.58 -
    4.59 -
    4.60 -        return new Viewable("game.fmt", obj);
    4.61 +        Document doc = base.path("games").path(id).accept(MediaType.TEXT_XML).get(Document.class);
    4.62 +        return new Viewable("game.fmt", doc);
    4.63      }
    4.64  
    4.65      @GET
    4.66 @@ -137,7 +131,7 @@
    4.67          @QueryParam("direction-next") @DefaultValue("") String directionNext,
    4.68          @QueryParam("column") @DefaultValue("") String column,
    4.69          @QueryParam("row") @DefaultValue("") String row
    4.70 -    ) throws JSONException {
    4.71 +    ) {
    4.72          Viewable v = checkLogin();
    4.73          if (v != null) {
    4.74              return v;
    4.75 @@ -160,41 +154,20 @@
    4.76      public Viewable create(
    4.77          @QueryParam("white") String white,
    4.78          @QueryParam("black") String black
    4.79 -    ) throws JSONException {
    4.80 +    ) {
    4.81          Viewable v = checkLogin();
    4.82          if (v != null) {
    4.83              return v;
    4.84          }
    4.85 -        Object obj = convert(
    4.86 +        Object obj =
    4.87              base.path("games").queryParam("white", white).
    4.88 -            queryParam("black", black).post(JSONObject.class)
    4.89 -        );
    4.90 -        Map<?,?> map = (Map<?,?>)obj;
    4.91 -        String id = (String)map.get("id");
    4.92 -        return board(id);
    4.93 +            queryParam("black", black).post(Document.class);
    4.94 +        return welcome();
    4.95      }
    4.96  
    4.97 -
    4.98 -    private static Object convert(Object obj) throws JSONException {
    4.99 -        if (obj instanceof JSONArray) {
   4.100 -            JSONArray arr = (JSONArray)obj;
   4.101 -            final int length = arr.length();
   4.102 -            List<Object> res = new ArrayList<Object>(length);
   4.103 -            for (int i = 0; i < length; i++) {
   4.104 -                res.add(convert(arr.get(i)));
   4.105 -            }
   4.106 -            return res;
   4.107 -        } else if (obj instanceof JSONObject) {
   4.108 -            JSONObject json = (JSONObject)obj;
   4.109 -            Map<Object,Object> map = new HashMap<Object,Object>(json.length() * 2 / 3);
   4.110 -            for (Iterator it = json.keys(); it.hasNext();) {
   4.111 -                String key = (String)it.next();
   4.112 -                map.put(key, convert(json.get(key)));
   4.113 -            }
   4.114 -            return map;
   4.115 -        } else {
   4.116 -            return obj;
   4.117 -        }
   4.118 +    private Viewable welcomeImpl() {
   4.119 +        final Object got = base.path("games").accept(MediaType.TEXT_XML).get(Document.class);
   4.120 +        return new Viewable("index.fmt", got);
   4.121      }
   4.122  
   4.123      //
   4.124 @@ -236,10 +209,4 @@
   4.125          return server;
   4.126      }
   4.127  
   4.128 -    private Viewable welcomeImpl() throws JSONException {
   4.129 -        final Object got = base.path("games").accept(MediaType.APPLICATION_JSON_TYPE).get(JSONArray.class);
   4.130 -        List<?> obj = (List<?>)convert(got);
   4.131 -        return new Viewable("index.fmt", obj);
   4.132 -    }
   4.133 -
   4.134  }
     5.1 --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt	Sun Aug 30 16:15:37 2009 +0200
     5.2 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt	Mon Aug 31 22:44:47 2009 +0200
     5.3 @@ -6,7 +6,7 @@
     5.4    </head>
     5.5    <body>
     5.6        <h1>Game</h1>
     5.7 -      <h3>${id.white} vs. ${id.black}</h3>
     5.8 +      <h3>${doc.game.id.@white} vs. ${doc.game.id.@black}</h3>
     5.9        <form action="move">
    5.10            <input type="hidden" name="type" value="fence" readonly="readonly"/>
    5.11            <select name="column">
    5.12 @@ -52,6 +52,6 @@
    5.13            </select>
    5.14            <input type="submit" value="Move!" />
    5.15        </form>
    5.16 -      <pre>${board}</pre>
    5.17 +      <pre>${doc.game.board}</pre>
    5.18    </body>
    5.19  </html>
    5.20 \ No newline at end of file
     6.1 --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/index.fmt	Sun Aug 30 16:15:37 2009 +0200
     6.2 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/index.fmt	Mon Aug 31 22:44:47 2009 +0200
     6.3 @@ -6,10 +6,11 @@
     6.4    </head>
     6.5    <body>
     6.6        <h1>Quoridor Community Server</h1>
     6.7 -
     6.8        <ol>
     6.9 -      <#list model as item>
    6.10 -        <li>${item.white} vs. ${item.black} <a href="games/${item.id}/">board</a></li>
    6.11 +      <#list doc.gameIds.* as g>
    6.12 +        <li>
    6.13 +            ${g.@white} vs. ${g.@black} <a href="games/${g.@id}/">board</a>
    6.14 +        </li>
    6.15        </#list>
    6.16        </ol>
    6.17        <form action="games/create">
     7.1 --- a/freemarkerdor/src/test/java/cz/xelfi/quoridor/freemarkerdor/UITest.java	Sun Aug 30 16:15:37 2009 +0200
     7.2 +++ b/freemarkerdor/src/test/java/cz/xelfi/quoridor/freemarkerdor/UITest.java	Mon Aug 31 22:44:47 2009 +0200
     7.3 @@ -104,6 +104,9 @@
     7.4          if (res.indexOf("action=\"login\"") == -1) {
     7.5              fail("Wrong index.html:\n" + res);
     7.6          }
     7.7 +        if (res.toLowerCase().indexOf("error") != -1) {
     7.8 +            fail("There was an error:\n" + res);
     7.9 +        }
    7.10          res = webResource.cookie(Cookie.valueOf("login=jarda")).accept("text/html").get(String.class);
    7.11          if (res.indexOf("action=\"games/create\"") == -1) {
    7.12              fail(res);
     8.1 --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/Game.java	Sun Aug 30 16:15:37 2009 +0200
     8.2 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/Game.java	Mon Aug 31 22:44:47 2009 +0200
     8.3 @@ -49,7 +49,7 @@
     8.4  public final class Game extends Object {
     8.5      @XmlElement
     8.6      private GameId id;
     8.7 -    @XmlAttribute
     8.8 +    @XmlElement
     8.9      @XmlJavaTypeAdapter(BoardAdapter.class)
    8.10      private Board board;
    8.11      @XmlElement
     9.1 --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/GameId.java	Sun Aug 30 16:15:37 2009 +0200
     9.2 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/GameId.java	Mon Aug 31 22:44:47 2009 +0200
     9.3 @@ -49,7 +49,7 @@
     9.4      private Date started;
     9.5      @XmlAttribute
     9.6      private GameResult result;
     9.7 -    @XmlID
     9.8 +    @XmlID @XmlAttribute
     9.9      private String id;
    9.10  
    9.11      GameId() {
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/W3CDocumentReader.java	Mon Aug 31 22:44:47 2009 +0200
    10.3 @@ -0,0 +1,46 @@
    10.4 +/*
    10.5 + * To change this template, choose Tools | Templates
    10.6 + * and open the template in the editor.
    10.7 + */
    10.8 +
    10.9 +package cz.xelfi.quoridor.webidor;
   10.10 +
   10.11 +import java.io.IOException;
   10.12 +import java.io.InputStream;
   10.13 +import java.lang.annotation.Annotation;
   10.14 +import java.lang.reflect.Type;
   10.15 +import javax.ws.rs.Consumes;
   10.16 +import javax.ws.rs.WebApplicationException;
   10.17 +import javax.ws.rs.core.MediaType;
   10.18 +import javax.ws.rs.core.MultivaluedMap;
   10.19 +import javax.ws.rs.ext.Provider;
   10.20 +import javax.xml.parsers.DocumentBuilder;
   10.21 +import javax.xml.parsers.DocumentBuilderFactory;
   10.22 +import javax.xml.parsers.ParserConfigurationException;
   10.23 +import org.w3c.dom.Document;
   10.24 +import org.xml.sax.SAXException;
   10.25 +
   10.26 +/**
   10.27 + *
   10.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   10.29 + */
   10.30 +@Provider
   10.31 +@Consumes(MediaType.TEXT_XML)
   10.32 +public class W3CDocumentReader implements javax.ws.rs.ext.MessageBodyReader<Document> {
   10.33 +    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
   10.34 +        return type == Document.class;
   10.35 +    }
   10.36 +
   10.37 +    public Document readFrom(Class<Document> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
   10.38 +        try {
   10.39 +            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   10.40 +            DocumentBuilder builder = factory.newDocumentBuilder();
   10.41 +            return builder.parse(entityStream);
   10.42 +        } catch (ParserConfigurationException ex) {
   10.43 +            throw new WebApplicationException(ex);
   10.44 +        } catch (SAXException ex) {
   10.45 +            throw new WebApplicationException(ex);
   10.46 +        }
   10.47 +    }
   10.48 +
   10.49 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/webidor/src/main/resources/META-INF/services/javax.ws.rs.ext.MessageBodyReader	Mon Aug 31 22:44:47 2009 +0200
    11.3 @@ -0,0 +1,1 @@
    11.4 +cz.xelfi.quoridor.webidor.W3CDocumentReader
    12.1 --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java	Sun Aug 30 16:15:37 2009 +0200
    12.2 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java	Mon Aug 31 22:44:47 2009 +0200
    12.3 @@ -40,6 +40,7 @@
    12.4  import java.util.Map;
    12.5  import javax.ws.rs.core.MediaType;
    12.6  import org.junit.Test;
    12.7 +import org.w3c.dom.Document;
    12.8  import static org.junit.Assert.*;
    12.9  
   12.10  /**
   12.11 @@ -100,6 +101,10 @@
   12.12  
   12.13          GenericType<List<GameId>> gType = new GenericType<List<GameId>>() {};
   12.14  
   12.15 +        Document doc = webResource.path("games").accept("text/xml").get(Document.class);
   12.16 +        assertNotNull("Can read games in form of XML", doc);
   12.17 +        assertEquals("Name is correct", "gameIds", doc.getDocumentElement().getNodeName());
   12.18 +        assertEquals("One child", 1, doc.getDocumentElement().getChildNodes().getLength());
   12.19          List<GameId> games = webResource.path("games").accept("application/json").get(gType);
   12.20          assertEquals("One game", 1, games.size());
   12.21          assertEquals("Same white", "Jarda", games.get(0).getWhite());