hu.bme.iit.quiz.endpoint.PollEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for hu.bme.iit.quiz.endpoint.PollEndpoint.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package hu.bme.iit.quiz.endpoint;

import hu.bme.iit.quiz.model.Quiz;
import hu.bme.iit.quiz.model.User;
import hu.bme.iit.quiz.util.EndpointUtil;
import hu.bme.iit.quiz.xml.Question;
import hu.bme.iit.quiz.xml.QuestionOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Singleton;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;

@Singleton
@ServerEndpoint(value = "/pollendpoint/{presentationID}")
public class PollEndpoint {

    private static final Logger logger = Logger.getLogger(PollEndpoint.class);
    private static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
    // <presentationID, quiz> pattern: a user only can have one quiz in active phase
    private static Map<Integer, QuizRoom> quizzesInOngoingPhase = Collections
            .synchronizedMap(new HashMap<Integer, QuizRoom>());
    // <SESSIONid, USERKEY>
    private static Map<String, String> userSessions = Collections.synchronizedMap(new HashMap<String, String>());
    //userkey []questionNum[1]selectedoptionnum
    private static Map<String, Integer[]> userAnswers = Collections
            .synchronizedMap(new HashMap<String, Integer[]>());

    @OnMessage
    public String onMessage(String jMessage, Session session, @PathParam("presentationID") Integer presentationID) {
        logger.debug("onMessage websocket event: " + jMessage);
        JSONObject message = new JSONObject(jMessage);
        try {
            logger.debug("onMessage type: " + message.getString("type"));
            switch (message.getString("type")) {
            case "JOIN":
                joinRoom(session, presentationID, message.getString("userkey"));
                break;
            case "START":
                if (isQuizOwner(presentationID, session)) {
                    sendQuizQestion(session, presentationID, message.getString("userkey"), 0);
                }
                break;
            case "NEXT":
                if (isQuizOwner(presentationID, session)) {
                    sendQuizQestion(session, presentationID, message.getString("userkey"),
                            message.getInt("questionID"));
                }
                break;
            case "SHOWCORRECT":
                if (isQuizOwner(presentationID, session)) {
                    sendActualQestionCorrection(session, presentationID, message.getString("userkey"));
                }
                break;
            case "ANSWER":
                setUserAnswer(session, presentationID, message.getString("userkey"), message.getInt("optionNum"));
                break;
            default:
                logger.warn("Websocket SWITCH drive in default case.");
                break;
            }
        } catch (JSONException e) {
            logger.error(e);
        }

        return null;
    }

    @OnOpen
    public void onOpen(final Session session, @PathParam("presentationID") Integer presentationID) {
        logger.debug("onOpen websocket event id: " + session.getId());
        peers.add(session);
        if (!quizzesInOngoingPhase.containsKey(presentationID)) {
            QuizRoom newQuizRoom = new QuizRoom(presentationID);
            quizzesInOngoingPhase.put(presentationID, newQuizRoom);
            newQuizRoom.initQuizPresentation();
        }
    }

    @OnClose
    public void onClose(Session peer, @PathParam("presentationID") Integer presentationID) {
        logger.debug("onClose from client: " + peer.getId() + " presid: " + presentationID);
        quizzesInOngoingPhase.get(presentationID).removeFollower(userSessions.get(peer.getId()));
        userSessions.remove(peer.getId());
        peers.remove(peer);
        EndpointUtil.sendUpdateToAll(peers, createFollowersUpdateString(presentationID));
    }

    private void joinRoom(Session session, Integer presentationID, String userkey) {
        userSessions.put(session.getId(), userkey);
        if (isQuizOwner(presentationID, session)) {
            quizzesInOngoingPhase.get(presentationID).setOwnerPeer(session);
        }
        quizzesInOngoingPhase.get(presentationID).addFollower(userkey);
        EndpointUtil.sendUpdateToAll(peers, createFollowersUpdateString(presentationID));
        //If quiz is ongoing
        logger.debug("ActualQuestionAtJoin: " + quizzesInOngoingPhase.get(presentationID).getActualQuestion());
        if (quizzesInOngoingPhase.get(presentationID).getActualQuestion() > -1) {
            EndpointUtil.sendUpdateToPeer(session, createQuizQuestionUpdateString(presentationID,
                    quizzesInOngoingPhase.get(presentationID).getActualQuestion()));
        }
    }

