org.darwinathome.server.controller.HubController.java Source code

Java tutorial

Introduction

Here is the source code for org.darwinathome.server.controller.HubController.java

Source

// ========= Copyright (C) 2009, 2010 Gerald de Jong =================
// This file is part of the Darwin at Home project, distributed
// under the GNU General Public License, version 3.
// You should have received a copy of this license in "license.txt",
// but if not, see http://www.gnu.org/licenses/gpl-3.0.txt.
// ===================================================================
package org.darwinathome.server.controller;

import org.apache.log4j.Logger;
import org.darwinathome.body.Target;
import org.darwinathome.genetics.Genome;
import org.darwinathome.geometry.math.Arrow;
import org.darwinathome.network.Failure;
import org.darwinathome.network.Hub;
import org.darwinathome.server.persistence.Player;
import org.darwinathome.server.persistence.Storage;
import org.darwinathome.server.persistence.WorldHistory;
import org.darwinathome.universe.SpeechChange;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.ServletContextAware;

import javax.servlet.ServletContext;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Gerald de Jong <geralddejong@gmail.com>
 */

@Controller
public class HubController implements ServletContextAware {
    private static final int TOKEN_SIZE = 24;
    private static final long SESSION_MILLIS = 60000;
    private static final String DOC_DIR = "docs";
    private static final String DOC_FILE_SUFFIX = ".txt";
    private Logger log = Logger.getLogger(getClass());
    private ServletContext servletContext;
    private Map<String, PlayerSession> sessionMap = new ConcurrentHashMap<String, PlayerSession>();

    @Value("#{storage.worldHistory}")
    private WorldHistory worldHistory;

    @Autowired
    private Storage storage;

    @RequestMapping(Hub.AUTHENTICATE_SERVICE)
    public void authenticate(@RequestParam(Hub.PARAM_BODY_NAME) String bodyName,
            @RequestParam(Hub.PARAM_PASSWORD) String password, OutputStream outputStream) throws IOException {
        log.info(Hub.AUTHENTICATE_SERVICE);
        DataOutputStream dos = new DataOutputStream(outputStream);
        Player player = storage.authenticate(bodyName, password);
        if (player != null) {
            PlayerSession session = new PlayerSession(player);
            sessionMap.put(session.getToken(), session);
            dos.writeUTF(Hub.SUCCESS);
            dos.writeUTF(session.getToken());
        } else {
            dos.writeUTF(Hub.FAILURE);
            dos.writeUTF(Failure.AUTHENTICATION.toString());
        }
        dos.close();
    }

    @RequestMapping(Hub.GET_WORLD_SERVICE)
    public void getWorld(@PathVariable("session") String session, OutputStream outputStream) throws IOException {
        log.info(Hub.GET_WORLD_SERVICE + " " + session);
        DataOutputStream dos = new DataOutputStream(outputStream);
        PlayerSession playerSession = sessionMap.get(session);
        if (playerSession != null) {
            dos.writeUTF(Hub.SUCCESS);
            dos.write(worldHistory.getFrozenWorld().getWorld());
            Iterator<PlayerSession> sessionWalk = sessionMap.values().iterator();
            while (sessionWalk.hasNext()) {
                if (sessionWalk.next().isExpired()) {
                    sessionWalk.remove();
                }
            }
        } else {
            dos.writeUTF(Hub.FAILURE);
            dos.writeUTF(Failure.SESSION.toString());
        }
    }

    @RequestMapping(Hub.CREATE_BEING_SERVICE)
    @ResponseBody
    public String createBeing(@PathVariable("session") String session, @RequestParam(Hub.PARAM_LOCATION_X) double x,
            @RequestParam(Hub.PARAM_LOCATION_Y) double y, @RequestParam(Hub.PARAM_LOCATION_Z) double z) {
        log.info(Hub.CREATE_BEING_SERVICE + " " + session);
        try {
            Arrow location = new Arrow(x, y, z);
            worldHistory.createBeing(getEmail(session), location, new Arrow().random());
            return Hub.SUCCESS;
        } catch (NoSessionException e) {
            return Hub.FAILURE + Failure.SESSION;
        }
    }

    @RequestMapping(Hub.SET_SPEECH_SERVICE)
    @ResponseBody
    public String setSpeech(@PathVariable("session") String session,
            @RequestParam(Hub.PARAM_SPEECH) String speech) {
        log.info(Hub.SET_SPEECH_SERVICE + " " + session);
        try {
            worldHistory.setSpeech(getEmail(session), speech);
            return Hub.SUCCESS;
        } catch (NoSessionException e) {
            return Hub.FAILURE + Failure.SESSION;
        }
    }

    @RequestMapping(Hub.GET_SPEECH_SINCE_SERVICE)
    public void getSpeechSince(@PathVariable("session") String session, @RequestParam(Hub.PARAM_TIME) long time,
            OutputStream outputStream) throws IOException {
        log.info(Hub.GET_SPEECH_SINCE_SERVICE + " " + session);
        DataOutputStream dos = new DataOutputStream(outputStream);
        try {
            List<SpeechChange> changes = worldHistory.getSpeechSince(getEmail(session), time);
            dos.writeUTF(Hub.SUCCESS);
            SpeechChange.write(dos, changes);
        } catch (NoSessionException e) {
            dos.writeUTF(Hub.FAILURE);
            dos.writeUTF(Failure.SESSION.toString());
        }
    }

