source: trunk/autoquest-plugin-http/src/main/java/de/ugoe/cs/autoquest/plugin/http/HTTPLogParser.java @ 1990

Last change on this file since 1990 was 1990, checked in by pharms, 9 years ago
File size: 10.1 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.plugin.http;
16
17import java.io.ByteArrayInputStream;
18import java.io.File;
19import java.io.FileInputStream;
20import java.io.FileNotFoundException;
21import java.io.IOException;
22import java.io.InputStream;
23import java.util.Collection;
24import java.util.LinkedList;
25import java.util.List;
26import java.util.Properties;
27import java.util.logging.Level;
28import java.util.logging.Logger;
29
30import javax.xml.bind.JAXBContext;
31import javax.xml.bind.JAXBElement;
32import javax.xml.bind.JAXBException;
33import javax.xml.bind.Unmarshaller;
34import javax.xml.soap.MessageFactory;
35import javax.xml.soap.SOAPMessage;
36import javax.xml.transform.stream.StreamSource;
37
38import org.xml.sax.SAXException;
39
40import de.ugoe.cs.autoquest.eventcore.Event;
41import de.ugoe.cs.autoquest.eventcore.IEventType;
42import de.ugoe.cs.autoquest.plugin.http.eventcore.HTTPEventType;
43import de.ugoe.cs.autoquest.plugin.http.eventcore.HTTPTarget;
44import de.ugoe.cs.autoquest.plugin.http.eventcore.SOAPEventType;
45import de.ugoe.cs.autoquest.plugin.http.logdata.Content;
46import de.ugoe.cs.autoquest.plugin.http.logdata.HttpExchange;
47import de.ugoe.cs.autoquest.plugin.http.logdata.Session;
48import de.ugoe.cs.util.console.Console;
49
50/**
51 * <p>
52 * Parser for HTTP Monitor logs. Uses JAXB for parsing and is therefore quite simple. For each
53 * exchange in the log, it creates an appropriate event. It differes between default HTTP events
54 * and SOAP events.
55 * </p>
56 *
57 * @author Patrick Harms
58 */
59public class HTTPLogParser {
60
61    /**
62     * <p>
63     * the event sequences parsed by this parser
64     * </p>
65     */
66    private Collection<List<Event>> sequences = new LinkedList<List<Event>>();
67   
68    /**
69     * <p>
70     * the message factory used for parsing SOAP messages
71     * </p>
72     */
73    private MessageFactory soapMessageFactory;
74   
75    /**
76     * <p>
77     * properties used to map the path of a service to its logical name
78     * </p>
79     */
80    private Properties urlNameMap = null;
81   
82    /**
83     * <p>
84     * Constructor. Creates a new HTTPLogParser without a urlNameMap.
85     * </p>
86     */
87    public HTTPLogParser() {
88        Logger.getLogger("com.sun.xml.internal.messaging.saaj").setLevel(Level.OFF);
89    }
90   
91    /**
92     * <p>
93     * Constructor. Creates a new HTTPLogParser with a urlNameMap
94     * </p>
95     *
96     * @param urlNameMapFile properties file with the path to logical name map
97     * @throws IOException thrown if there is an error load in the service name map
98     */
99    public HTTPLogParser(File urlNameMapFile) throws IOException {
100        this(new FileInputStream(urlNameMapFile));
101    }
102   
103    /**
104     * <p>
105     * Constructor. Creates a new HTTPLogParser with a urlNameMap
106     * </p>
107     *
108     * @param urlNameMapFile properties file with the path to logical name map
109     * @throws IOException thrown if there is an error load in the service name map
110     */
111    public HTTPLogParser(InputStream urlNameMapStream) throws IOException {
112        this();
113        urlNameMap = new Properties();
114        urlNameMap.load(urlNameMapStream);
115    }
116   
117    /**
118     * <p>
119     * Constructor. Creates a new HTTPLogParser with a urlNameMap.
120     * </p>
121     *
122     * @param urlNameMapFile properties that include the logical name map
123     */
124    public HTTPLogParser(Properties urlNameMapFile) {
125        this();
126        urlNameMap = urlNameMapFile;
127    }
128
129    /**
130     * <p>
131     * Parses a log file written by the HTTPMonitor and creates a collection of event sequences.
132     * </p>
133     *
134     * @param filename
135     *            name and path of the log file
136     *
137     * @throws SAXException in the case, the file could not be parsed
138     */
139    public void parseFile(String filename) throws JAXBException {
140        if (filename == null) {
141            throw new IllegalArgumentException("filename must not be null");
142        }
143
144        parseFile(new File(filename));
145    }
146
147    /**
148     * <p>
149     * Parses a log file written by the HTTPMonitor and creates a collection of event sequences.
150     * </p>
151     *
152     * @param file
153     *            file to be parsed
154     *
155     * @throws SAXException in the case, the file could not be parsed
156     */
157    public void parseFile(File file) throws JAXBException {
158        if (file == null) {
159            throw new IllegalArgumentException("file must not be null");
160        }
161       
162        try {
163            parseFile(new FileInputStream(file));
164        }
165        catch (FileNotFoundException e) {
166            Console.printerr("Error parsing file + " + file.getName());
167            Console.logException(e);
168            return;
169        }
170    }
171   
172    /**
173     * <p>
174     * Parses a log file written by the HTTPMonitor and creates a collection of event sequences.
175     * </p>
176     *
177     * @param stream
178     *            file to be parsed
179     *
180     * @throws SAXException in the case, the file could not be parsed
181     */
182    public void parseFile(InputStream stream) throws JAXBException {
183        if (stream == null) {
184            throw new IllegalArgumentException("stream must not be null");
185        }
186       
187        JAXBContext jc = JAXBContext.newInstance(Session.class.getPackage().getName());
188       
189        Unmarshaller unmarshaller = jc.createUnmarshaller();
190        StreamSource source = new StreamSource(stream);
191       
192        @SuppressWarnings("unchecked")
193        JAXBElement<Session> sessionObj = (JAXBElement<Session>) unmarshaller.unmarshal(source);
194       
195        Session session = sessionObj.getValue();
196
197        long orderingId = 0;
198        if ((session.getHttpExchange() != null) && (session.getHttpExchange().size() > 0)) {
199            List<Event> sequence = new LinkedList<Event>();
200            for (HttpExchange exchange : session.getHttpExchange()) {
201               
202                // check, if the exchange is an old one and does not contain ordering ids yet.
203                // If not, then add them.
204                if (exchange.getRequest().getOrderingId() == null) {
205                    exchange.getRequest().setOrderingId(orderingId++);
206                }
207                else {
208                    orderingId = exchange.getRequest().getOrderingId();
209                }
210               
211                if (exchange.getResponse().getOrderingId() == null) {
212                    exchange.getResponse().setOrderingId(orderingId++);
213                }
214                else {
215                    orderingId = exchange.getResponse().getOrderingId();
216                }
217               
218                // now handle the exchange
219                sequence.add(new Event(createEvent(exchange),
220                                       new HTTPTarget(exchange.getReceiver())));
221            }
222            sequences.add(sequence);
223        }
224       
225    }
226
227    /**
228     * <p>
229     * instantiates the appropriate event type. If it encounters a SOAP exchange, a SOAP event type
230     * is instantiated. Otherwise a normal HTTP event type is created.
231     * </p>
232     *
233     * @param exchange the exchange for which an event type is to be created
234     *
235     * @return as described
236     */
237    private IEventType createEvent(HttpExchange exchange) {
238        Content requestContent =
239            exchange.getRequest() != null ? exchange.getRequest().getContent() : null;
240       
241        SOAPMessage soapRequest = getSOAPMessage(requestContent);
242       
243        Content responseContent =
244            exchange.getResponse() != null ? exchange.getResponse().getContent() : null;
245           
246        SOAPMessage soapResponse = getSOAPMessage(responseContent);
247       
248        if (soapRequest != null) {
249            return new SOAPEventType(exchange, soapRequest, soapResponse, urlNameMap);
250        }
251        else {
252            return new HTTPEventType(exchange);
253        }
254    }
255
256    /**
257     * <p>
258     * convenience method to convert the content of an HTTP request or response into a SOAP message
259     * </p>
260     *
261     * @param content the content to be converted into a SOAP message
262     *
263     * @return the SOAP message contained in the content or null if either the content is null or
264     *         the content does not contain a SOAP message
265     */
266    private SOAPMessage getSOAPMessage(Content content) {
267        if ((content != null) && (content.getData() != null)) {
268            try {
269                if (soapMessageFactory == null) {
270                    soapMessageFactory = MessageFactory.newInstance();
271                }
272           
273                String encoding = content.getEncoding();
274                if (encoding == null) {
275                    encoding = "UTF-8";
276                }
277               
278                InputStream in = new ByteArrayInputStream(content.getData().getBytes(encoding));
279                SOAPMessage message = soapMessageFactory.createMessage(null, in);
280               
281                // try to access something to see, if everything worked fine.
282                message.getSOAPHeader();
283                message.getSOAPBody();
284               
285                return message;
286            }
287            catch (Exception e) {
288                if (content.getData().toLowerCase().indexOf("envelope") > 0) {
289                    Console.traceln(Level.WARNING, "HTTP message seems to be a SOAP message but " +
290                                    "it could not be parsed as such: " + e);
291                    //Console.logException(e);
292                }
293            }
294        }
295       
296        return null;
297    }
298
299    /**
300     * <p>
301     * returns the sequences parsed by this parser
302     * </p>
303     *
304     * @return as described
305     */
306    public Collection<List<Event>> getSequences() {
307        return sequences;
308    }
309}
Note: See TracBrowser for help on using the repository browser.