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

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