de.dailab.plistacontest.client.ClientAndContestHandler0MQ.java Source code

Java tutorial

Introduction

Here is the source code for de.dailab.plistacontest.client.ClientAndContestHandler0MQ.java

Source

/*
Copyright (c) 2014, TU Berlin
Permission is hereby granted, free of charge, to any person obtaining 
a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
DEALINGS IN THE SOFTWARE.
 */
package de.dailab.plistacontest.client;

import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.List;
import java.util.Properties;

/**
 * Class to handle the communication with the CLEF NewsREEL challenge server Functions:
 * - parsing incoming Requests (based on 0MQ) - parse and handle the messages
 * 
 * @author till, andreas, thanh
 * 
 */
public class ClientAndContestHandler0MQ {

    /**
     * Define the default logger
     */
    private final static Logger logger = LoggerFactory.getLogger(ClientAndContestHandler0MQ.class);

    /**
     * here we store all relevant data about items.
     */
    private final RecommenderItemTable recommenderItemTable = new RecommenderItemTable();

    /**
     * Define the default recommender, currently not used.
     */
    @SuppressWarnings("unused")
    private Object contestRecommender;

    /**
     * Constructor, sets some default values.
     * 
     * @param _properties
     * @param _contestRecommender
     */
    public ClientAndContestHandler0MQ(final Properties _properties, final Object _contestRecommender) {

        this.contestRecommender = _contestRecommender;

    }

    /**
     * Handle incoming messages. This method is called by plista We check the
     * message, and extract the relevant parameter values
     * 
     * @see org.eclipse.jetty.server.Handler#handle(String,
     *      org.eclipse.jetty.server.Request,
     *      javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse)
     */
    public String handle(String typeMessage, String bodyMessage, String propertyMessage, String entityMessage)
            throws IOException {

        String responseText = "";
        String encoding = null;

        // handle idomaar messages
        if (bodyMessage == null || bodyMessage.length() == 0) {

            // we may recode the body message
            if (encoding != null) {
                bodyMessage = URLDecoder.decode(bodyMessage, encoding);
                propertyMessage = URLDecoder.decode(propertyMessage, encoding);
                entityMessage = URLDecoder.decode(entityMessage, encoding);
            }

            // delegate the request and create a response message
            responseText = handleIdomaarMessage(typeMessage, propertyMessage, entityMessage);
            return responseText;

        } else {
            // handle old data format messages
            // we may recode the body message
            if (encoding != null) {
                bodyMessage = URLDecoder.decode(bodyMessage, "utf-8");
            }
            responseText = handleTraditionalMessage(typeMessage, bodyMessage);
        }
        // send the response message as text
        return responseText;
    }

    /**
     * Method to handle incoming messages from the server.
     * 
     * @param messageType
     *                the messageType of the incoming contest server message.
     * @param properties
     *                
     * @param entities
     * @return the response to the contest server
     */
    private String handleIdomaarMessage(final String messageType, final String properties, final String entities) {
        // write all data from the server to a file
        logger.info(messageType + "\t" + properties + "\t" + entities);

        // create an jSON object from the String
        final JSONObject jOP = (JSONObject) JSONValue.parse(properties);
        final JSONObject jOE = (JSONObject) JSONValue.parse(entities);

        // merge the different jsonObjects and correct missing itemIDs
        jOP.putAll(jOE);
        Object itemID = jOP.get("itemID");
        if (itemID == null) {
            jOP.put("itemID", 0);
        }

        // define a response object
        String response = null;

        if ("impression".equalsIgnoreCase(messageType)) {

            // parse the type of the event
            final RecommenderItem item = RecommenderItem.parseEventNotification(jOP.toJSONString());
            final String eventNotificationType = item.getNotificationType();

            // new items shall be added to the list of items
            if (item.getItemID() != null) {
                recommenderItemTable.handleItemUpdate(item);
            }
            response = "handle impression eventNotification successful";

            // impression refers to articles read by the user
            if ("recommendation_request".equalsIgnoreCase(eventNotificationType)) {

                // we mark this information in the article table
                if (item.getItemID() != null) {

                    item.setNumberOfRequestedResults(6);
                    //List<Long> suggestedItemIDs = item.getListOfDisplayedRecs();
                    List<Long> suggestedItemIDs = recommenderItemTable.getLastItems(item);
                    response = "{" + "\"recs\": {" + "\"ints\": {" + "\"3\": " + suggestedItemIDs + "}" + "}}";

                } else {
                    System.err.println("invalid itemID - requests are only valid for 'normal' articles");
                }
                // click refers to recommendations clicked by the user
            } else if ("click".equalsIgnoreCase(eventNotificationType)) {

                // we mark this information in the article table
                if (item.getItemID() != null) {
                    // new items shall be added to the list of items
                    recommenderItemTable.handleItemUpdate(item);

                    response = "handle impression eventNotification successful";
                }
                response = "handle click eventNotification successful";

            } else {
                System.out.println("unknown event-type: " + eventNotificationType + " (message ignored)");
            }

        } else if ("error_notification".equalsIgnoreCase(messageType)) {

            System.out.println("error-notification: " + jOP.toString() + jOE.toJSONString());

        } else {
            System.out.println("unknown MessageType: " + messageType);
            // Error handling
            logger.info(jOP.toString() + jOE.toJSONString());
            // this.contestRecommender.error(jObj.toString());
        }
        return response;
    }

