source: trunk/autoquest-httpmonitor/src/main/java/de/ugoe/cs/autoquest/httpmonitor/proxy/ExchangeListenerManager.java @ 1384

Last change on this file since 1384 was 1384, checked in by pharms, 10 years ago
  • removed find bugs warning
File size: 8.4 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.httpmonitor.proxy;
16
17import java.nio.ByteBuffer;
18import java.util.ArrayList;
19import java.util.HashMap;
20import java.util.List;
21import java.util.Map;
22import java.util.Timer;
23import java.util.TimerTask;
24import java.util.logging.Level;
25
26import javax.servlet.http.HttpServletRequest;
27import javax.servlet.http.HttpServletResponse;
28
29import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorComponent;
30import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorException;
31import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorExchangeHandler;
32import de.ugoe.cs.autoquest.httpmonitor.exchange.Status;
33import de.ugoe.cs.util.console.Console;
34
35/**
36 * <p>
37 * {@link ExchangeListener}s need to be managed, as there is one instantiated for each proxied
38 * request/response. They need to be timed out, if for a longer time, no update is received. All
39 * this is done by the ExchangeListenerManager.
40 * </p>
41 *
42 * @author Patrick Harms
43 */
44class ExchangeListenerManager implements HttpMonitorComponent {
45
46    /**
47     * <p>
48     * the timeout after which a writer of an inactive client is closed
49     * </p>
50     */
51    private static final int SESSION_TIMEOUT = 10 * 60 * 1000;
52   
53    /**
54     * <p>
55     * the exchange handler forwarded to the exchange listeners
56     * </p>
57     */
58    private HttpMonitorExchangeHandler exchangeHandler;
59   
60    /**
61     * <p>
62     * the mapping of requests handled by the proxy to the respective exchange listeners
63     * </p>
64     */
65    private Map<HttpServletRequest, ExchangeListener> listeners;
66
67    /**
68     * <p>
69     * a timer used to detect exchange listener timeouts
70     * </p>
71     */
72    private Timer listenerTimer;
73
74    /**
75     * <p>
76     * creates the exchange listener manager with the exchange handler to be forwarded to the
77     * exchange listeners
78     * </p>
79     *
80     * @param exchangeHandler the exchange handler to be forwarded to the exchange listeners
81     */
82    ExchangeListenerManager(HttpMonitorExchangeHandler exchangeHandler) {
83        this.exchangeHandler = exchangeHandler;
84    }
85
86    /* (non-Javadoc)
87     * @see de.ugoe.cs.autoquest.htmlmonitor.HtmlMonitorComponent#init()
88     */
89    @Override
90    public synchronized void init() throws IllegalStateException, HttpMonitorException {
91        Console.traceln(Level.FINER, "initializing exchange listener manager");
92       
93        if (listeners != null) {
94            throw new IllegalStateException("already initialized");
95        }
96       
97        listeners = new HashMap<HttpServletRequest, ExchangeListener>();
98        listenerTimer = new Timer();
99    }
100
101    /* (non-Javadoc)
102     * @see de.ugoe.cs.autoquest.htmlmonitor.HtmlMonitorComponent#start()
103     */
104    @Override
105    public synchronized void start() throws IllegalStateException, HttpMonitorException {
106        Console.traceln(Level.FINER, "starting exchange listener manager");
107
108        if (listeners == null) {
109            throw new IllegalStateException("not initialized");
110        }
111       
112        listenerTimer.schedule
113            (new ListenerMonitorTimerTask(), SESSION_TIMEOUT / 2, SESSION_TIMEOUT / 2);
114    }
115
116    /* (non-Javadoc)
117     * @see de.ugoe.cs.autoquest.htmlmonitor.HtmlMonitorComponent#stop()
118     */
119    @Override
120    public synchronized void stop() {
121        Console.traceln(Level.FINER, "stopping exchange listener manager");
122
123        if (listenerTimer != null) {
124            listenerTimer.cancel();
125        }
126       
127        if (listeners != null) {
128            for (ExchangeListener listener : listeners.values()) {
129                listener.onFinish(Status.TIMEOUT);
130            }
131        }
132       
133        listeners = null;
134    }
135
136    /**
137     * <p>
138     * called, when the request was received by the proxy. Calls the appropriate method on
139     * the exchange listener.
140     * </p>
141     *
142     * @param request the request of the exchange
143     */
144    public void onRequest(HttpServletRequest request) throws IllegalStateException {
145        ensureListener(request).onRequest(request);
146    }
147
148    /**
149     * <p>
150     * called, when some content of the request was processed by the proxy. Calls the appropriate
151     * method on the exchange listener.
152     * </p>
153     *
154     * @param request the request of the exchange
155     * @param data    the processed content of the request of the exchange
156     */
157    public void onRequestContent(HttpServletRequest request, ByteBuffer data)
158        throws IllegalStateException
159    {
160        ensureListener(request).onRequestContent(data);
161    }
162
163    /**
164     * <p>
165     * called, when the response is to be returned by the proxy. Calls the appropriate
166     * method on the exchange listener.
167     * </p>
168     *
169     * @param request  the request of the exchange
170     * @param response the response of the exchange
171     */
172    public void onResponse(HttpServletRequest request, HttpServletResponse response)
173        throws IllegalStateException
174    {
175        ensureListener(request).onResponse(response);
176    }
177
178    /**
179     * <p>
180     * called, when some content of the response was processed by the proxy. Calls the appropriate
181     * method on the exchange listener.
182     * </p>
183     *
184     * @param request the request of the exchange
185     * @param data    the processed content of the response of the exchange
186     */
187    public void onResponseContent(HttpServletRequest request, ByteBuffer data)
188        throws IllegalStateException
189    {
190        ensureListener(request).onResponseContent(data);
191    }
192
193    /**
194     * <p>
195     * called, when proxy finished proxying a request. Calls the appropriate method on the
196     * exchange listener and afterwards cleans up the listener.
197     * </p>
198     *
199     * @param request the request of the exchange
200     * @param status  the status of the proxying after finalization
201     */
202    public void onFinish(HttpServletRequest request, Status status) throws IllegalStateException {
203        ensureListener(request).onFinish(status);
204        Console.traceln(Level.FINEST, "removing exchange listener for " + request);
205        listeners.remove(request);
206    }
207
208    /**
209     * <p>
210     * convenience method to ensure a listener for a specific HTTP servlet request to be handled.
211     * </p>
212     */
213    private ExchangeListener ensureListener(HttpServletRequest request) {
214        ExchangeListener listener = listeners.get(request);
215       
216        if (listener == null) {
217            synchronized (this) {
218                listener = listeners.get(request);
219                if (listener == null) {
220                    Console.traceln(Level.FINEST, "creating exchange listener for " + request);
221                    listener = new ExchangeListener(exchangeHandler);
222                    listeners.put(request, listener);
223                }
224            }
225        }
226
227        return listener;
228    }
229
230    /**
231     * <p>
232     * internal timer task used for detecting exchange timeouts
233     * </p>
234     *
235     * @author Patrick Harms
236     */
237    public class ListenerMonitorTimerTask extends TimerTask {
238
239        /* (non-Javadoc)
240         * @see java.lang.Runnable#run()
241         */
242        @Override
243        public void run() {
244            synchronized (ExchangeListenerManager.this) {
245                List<HttpServletRequest> timeoutRequests = new ArrayList<HttpServletRequest>();
246                for (Map.Entry<HttpServletRequest, ExchangeListener> entry : listeners.entrySet()) {
247                    ExchangeListener listener = entry.getValue();
248                   
249                    if (System.currentTimeMillis() - listener.getLastUpdate() > SESSION_TIMEOUT) {
250                        timeoutRequests.add(entry.getKey());
251                    }
252                }
253               
254                for (HttpServletRequest request : timeoutRequests) {
255                    ExchangeListener listener = listeners.remove(request);
256                    listener.onFinish(Status.TIMEOUT);
257                }
258            }
259        }
260
261    }
262
263}
Note: See TracBrowser for help on using the repository browser.