001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.joran.event.stax;
015
016import java.io.InputStream;
017import java.util.ArrayList;
018import java.util.List;
019
020import javax.xml.stream.XMLEventReader;
021import javax.xml.stream.XMLInputFactory;
022import javax.xml.stream.XMLStreamException;
023import javax.xml.stream.events.Characters;
024import javax.xml.stream.events.EndElement;
025import javax.xml.stream.events.StartElement;
026import javax.xml.stream.events.XMLEvent;
027
028import ch.qos.logback.core.Context;
029import ch.qos.logback.core.joran.spi.ElementPath;
030import ch.qos.logback.core.joran.spi.JoranException;
031import ch.qos.logback.core.spi.ContextAwareBase;
032
033public class StaxEventRecorder extends ContextAwareBase {
034
035    List<StaxEvent> eventList = new ArrayList<StaxEvent>();
036    ElementPath globalElementPath = new ElementPath();
037
038    public StaxEventRecorder(Context context) {
039        setContext(context);
040    }
041
042    public void recordEvents(InputStream inputStream) throws JoranException {
043        try {
044            XMLEventReader xmlEventReader = XMLInputFactory.newInstance().createXMLEventReader(inputStream);
045            read(xmlEventReader);
046        } catch (XMLStreamException e) {
047            throw new JoranException("Problem parsing XML document. See previously reported errors.", e);
048        }
049    }
050
051    public List<StaxEvent> getEventList() {
052        return eventList;
053    }
054
055    private void read(XMLEventReader xmlEventReader) throws XMLStreamException {
056        while (xmlEventReader.hasNext()) {
057            XMLEvent xmlEvent = xmlEventReader.nextEvent();
058            switch (xmlEvent.getEventType()) {
059            case XMLEvent.START_ELEMENT:
060                addStartElement(xmlEvent);
061                break;
062            case XMLEvent.CHARACTERS:
063                addCharacters(xmlEvent);
064                break;
065            case XMLEvent.END_ELEMENT:
066                addEndEvent(xmlEvent);
067                break;
068            default:
069                break;
070            }
071        }
072    }
073
074    private void addStartElement(XMLEvent xmlEvent) {
075        StartElement se = xmlEvent.asStartElement();
076        String tagName = se.getName().getLocalPart();
077        this.globalElementPath.push(tagName);
078        ElementPath current = globalElementPath.duplicate();
079        StartEvent startEvent = new StartEvent(current, tagName, se.getAttributes(), se.getLocation());
080        eventList.add(startEvent);
081    }
082
083    private void addCharacters(XMLEvent xmlEvent) {
084        Characters characters = xmlEvent.asCharacters();
085        StaxEvent lastEvent = getLastEvent();
086
087        if (lastEvent instanceof BodyEvent) {
088            BodyEvent be = (BodyEvent) lastEvent;
089            be.append(characters.getData());
090        } else {
091            // ignore space only text if the previous event is not a BodyEvent
092            if (!characters.isWhiteSpace()) {
093                BodyEvent bodyEvent = new BodyEvent(characters.getData(), xmlEvent.getLocation());
094                eventList.add(bodyEvent);
095            }
096        }
097    }
098
099    private void addEndEvent(XMLEvent xmlEvent) {
100        EndElement ee = xmlEvent.asEndElement();
101        String tagName = ee.getName().getLocalPart();
102        EndEvent endEvent = new EndEvent(tagName, ee.getLocation());
103        eventList.add(endEvent);
104        this.globalElementPath.pop();
105    }
106
107    StaxEvent getLastEvent() {
108        if (eventList.isEmpty()) {
109            return null;
110        }
111        int size = eventList.size();
112        if (size == 0)
113            return null;
114        return eventList.get(size - 1);
115    }
116
117}