webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Games.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 26 Sep 2009 21:47:02 +0200
changeset 114 ed560bfe37f0
parent 106 7d090f2c5b91
child 115 6a80463a74c0
permissions -rw-r--r--
Line can contain only black move
     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * The contents of this file are subject to the terms of either the GNU
     5  * General Public License Version 2 only ("GPL") or the Common
     6  * Development and Distribution License("CDDL") (collectively, the
     7  * "License"). You may not use this file except in compliance with the
     8  * License. You can obtain a copy of the License at
     9  * http://www.netbeans.org/cddl-gplv2.html
    10  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    11  * specific language governing permissions and limitations under the
    12  * License.  When distributing the software, include this License Header
    13  * Notice in each file and include the License file at
    14  * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    15  * particular file as subject to the "Classpath" exception as provided
    16  * by Sun in the GPL Version 2 section of the License file that
    17  * accompanied this code. If applicable, add the following below the
    18  * License Header, with the fields enclosed by brackets [] replaced by
    19  * your own identifying information:
    20  * "Portions Copyrighted [year] [name of copyright owner]"
    21  *
    22  * Contributor(s):
    23  *
    24  * Portions Copyrighted 2009 Jaroslav Tulach
    25  */
    26 
    27 package cz.xelfi.quoridor.webidor.resources;
    28 
    29 import cz.xelfi.quoridor.IllegalPositionException;
    30 import cz.xelfi.quoridor.webidor.*;
    31 import cz.xelfi.quoridor.Move;
    32 import java.io.BufferedReader;
    33 import java.io.BufferedWriter;
    34 import java.io.File;
    35 import java.io.FileReader;
    36 import java.io.FileWriter;
    37 import java.io.IOException;
    38 import java.io.PrintWriter;
    39 import java.util.ArrayList;
    40 import java.util.Collections;
    41 import java.util.Date;
    42 import java.util.List;
    43 import java.util.logging.Level;
    44 import java.util.logging.Logger;
    45 import javax.ws.rs.DefaultValue;
    46 import javax.ws.rs.GET;
    47 import javax.ws.rs.POST;
    48 import javax.ws.rs.PUT;
    49 import javax.ws.rs.Path;
    50 import javax.ws.rs.PathParam;
    51 import javax.ws.rs.Produces;
    52 import javax.ws.rs.QueryParam;
    53 import javax.ws.rs.WebApplicationException;
    54 import javax.ws.rs.core.MediaType;
    55 import javax.ws.rs.core.Response.Status;
    56 
    57 /**
    58  *
    59  * @author Jaroslav Tulach <jtulach@netbeans.org>
    60  */
    61 public final class Games {
    62     private final Quoridor quoridor;
    63     private final List<Game> games = new ArrayList<Game>();
    64     private final File dir;
    65     private static final Logger LOG = Logger.getLogger(Games.class.getName());
    66 
    67     public Games(File dir, Quoridor quoridor) {
    68         this.dir = dir;
    69         this.quoridor = quoridor;
    70         File[] arr = dir.listFiles();
    71         if (arr != null) {
    72             for (File f : arr) {
    73                 try {
    74                     Game g = readGame(f);
    75                     games.add(g);
    76                 } catch (IOException ex) {
    77                     LOG.log(Level.WARNING, "Wrong game in " + f, ex);
    78                 }
    79             }
    80         }
    81     }
    82 
    83     @POST
    84     @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
    85     public GameId createGame(
    86         @QueryParam("loginID") String id,
    87         @QueryParam("white") String white,
    88         @QueryParam("black") String black
    89     ) throws IOException {
    90         String logUser = quoridor.isLoggedIn(id);
    91         if (logUser == null) {
    92             throw new WebApplicationException(Status.UNAUTHORIZED);
    93         }
    94         if (white == null) {
    95             throw new WebApplicationException(Status.PRECONDITION_FAILED);
    96         }
    97         if (black == null) {
    98             throw new WebApplicationException(Status.PRECONDITION_FAILED);
    99         }
   100         if (!logUser.equals(white) && !logUser.equals(black)) {
   101             throw new WebApplicationException(Status.PRECONDITION_FAILED);
   102         }
   103 
   104         Game g = new Game(white, black);
   105         storeGame(g);
   106         games.add(g);
   107         return g.getId();
   108     }
   109 
   110     @GET
   111     @Path("{id}")
   112     @Produces(MediaType.TEXT_PLAIN)
   113     public String getBoard(
   114         @PathParam("id") String id,
   115         @QueryParam("move") @DefaultValue("-1") int move
   116     ) {
   117         Game g = findGame(id, move);
   118         if (g == null) {
   119             throw new IllegalArgumentException("Unknown game " + id);
   120         }
   121         return g.getBoard().toString();
   122     }
   123 
   124     @GET
   125     @Path("{id}")
   126     @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
   127     public Game getBoardInfo(
   128         @PathParam("id") String id,
   129         @QueryParam("move") @DefaultValue("-1") int move
   130     ) {
   131         return findGame(id, move);
   132     }
   133 
   134     @PUT
   135     @Path("{id}")
   136     @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
   137     public GameId applyMove(
   138         @QueryParam("loginID") String loginId,
   139         @PathParam("id") String id,
   140         @QueryParam("player") String player,
   141         @QueryParam("move") String move
   142     ) throws IllegalPositionException {
   143         String logUser = quoridor.isLoggedIn(loginId);
   144         if (logUser == null) {
   145             throw new WebApplicationException(Status.UNAUTHORIZED);
   146         }
   147         if (!logUser.equals(player)) {
   148             throw new WebApplicationException(Status.UNAUTHORIZED);
   149         }
   150 
   151         Game g = findGame(id);
   152         if (g == null) {
   153             throw new IllegalArgumentException("Unknown game " + id);
   154         }
   155         Move m = Move.valueOf(move);
   156         g.apply(player, m, new Date());
   157         try {
   158             storeGame(g);
   159         } catch (IOException ex) {
   160             LOG.log(Level.WARNING, "Cannot store game " + id, ex);
   161         }
   162         return g.getId();
   163     }
   164 
   165     @GET
   166     @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
   167     public List<GameId> listGames() {
   168         List<GameId> arr = new ArrayList<GameId>(games.size());
   169         for (Game g : games) {
   170             arr.add(g.getId());
   171         }
   172         Collections.sort(arr, GameId.NEWEST_FIRST);
   173         return arr;
   174     }
   175 
   176     public List<Game> getGames() {
   177         return games;
   178     }
   179 
   180     private Game findGame(String id) {
   181         for (Game g : games) {
   182             if (g.getId().getId().equals(id)) {
   183                 return g;
   184             }
   185         }
   186         return null;
   187     }
   188     private Game findGame(String id, int move) {
   189         Game g = findGame(id);
   190         if (g == null) {
   191             throw new IllegalArgumentException("Unknown game " + id);
   192         }
   193         try {
   194             return move == -1 ? g : g.snapshot(move);
   195         } catch (IllegalPositionException ex) {
   196             Logger.getLogger(Games.class.getName()).log(Level.SEVERE, null, ex);
   197             return null;
   198         }
   199     }
   200 
   201     private Game readGame(File f) throws IOException {
   202         BufferedReader r = new BufferedReader(new FileReader(f));
   203         String white = null;
   204         String black = null;
   205         Game g = null;
   206         for (;;) {
   207             String line = r.readLine();
   208             if (line == null) {
   209                 line = "finish";
   210             }
   211             line = line.trim();
   212             if (line.length() == 0) {
   213                 continue;
   214             }
   215             if (line.startsWith("# white: ")) {
   216                 white = line.substring(9);
   217                 continue;
   218             }
   219             if (line.startsWith("# black: ")) {
   220                 black = line.substring(9);
   221                 continue;
   222             }
   223             if (line.startsWith("#")) {
   224                 continue;
   225             }
   226             if (white == null || black == null) {
   227                 throw new IOException("Missing white and black identification in " + f);
   228             }
   229             if (g == null) {
   230                 GameId id = new GameId(f.getName(), white, black, new Date(f.lastModified()), new Date(f.lastModified()), GameStatus.whiteMove);
   231                 g = new Game(id);
   232             }
   233             int hash = line.indexOf('#');
   234             if (hash >= 0) {
   235                 line = line.substring(0, hash);
   236             }
   237             if (line.equals("finish")) {
   238                 break;
   239             }
   240             String[] moves = line.split(" ");
   241             if (moves.length == 0) {
   242                 continue;
   243             }
   244             if (moves.length > 2) {
   245                 throw new IOException("Too much moves on line: " + line);
   246             }
   247             try {
   248                 if (!"...".equals(moves[0])) {
   249                     g.apply(white, Move.valueOf(moves[0]), null);
   250                 }
   251                 if (moves.length == 2) {
   252                     g.apply(black, Move.valueOf(moves[1]), null);
   253                 }
   254             } catch (IllegalPositionException ex) {
   255                 throw new IOException("Wrong move: " + ex.getMessage());
   256             }
   257         }
   258         if (g == null) {
   259             throw new IOException("No moves in " + f);
   260         }
   261         return g;
   262     }
   263 
   264     private void storeGame(Game g) throws IOException {
   265         dir.mkdirs();
   266         File f = new File(dir, g.getId().getId());
   267         PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(f)));
   268         pw.println("# white: " + g.getId().getWhite());
   269         pw.println("# black: " + g.getId().getBlack());
   270         pw.println("# status: " + g.getId().getStatus());
   271         int cnt = 0;
   272         for (Move m : g.getMoves()) {
   273             pw.print(m.toString());
   274             if (++cnt % 2 == 0) {
   275                 pw.println();
   276             } else {
   277                 pw.print(' ');
   278             }
   279         }
   280         pw.println();
   281         pw.println();
   282         pw.flush();
   283         pw.close();
   284     }
   285 }