// Copyright 2012 Georg-August-Universität Göttingen, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package de.ugoe.cs.autoquest.httpmonitor.proxy;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorComponent;
import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorException;
import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorExchangeHandler;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Status;
import de.ugoe.cs.util.console.Console;
/**
*
* TODO update comment
* The log manager handles different {@link HttpMonitorOutputWriter}s to perform the logging
* of recorded messages. It initializes a new writer if the first message for a specific
* client is received and it closes a writer if for a specific period of time no further message
* of the same client was received. The writers themselves consider log rotation. For handling
* messages, the {@link HttpMonitorExchangeHandler} mechanism provided by the
* {@link HttpMonitorServer} is used.
*
*
* @author Patrick Harms
*/
class ExchangeListenerManager implements HttpMonitorComponent {
/**
* the timeout after which a writer of an inactive client is closed
*/
private static final int SESSION_TIMEOUT = 10 * 60 * 1000;
/**
*
*/
private HttpMonitorExchangeHandler exchangeHandler;
/**
* the mapping of client ids to the respective writers.
*/
private Map listeners;
/**
* a timer used to detect exchange timeouts
*/
private Timer listenerTimer;
/**
*
*
*/
ExchangeListenerManager(HttpMonitorExchangeHandler exchangeHandler) {
this.exchangeHandler = exchangeHandler;
}
/* (non-Javadoc)
* @see de.ugoe.cs.autoquest.htmlmonitor.HtmlMonitorComponent#init()
*/
@Override
public synchronized void init() throws IllegalStateException, HttpMonitorException {
Console.traceln(Level.FINER, "initializing exchange listener manager");
if (listeners != null) {
throw new IllegalStateException("already initialized");
}
listeners = new HashMap();
listenerTimer = new Timer();
}
/* (non-Javadoc)
* @see de.ugoe.cs.autoquest.htmlmonitor.HtmlMonitorComponent#start()
*/
@Override
public synchronized void start() throws IllegalStateException, HttpMonitorException {
Console.traceln(Level.FINER, "starting exchange listener manager");
if (listeners == null) {
throw new IllegalStateException("not initialized");
}
listenerTimer.schedule
(new ListenerMonitorTimerTask(), SESSION_TIMEOUT / 2, SESSION_TIMEOUT / 2);
}
/* (non-Javadoc)
* @see de.ugoe.cs.autoquest.htmlmonitor.HtmlMonitorComponent#stop()
*/
@Override
public synchronized void stop() {
Console.traceln(Level.FINER, "stopping exchange listener manager");
if (listenerTimer != null) {
listenerTimer.cancel();
}
if (listeners != null) {
for (ExchangeListener listener : listeners.values()) {
listener.onFinish(Status.TIMEOUT);
}
}
listeners = null;
}
/**
*
*/
public void onRequest(HttpServletRequest request) throws IllegalStateException {
ensureListener(request).onRequest(request);
}
/**
*
*/
public void onRequestContent(HttpServletRequest request, ByteBuffer data)
throws IllegalStateException
{
ensureListener(request).onRequestContent(data);
}
/**
*
*/
public void onResponse(HttpServletRequest request, HttpServletResponse response)
throws IllegalStateException
{
ensureListener(request).onResponse(response);
}
/**
*
*/
public void onResponseContent(HttpServletRequest request, ByteBuffer data)
throws IllegalStateException
{
ensureListener(request).onResponseContent(data);
}
/**
*
*/
public void onFinish(HttpServletRequest request, Status status) throws IllegalStateException {
ensureListener(request).onFinish(status);
Console.traceln(Level.FINEST, "removing exchange listener for " + request);
listeners.remove(request);
}
/**
*
*/
private ExchangeListener ensureListener(HttpServletRequest request) {
ExchangeListener listener = listeners.get(request);
if (listener == null) {
synchronized (this) {
listener = listeners.get(request);
if (listener == null) {
Console.traceln(Level.FINEST, "creating exchange listener for " + request);
listener = new ExchangeListener(exchangeHandler);
listeners.put(request, listener);
}
}
}
return listener;
}
/**
*
* internal timer task used for detecting session timeouts of clients
*
*
* @author Patrick Harms
*/
public class ListenerMonitorTimerTask extends TimerTask {
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
synchronized (ExchangeListenerManager.this) {
List timeoutRequests = new ArrayList();
for (Map.Entry entry : listeners.entrySet()) {
ExchangeListener listener = entry.getValue();
if (System.currentTimeMillis() - listener.getLastUpdate() > SESSION_TIMEOUT) {
timeoutRequests.add(entry.getKey());
}
}
for (HttpServletRequest request : timeoutRequests) {
ExchangeListener listener = listeners.remove(request);
listener.onFinish(Status.TIMEOUT);
}
}
}
}
}