    /**
     * Method to handle incoming messages from the server.
     * 
     * @param messageType
     *            the messageType of the incoming contest server message
     * @param _jsonString
     *            the incoming contest server message
     * @return the response to the contest server
     */
    @SuppressWarnings("unused")
    private String handleTraditionalMessage(final String messageType, final String _jsonMessageBody) {

        // write all data from the server to a file
        logger.info(messageType + "\t" + _jsonMessageBody);

        // create an jSON object from the String
        final JSONObject jObj = (JSONObject) JSONValue.parse(_jsonMessageBody);

        // define a response object
        String response = null;

        // TODO handle "item_create"

        // in a complex if/switch statement we handle the differentTypes of
        // messages
        if ("item_update".equalsIgnoreCase(messageType)) {

            // we extract itemID, domainID, text and the timeTime, create/update
            final RecommenderItem recommenderItem = RecommenderItem.parseItemUpdate(_jsonMessageBody);

            // we mark this information in the article table
            if (recommenderItem.getItemID() != null) {
                recommenderItemTable.handleItemUpdate(recommenderItem);
            }

            response = ";item_update successfull";
        }

        else if ("recommendation_request".equalsIgnoreCase(messageType)) {
            final RecommenderItem recommenderItem = RecommenderItem.parseItemUpdate(_jsonMessageBody);

            // we handle a recommendation request
            try {
                // parse the new recommender request
                RecommenderItem currentRequest = RecommenderItem.parseRecommendationRequest(_jsonMessageBody);

                // gather the items to be recommended
                List<Long> resultList = recommenderItemTable.getLastItems(currentRequest);
                if (resultList == null) {
                    response = "[]";
                    System.out.println("invalid resultList");
                } else {
                    response = resultList.toString();
                }
                response = getRecommendationResultJSON(response);

                // TODO? might handle the the request as impressions
            } catch (Throwable t) {
                t.printStackTrace();
            }
        } else if ("event_notification".equalsIgnoreCase(messageType)) {

            // parse the type of the event
            final RecommenderItem item = RecommenderItem.parseEventNotification(_jsonMessageBody);
            final String eventNotificationType = item.getNotificationType();

            // impression refers to articles read by the user
            if ("impression".equalsIgnoreCase(eventNotificationType)
                    || "impression_empty".equalsIgnoreCase(eventNotificationType)) {

                // we mark this information in the article table
                if (item.getItemID() != null) {
                    // new items shall be added to the list of items
                    recommenderItemTable.handleItemUpdate(item);

                    response = "handle impression eventNotification successful";
                }
                // click refers to recommendations clicked by the user
            } else if ("click".equalsIgnoreCase(eventNotificationType)) {

                response = "handle click eventNotification successful";

            } else {
                System.out.println("unknown event-type: " + eventNotificationType + " (message ignored)");
            }

        } else if ("error_notification".equalsIgnoreCase(messageType)) {

            System.out.println("error-notification: " + _jsonMessageBody);

        } else {
            System.out.println("unknown MessageType: " + messageType);
            // Error handling
            logger.info(jObj.toString());
            // this.contestRecommender.error(jObj.toString());
        }
        return response;
    }

    /**
     * Create a json response object for recommendation requests.
     * 
     * @param _itemsIDs
     *     the recommendation result
     * @return 
     *       the recommendation result as json
     */
    public static final String getRecommendationResultJSON(String _itemsIDs) {

        // invalid recommendations result in empty result sets
        if (_itemsIDs == null || _itemsIDs.length() == 0) {
            _itemsIDs = "[]";
        }
        // add brackets if needed
        else if (!_itemsIDs.trim().startsWith("[")) {
            _itemsIDs = "[" + _itemsIDs + "]";
        }
        // build result as JSON according to formal requirements
        String result = "{" + "\"recs\": {" + "\"ints\": {" + "\"3\": " + _itemsIDs + "}" + "}}";

        return result;
    }

    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////
    ///////////////////////////////////////////////

    /**
     * the default constructor.
     */
    public ClientAndContestHandler0MQ() {
        super();
    }

    /**
     * This method starts the server
     * 
     * @param args [hostname:port, properties_filename]
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        // you might want to use a recommender
        Object recommender = null;

        String hostname = "0.0.0.0";
        int port = 8081;
        try {
            hostname = args[0].substring(0, args[0].indexOf(":"));
            port = Integer.parseInt(args[0].substring(args[0].indexOf(":") + 1));
        } catch (Exception e) {
            System.out.println("No hostname and port given. Using default 0.0.0.0:8081");
            logger.info(e.getMessage());
        }

        // initialize zeroMQ
        // initialize the 0MQ
        ZContext context = new ZContext();
        ZMQ.Socket clientSocket = context.createSocket(ZMQ.SUB);
        String serverURL = "tcp://" + hostname + ":" + port;
        if (serverURL == null) {
            serverURL = "tcp://127.0.0.1:8088";
        }
        clientSocket.bind(serverURL);

        // create the handler 
        ClientAndContestHandler0MQ me = new ClientAndContestHandler0MQ();
        for (;;) {
            String message = clientSocket.recvStr();
            // split the message
            String[] token = message.split("\t");

            // call handle and provide the relevant token
            String result = me.handle(token[0], null, token[3], token[4]);

            // send back the result
            clientSocket.send(result);
        }
    }
}