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

Last change on this file since 1614 was 1561, checked in by pharms, 10 years ago
  • update of namespaces for HTTP logfiles
File size: 12.2 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.math.BigInteger;
18import java.nio.ByteBuffer;
19import java.util.Collection;
20import java.util.Enumeration;
21import java.util.LinkedList;
22import java.util.List;
23import java.util.logging.Level;
24
25import javax.servlet.http.HttpServletRequest;
26import javax.servlet.http.HttpServletResponse;
27
28import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorExchangeHandler;
29import de.ugoe.cs.autoquest.plugin.http.logdata.Address;
30import de.ugoe.cs.autoquest.plugin.http.logdata.Content;
31import de.ugoe.cs.autoquest.plugin.http.logdata.Cookie;
32import de.ugoe.cs.autoquest.plugin.http.logdata.Cookies;
33import de.ugoe.cs.autoquest.plugin.http.logdata.Header;
34import de.ugoe.cs.autoquest.plugin.http.logdata.Headers;
35import de.ugoe.cs.autoquest.plugin.http.logdata.HttpExchange;
36import de.ugoe.cs.autoquest.plugin.http.logdata.HttpRequest;
37import de.ugoe.cs.autoquest.plugin.http.logdata.HttpResponse;
38import de.ugoe.cs.autoquest.plugin.http.logdata.Method;
39import de.ugoe.cs.autoquest.plugin.http.logdata.ObjectFactory;
40import de.ugoe.cs.autoquest.plugin.http.logdata.Protocol;
41import de.ugoe.cs.autoquest.plugin.http.logdata.Status;
42import de.ugoe.cs.util.console.Console;
43
44/**
45 * <p>
46 * recording an exchange can not be done in one step. This is due to the fact, that the proxy
47 * servlet notifies different processing states for requests and response. An exchange listener
48 * records all these event. On the occurrence of the final event, it compiles an
49 * {@link HttpExchange} and forwards it to the exchange handler.
50 * </p>
51 *
52 * @author Patrick Harms
53 */
54class ExchangeListener {
55   
56    /**
57     * <p>
58     * the exchange handler to forward compiles exchanges to
59     * </p>
60     */
61    private HttpMonitorExchangeHandler exchangeHandler;
62   
63    /**
64     * <p>
65     * the request of compiled exchange
66     * </p>
67     */
68    private HttpServletRequest request;
69
70    /**
71     * <p>
72     * the content of the request of compiled exchange
73     * </p>
74     */
75    private List<ByteBuffer> requestData = new LinkedList<ByteBuffer>();
76   
77    /**
78     * <p>
79     * the response of compiled exchange
80     * </p>
81     */
82    private HttpServletResponse response;
83
84    /**
85     * <p>
86     * the content of the response of compiled exchange
87     * </p>
88     */
89    private List<ByteBuffer> responseData = new LinkedList<ByteBuffer>();
90   
91    /**
92     * <p>
93     * the last time an event for the exchange was received (used for supporting timeouts)
94     * </p>
95     */
96    private long lastUpdate = System.currentTimeMillis();
97   
98    /**
99     * <p>
100     * initialized the exchange listener with the exchange handler to forward compiled exchanges to
101     * </p>
102     *
103     * @param exchangeHandler the exchange handler to forward compiled exchanges to
104     */
105    ExchangeListener(HttpMonitorExchangeHandler exchangeHandler) {
106        this.exchangeHandler = exchangeHandler;
107    }
108
109    /**
110     * <p>
111     * called, when the request was received by the proxy
112     * </p>
113     *
114     * @param request the request of the exchange
115     */
116    public void onRequest(HttpServletRequest request) throws IllegalStateException {
117        Console.traceln(Level.FINEST, this + ": onRequest " + request);
118
119        if (request == null) {
120            throw new IllegalArgumentException("request must not be null");
121        }
122
123        lastUpdate = System.currentTimeMillis();
124        this.request = request;
125    }
126
127    /**
128     * <p>
129     * called, when some content of the request was processed by the proxy
130     * </p>
131     *
132     * @param data the processed content of the request of the exchange
133     */
134    public void onRequestContent(ByteBuffer data) {
135        Console.traceln(Level.FINEST, this + ": onRequestContent " + data);
136
137        if (data == null) {
138            throw new IllegalArgumentException("data must not be null");
139        }
140
141        lastUpdate = System.currentTimeMillis();
142        requestData.add(data);
143    }
144   
145    /**
146     * <p>
147     * called, when the response is to be returned by the proxy
148     * </p>
149     *
150     * @param response the response of the exchange
151     */
152    public void onResponse(HttpServletResponse response) {
153        Console.traceln(Level.FINEST, this + ": onResponse " + response);
154
155        if (response == null) {
156            throw new IllegalArgumentException("response must not be null");
157        }
158
159        lastUpdate = System.currentTimeMillis();
160        this.response = response;
161    }
162   
163    /**
164     * <p>
165     * called, when some content of the response was processed by the proxy
166     * </p>
167     *
168     * @param data the processed content of the response of the exchange
169     */
170    public void onResponseContent(ByteBuffer data) {
171        Console.traceln(Level.FINEST, this + ": onResponseContent " + data);
172
173        if (data == null) {
174            throw new IllegalArgumentException("data must not be null");
175        }
176
177        lastUpdate = System.currentTimeMillis();
178        responseData.add(data);
179    }
180   
181    /**
182     * <p>
183     * called, when proxy finished proxying a request
184     * </p>
185     *
186     * @param status the status of the proxying after finalization
187     */
188    public void onFinish(Status status) {
189        Console.traceln(Level.FINEST, this + ": onFinish " + status);
190
191        if (status == null) {
192            throw new IllegalArgumentException("status must not be null");
193        }
194
195        lastUpdate = System.currentTimeMillis();
196        sendToExchangeHandler(status);
197    }
198   
199    /**
200     * @return the request of the exchange
201     */
202    HttpServletRequest getRequest() {
203        return request;
204    }
205
206    /**
207     * @return the last time this listener received an event
208     */
209    long getLastUpdate() {
210        return lastUpdate;
211    }
212
213    /**
214     * <p>
215     * convenience method to compile an {@link HttpExchange} and send it to the exchange handler
216     * after finalization of the exchange.
217     * </p>
218     *
219     * @param status the status of the proxying after finalization
220     */
221    private void sendToExchangeHandler(Status status) {
222        ObjectFactory eventObjectFactory = new ObjectFactory();
223        HttpExchange exchange = eventObjectFactory.createHttpExchange();
224       
225        exchange.setStatus(status);
226       
227        // the remote address
228        Address address = eventObjectFactory.createAddress();
229        address.setIp(request.getRemoteAddr());
230        address.setHost(request.getRemoteHost());
231        address.setPort(BigInteger.valueOf(request.getRemotePort()));
232        exchange.setSender(address);
233       
234        // the local address
235        address = eventObjectFactory.createAddress();
236        address.setIp(request.getLocalAddr());
237        address.setHost(request.getLocalName());
238        address.setPort(BigInteger.valueOf(request.getLocalPort()));
239        exchange.setReceiver(address);
240       
241        exchange.setRequest(map(request, eventObjectFactory));
242        exchange.setResponse(map(response, eventObjectFactory));
243       
244        exchangeHandler.handleHttpExchange(exchange);
245    }
246
247    /**
248     * <p>
249     * convenience method to map an {@link HttpServletRequest} to an {@link HttpRequest}
250     * </p>
251     */
252    private HttpRequest map(HttpServletRequest request, ObjectFactory eventObjectFactory) {
253        HttpRequest eventRequest = eventObjectFactory.createHttpRequest();
254        eventRequest.setMethod(Method.fromValue(request.getMethod()));
255        eventRequest.setProtocol(Protocol.fromValue(request.getProtocol()));
256        eventRequest.setUrl(request.getRequestURL().toString());
257        eventRequest.setQuery(request.getQueryString());
258       
259        Headers headers = eventObjectFactory.createHeaders();
260        Enumeration<String> headerNames = request.getHeaderNames();
261        while (headerNames.hasMoreElements()) {
262            String headerName = headerNames.nextElement();
263           
264            Enumeration<String> headerValues = request.getHeaders(headerName);
265            while (headerValues.hasMoreElements()) {
266                Header header = eventObjectFactory.createHeader();
267                header.setKey(headerName);
268                header.setValue(headerValues.nextElement());
269                headers.getHeader().add(header);
270            }
271        }
272        eventRequest.setHeaders(headers);
273       
274        if (request.getCookies() != null) {
275            Cookies cookies = eventObjectFactory.createCookies();
276            for (javax.servlet.http.Cookie requestCookie : request.getCookies()) {
277                Cookie cookie = eventObjectFactory.createCookie();
278                cookie.setComment(requestCookie.getComment());
279                cookie.setDomain(requestCookie.getDomain());
280                cookie.setIsHttpOnly(requestCookie.isHttpOnly());
281                cookie.setIsSecure(requestCookie.getSecure());
282                cookie.setMaxAge(BigInteger.valueOf(requestCookie.getMaxAge()));
283                cookie.setName(requestCookie.getName());
284                cookie.setPath(requestCookie.getPath());
285                cookie.setValue(requestCookie.getValue());
286                cookie.setVersion(BigInteger.valueOf(requestCookie.getVersion()));
287                cookies.getCookie().add(cookie);
288            }
289            eventRequest.setCookies(cookies);
290        }
291       
292        eventRequest.setAuthType(request.getAuthType());
293        eventRequest.setRemoteUser(request.getRemoteUser());
294        eventRequest.setRequestedSessionId(request.getRequestedSessionId());
295       
296        if (requestData.size() > 0) {
297            Content content = eventObjectFactory.createContent();
298            content.setEncoding(request.getCharacterEncoding());
299            content.setType(request.getContentType());
300            content.setLength(request.getContentLength());
301            content.setData(createString(requestData));
302            eventRequest.setContent(content);
303        }
304       
305        return eventRequest;
306    }
307
308    /**
309     * <p>
310     * convenience method to map an {@link HttpServletResponse} to an {@link HttpResponse}
311     * </p>
312     */
313    private HttpResponse map(HttpServletResponse response, ObjectFactory eventObjectFactory) {
314        HttpResponse eventResponse = eventObjectFactory.createHttpResponse();
315       
316        eventResponse.setStatus(BigInteger.valueOf(response.getStatus()));
317
318        Headers headers = eventObjectFactory.createHeaders();
319        Collection<String> headerNames = response.getHeaderNames();
320        for (String headerName : headerNames) {
321            Collection<String> headerValues = response.getHeaders(headerName);
322            for (String headerValue : headerValues) {
323                Header header = eventObjectFactory.createHeader();
324                header.setKey(headerName);
325                header.setValue(headerValue);
326                headers.getHeader().add(header);
327            }
328        }
329        eventResponse.setHeaders(headers);
330       
331        if (responseData.size() > 0) {
332            Content content = eventObjectFactory.createContent();
333            content.setEncoding(response.getCharacterEncoding());
334            content.setType(response.getContentType());
335
336            String data = createString(responseData);
337            content.setLength(data.length());
338            content.setData(data);
339           
340            eventResponse.setContent(content);
341        }
342       
343        return eventResponse;
344    }
345
346    /**
347     * <p>
348     * convenience method to create a string out of recorded request or response content
349     * </p>
350     */
351    private String createString(List<ByteBuffer> bufferList) {
352        StringBuffer str = new StringBuffer();
353       
354        for (ByteBuffer buffer : bufferList) {
355            while (buffer.hasRemaining()) {
356                str.append((char) buffer.get());
357            }
358        }
359       
360        return str.toString();
361    }
362
363}
Note: See TracBrowser for help on using the repository browser.