/*
* Aipo is a groupware program developed by TOWN, Inc.
* Copyright (C) 2004-2015 TOWN, Inc.
* http://www.aipo.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aimluck.eip.http;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.catalina.comet.CometEvent;
import org.apache.catalina.comet.CometProcessor;
import com.aimluck.eip.common.ALBaseUser;
import com.aimluck.eip.common.ALEipConstants;
/**
*
*/
public class ALCometServlet extends HttpServlet implements CometProcessor {
private static final long serialVersionUID = -3319969086920456957L;
public static final String KEY_MESSAGE_SENDER =
"com.aimluck.eip.http.ALCometServlet.MessageSender";
protected transient ConcurrentHashMap<HttpServletResponse, String> connections =
null;
protected transient MessageSender sender = null;
@Override
public void init() {
connections = new ConcurrentHashMap<HttpServletResponse, String>();
this.sender = new MessageSender();
this.sender.setDaemon(true);
this.sender.start();
getServletContext().setAttribute(KEY_MESSAGE_SENDER, sender);
}
@Override
public void destroy() {
sender.quit();
sender = null;
connections.clear();
}
/**
* @param event
* @throws IOException
* @throws ServletException
*/
@Override
public void event(CometEvent event) throws IOException, ServletException {
try {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
ALBaseUser user = getUser(request);
if (user == null) {
close(response);
event.close();
return;
}
switch (event.getEventType()) {
case BEGIN:
open(request, response);
event.setTimeout(60 * 60 * 1000);
break;
case READ:
open(request, response);
event.setTimeout(60 * 60 * 1000);
break;
case END:
close(response);
event.close();
break;
case ERROR:
close(response);
event.close();
break;
default:
break;
}
} catch (Throwable t) {
log(t.getMessage(), t);
}
}
protected void open(HttpServletRequest request, HttpServletResponse response) {
ALBaseUser user = getUser(request);
if (user != null) {
connections.put(response, user.getUserName());
}
}
protected void close(HttpServletResponse response) {
try {
if (!response.isCommitted()) {
response.setContentType("text/json");
response.setCharacterEncoding("UTF-8");
ServletOutputStream os = response.getOutputStream();
os.write("{}".getBytes(ALEipConstants.DEF_CONTENT_ENCODING));
os.flush();
os.close();
}
} catch (Throwable t) {
log(t.getMessage(), t);
} finally {
try {
connections.remove(response);
} catch (Throwable ignore) {
//
}
}
}
protected ALBaseUser getUser(HttpServletRequest httpServletRequest) {
try {
HttpSession session = httpServletRequest.getSession(false);
if (session == null) {
return null;
}
return (ALBaseUser) session.getAttribute("turbine.user");
} catch (Throwable ignore) {
// ignore
}
return null;
}
public static class Message {
private final List<String> recipients;
private final String message;
public Message(List<String> recipients, String message) {
this.recipients = recipients;
this.message = message;
}
/**
* @return message
*/
public String getMessage() {
return message;
}
/**
* @return recipients
*/
public List<String> getRecipients() {
return recipients;
}
}
public class MessageSender extends Thread {
protected final List<Message> messages = new ArrayList<Message>();
protected boolean running = true;
public void quit() {
running = false;
messages.clear();
this.interrupt();
}
public synchronized void sendMessage(List<String> recipients, String message) {
try {
synchronized (messages) {
messages.add(new Message(recipients, message));
messages.notify();
}
} catch (Throwable ignore) {
//
}
}
@Override
public void run() {
while (running) {
try {
if (messages.size() == 0) {
try {
synchronized (messages) {
messages.wait();
}
} catch (InterruptedException ignore) {
// Ignore
}
}
Message[] pendingMessages = null;
synchronized (messages) {
pendingMessages = messages.toArray(new Message[0]);
messages.clear();
}
for (Message message : pendingMessages) {
Iterator<Entry<HttpServletResponse, String>> iterator =
connections.entrySet().iterator();
while (iterator.hasNext()) {
Entry<HttpServletResponse, String> next = iterator.next();
if (message.getRecipients().contains(next.getValue())) {
HttpServletResponse response = next.getKey();
try {
if (!response.isCommitted()) {
response.setContentType("text/json");
response.setCharacterEncoding("UTF-8");
ServletOutputStream os = response.getOutputStream();
os.write(message.getMessage().getBytes(
ALEipConstants.DEF_CONTENT_ENCODING));
os.flush();
os.close();
}
} catch (Throwable t) {
log(t.getMessage(), t);
} finally {
try {
connections.remove(response);
} catch (Throwable ignore) {
//
}
}
}
}
pendingMessages = null;
}
try {
Thread.sleep(100);
} catch (Throwable ignore) {
//
}
} catch (Throwable t) {
log(t.getMessage(), t);
//
}
}
}
}
}