    private void sendQuizQestion(Session session, Integer presentationID, String userkey, Integer questionID) {
        logger.debug("sendQuizQestion function start: " + session.getId());
        quizzesInOngoingPhase.get(presentationID).setActualQuestion(questionID);
        EndpointUtil.sendUpdateToAll(peers, createQuizQuestionUpdateString(presentationID, questionID));

        for (String secretkey : quizzesInOngoingPhase.get(presentationID).getFollowers().keySet()) {
            this.storeUserAnswer(presentationID, secretkey, -1);
        }
        EndpointUtil.sendUpdateToPeer(quizzesInOngoingPhase.get(presentationID).getOwnerPeer(),
                createUserAnswerUpdateString(presentationID));
        logger.debug("sendQuizQestion function finish: " + session.getId());
    }

    private void setUserAnswer(Session session, Integer presentationID, String userkey, int answerNum) {
        logger.debug("setUserAnswer function start");
        this.storeUserAnswer(presentationID, userkey, answerNum);
        EndpointUtil.sendUpdateToPeer(quizzesInOngoingPhase.get(presentationID).getOwnerPeer(),
                createUserAnswerUpdateString(presentationID));
    }

    private void storeUserAnswer(Integer presentationID, String userkey, int answerNum) {
        if (!userAnswers.containsKey(userkey)) {
            Integer[] answers = new Integer[quizzesInOngoingPhase.get(presentationID).getQuizData().getContent()
                    .getQuestion().size()];
            userAnswers.put(userkey, answers);
        }
        Integer[] answers = userAnswers.get(userkey);
        answers[quizzesInOngoingPhase.get(presentationID).getActualQuestion()] = answerNum;
        userAnswers.put(userkey, answers);
    }

    private void sendActualQestionCorrection(Session session, Integer presentationID, String string) {
        List<QuestionOption> questionOptions = quizzesInOngoingPhase.get(presentationID).getQuizData().getContent()
                .getQuestion().get(quizzesInOngoingPhase.get(presentationID).getActualQuestion())
                .getQuestionContent().getQuestionOption();
        int i = 0;
        List<Integer> corrects = new ArrayList<Integer>();
        for (QuestionOption option : questionOptions) {
            if (option.isIsCorrect()) {
                corrects.add(i);
            }
            i++;
        }
        EndpointUtil.sendUpdateToAll(peers, createQuizCorrectionString(corrects));
    }

    private boolean isQuizOwner(Integer presentationID, Session peer) {
        return quizzesInOngoingPhase.get(presentationID).getQuizPresentation().getOwner().getSecretkey()
                .equalsIgnoreCase(userSessions.get(peer.getId()));
    }

    private String createFollowersUpdateString(Integer presentationID) {
        JSONStringer creator = new JSONStringer();
        creator.object().key("type").value("FOLLOWERSUPDATE").key("followers").array();
        Map<String, User> users = quizzesInOngoingPhase.get(presentationID).getFollowers();
        for (String key : users.keySet()) {
            User user = users.get(key);
            creator.object().key("username").value(user.getLogin()).endObject();
        }
        creator.endArray().endObject();
        return creator.toString();
    }

    private String createQuizQuestionUpdateString(Integer presentationID, Integer questionID) {
        logger.debug("sendQuizQestion createQuizQuestionUpdateString start: questionID: " + questionID);
        JSONStringer creator = new JSONStringer();
        Question question = quizzesInOngoingPhase.get(presentationID).getQuestionData(questionID);
        creator.object().key("type").value("QUESTION").key("questionTitle").value(question.getQuestionTitle())
                .key("questionID").value(questionID).key("questionBody").value(question.getQuestionBody())
                .key("options").array();
        for (QuestionOption option : question.getQuestionContent().getQuestionOption()) {
            creator.object().key("optionBody").value(option.getQuestionOptionBody()).endObject();
        }
        creator.endArray().endObject();
        logger.debug("sendQuizQestion createQuizQuestionUpdateString finish");
        return creator.toString();
    }

    private String createUserAnswerUpdateString(Integer presentationID) {
        JSONStringer creator = new JSONStringer();
        QuizRoom quiz = quizzesInOngoingPhase.get(presentationID);
        creator.object().key("type").value("ANSWERUPDATE").key("answers").array();
        for (String secretkey : userAnswers.keySet()) {
            User user = EndpointUtil.getUserByKey(secretkey);
            creator.object().key("username").value(user.getLogin()).key("selected").value(
                    userAnswers.get(secretkey)[quizzesInOngoingPhase.get(presentationID).getActualQuestion()])
                    .endObject();
        }
        creator.endArray().endObject();
        return creator.toString();
    }

    private String createQuizCorrectionString(List<Integer> corrects) {
        JSONStringer creator = new JSONStringer();
        creator.object().key("type").value("CORRECTION").key("corrects").array();
        for (Integer correct : corrects) {
            creator.object().key("optionID").value(correct).endObject();
        }
        creator.endArray().endObject();
        return creator.toString();
    }
}