Package net.socialgamer.cah.servlets

Source Code of net.socialgamer.cah.servlets.LongPollServlet

/**
* Copyright (c) 2012, Andy Janata
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions
*   and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
*   conditions and the following disclaimer in the documentation and/or other materials provided
*   with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package net.socialgamer.cah.servlets;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.socialgamer.cah.Constants.LongPollEvent;
import net.socialgamer.cah.Constants.LongPollResponse;
import net.socialgamer.cah.Constants.ReturnableData;
import net.socialgamer.cah.Constants.SessionAttribute;
import net.socialgamer.cah.data.QueuedMessage;
import net.socialgamer.cah.data.User;


/**
* Servlet implementation class LongPollServlet.
*
* This servlet is used for client long polling requests.
*
* @author Andy Janata (ajanata@socialgamer.net)
*/
@WebServlet("/LongPollServlet")
public class LongPollServlet extends CahServlet {
  private static final long serialVersionUID = 1L;

  /**
   * Minimum amount of time before timing out and returning a no-op, in nanoseconds.
   */
  private static final long TIMEOUT_BASE = TimeUnit.SECONDS.toNanos(20);
  //  private static final long TIMEOUT_BASE = 10 * 1000 * 1000;

  /**
   * Randomness factor added to minimum timeout duration, in nanoseconds. The maximum timeout delay
   * will be TIMEOUT_BASE + TIMEOUT_RANDOMNESS - 1.
   */
  private static final double TIMEOUT_RANDOMNESS = TimeUnit.SECONDS.toNanos(5);
  //  private static final double TIMEOUT_RANDOMNESS = 0;

  /**
   * The maximum number of messages which will be returned to a client during a single poll
   * operation.
   */
  private static final int MAX_MESSAGES_PER_POLL = 20;

  /**
   * An amount of milliseconds to wait after being notified that the user has at least one message
   * to deliver, before we actually deliver messages. This will allow multiple messages that arrive
   * in close proximity to each other to actually be delivered in the same client request.
   */
  private static final int WAIT_FOR_MORE_DELAY = 50;

  /**
   * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
   */
  @Override
  protected void handleRequest(final HttpServletRequest request,
      final HttpServletResponse response, final HttpSession hSession) throws ServletException,
      IOException {
    final PrintWriter out = response.getWriter();

    final long start = System.nanoTime();
    // Pick a random timeout point between [TIMEOUT_BASE, TIMEOUT_BASE + TIMEOUT_RANDOMNESS)
    // nanoseconds from now.
    final long end = start + TIMEOUT_BASE + (long) (Math.random() * TIMEOUT_RANDOMNESS);
    final User user = (User) hSession.getAttribute(SessionAttribute.USER);
    assert (user != null);
    user.contactedServer();
    while (!(user.hasQueuedMessages()) && System.nanoTime() - end < 0) {
      try {
        user.waitForNewMessageNotification(TimeUnit.NANOSECONDS.toMillis(end - System.nanoTime()));
      } catch (final InterruptedException ie) {
        // pass
      }
    }
    if (user.hasQueuedMessages()) {
      try {
        // Delay for a short while in case there will be other messages queued to be delivered.
        // This will certainly happen in some game states. We want to deliver as much to the client
        // in as few round-trips as possible while not waiting too long.
        Thread.sleep(WAIT_FOR_MORE_DELAY);
      } catch (final InterruptedException ie) {
        // pass
      }
      final Collection<QueuedMessage> msgs = user.getNextQueuedMessages(MAX_MESSAGES_PER_POLL);
      // just in case...
      if (msgs.size() > 0) {
        final List<Map<ReturnableData, Object>> data =
            new ArrayList<Map<ReturnableData, Object>>(msgs.size());
        for (final QueuedMessage qm : msgs) {
          data.add(qm.getData());
        }
        returnArray(user, out, data);
        return;
      }
    }
    // otherwise, return that there is no new data
    final Map<ReturnableData, Object> data = new HashMap<ReturnableData, Object>();
    data.put(LongPollResponse.EVENT, LongPollEvent.NOOP.toString());
    data.put(LongPollResponse.TIMESTAMP, System.currentTimeMillis());
    returnData(user, out, data);
  }
}
TOP

Related Classes of net.socialgamer.cah.servlets.LongPollServlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.