    @RequestMapping(Hub.SET_GENOME_SERVICE)
    @ResponseBody
    public String setGenome(@PathVariable("session") String session, HttpEntity<byte[]> entity) {
        log.info(Hub.SET_GENOME_SERVICE + " " + session);
        try {
            DataInputStream dis = new DataInputStream(new ByteArrayInputStream(entity.getBody()));
            Genome genome = Genome.read(dis, worldHistory.getNoise());
            worldHistory.setGenome(getEmail(session), genome);
            return Hub.SUCCESS;
        } catch (IOException e) {
            log.warn("Unable to read genome", e);
            return Hub.FAILURE + Failure.MARSHALLING;
        } catch (NoSessionException e) {
            return Hub.FAILURE + Failure.SESSION;
        }
    }

    @RequestMapping(Hub.SET_TARGET_SERVICE)
    public void setTarget(@PathVariable("session") String session, @RequestParam(Hub.PARAM_LOCATION_X) double x,
            @RequestParam(Hub.PARAM_LOCATION_Y) double y, @RequestParam(Hub.PARAM_LOCATION_Z) double z,
            @RequestParam(Hub.PARAM_PREY_NAME) String preyName, OutputStream outputStream) throws IOException {
        log.info(Hub.SET_TARGET_SERVICE);
        DataOutputStream dos = new DataOutputStream(outputStream);
        try {
            Arrow location = new Arrow(x, y, z);
            Target target = new Target(location, preyName);
            WorldHistory.Frozen frozen = worldHistory.setTarget(getEmail(session), target);
            dos.writeUTF(Hub.SUCCESS);
            dos.write(frozen.getWorld());
        } catch (NoSessionException e) {
            dos.writeUTF(Hub.FAILURE);
            dos.writeUTF(Failure.SESSION.toString());
        }
    }

    @RequestMapping(Hub.DOCUMENTATION_SERVICE)
    @ResponseBody
    public void getDocumentation(@RequestParam(Hub.PARAM_TITLE) String title, OutputStream outputStream) {
        log.info(Hub.DOCUMENTATION_SERVICE);
        DataOutputStream dos = new DataOutputStream(outputStream);
        File docsDirectory = new File(servletContext.getRealPath(DOC_DIR));
        try {
            if (!docsDirectory.isDirectory()) {
                log.fatal("Docs directory not found!");
                dos.writeUTF(Hub.FAILURE);
                dos.writeUTF(Failure.SYSTEM.toString());
                return;
            }
            if (title.isEmpty()) {
                File[] textFiles = docsDirectory.listFiles(new TextFilter());
                dos.writeUTF(Hub.SUCCESS);
                dos.writeUTF(title);
                dos.writeShort(textFiles.length);
                for (File docFile : textFiles) {
                    dos.writeUTF(
                            docFile.getName().substring(0, docFile.getName().length() - DOC_FILE_SUFFIX.length()));
                }
            } else {
                File docFile = new File(docsDirectory, title + DOC_FILE_SUFFIX);
                if (!docFile.exists()) {
                    dos.writeUTF(Hub.FAILURE);
                    dos.writeUTF(Failure.SYSTEM.toString());
                    return;
                }
                List<String> lines = getLines(docFile);
                dos.writeUTF(Hub.SUCCESS);
                dos.writeUTF(title);
                dos.writeShort(lines.size());
                for (String line : lines) {
                    dos.writeUTF(line);
                }
            }
        } catch (IOException e) {
            log.error("Problem delivering documentation", e);
        }
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    private static class NoSessionException extends Exception {
    }

    private String getEmail(String session) throws NoSessionException {
        PlayerSession playerSession = sessionMap.get(session);
        if (playerSession == null) {
            throw new NoSessionException();
        }
        playerSession.used();
        return playerSession.getEmail();
    }

    private List<String> getLines(File docFile) throws IOException {
        List<String> lines = new ArrayList<String>();
        BufferedReader in = new BufferedReader(new FileReader(docFile));
        String line;
        while ((line = in.readLine()) != null) {
            lines.add(line);
        }
        in.close();
        return lines;
    }

    private class TextFilter implements FilenameFilter {

        @Override
        public boolean accept(File dir, String name) {
            return name.endsWith(DOC_FILE_SUFFIX);
        }
    }

    private class PlayerSession {
        private Player player;
        private long lastUsed = System.currentTimeMillis();
        private String token;

        private PlayerSession(Player player) {
            this.player = player;
            StringBuilder out = new StringBuilder();
            for (int walk = 0; walk < TOKEN_SIZE; walk++) {
                out.append((char) ('a' + (int) (Math.random() * 26)));
            }
            token = out.toString();
        }

        private void used() {
            lastUsed = System.currentTimeMillis();
            log.info("session " + token + " is " + player.getEmail());
        }

        public String getEmail() {
            return player.getEmail();
        }

        public String getToken() {
            return token;
        }

        public boolean isExpired() {
            return System.currentTimeMillis() - lastUsed > SESSION_MILLIS;
        }
    }
}