1/*
2 * Copyright (C) 2010 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package benchmarks;
18
19import com.google.caliper.Param;
20import com.google.caliper.Runner;
21import com.google.caliper.SimpleBenchmark;
22import java.io.ByteArrayInputStream;
23import java.io.ByteArrayOutputStream;
24import java.io.FileInputStream;
25import java.io.IOException;
26import java.lang.reflect.Constructor;
27import java.util.Arrays;
28import java.util.List;
29import javax.xml.parsers.DocumentBuilder;
30import javax.xml.parsers.DocumentBuilderFactory;
31import javax.xml.parsers.SAXParser;
32import javax.xml.parsers.SAXParserFactory;
33import org.w3c.dom.Document;
34import org.w3c.dom.Node;
35import org.xml.sax.Attributes;
36import org.xml.sax.SAXException;
37import org.xml.sax.helpers.DefaultHandler;
38import org.xmlpull.v1.XmlPullParser;
39
40public class XmlParseBenchmark extends SimpleBenchmark {
41
42    @Param String xmlFile;
43    ByteArrayInputStream inputStream;
44
45    static List<String> xmlFileValues = Arrays.asList(
46            "/etc/apns-conf.xml",
47            "/etc/media_profiles.xml",
48            "/etc/permissions/features.xml"
49    );
50
51    private SAXParser saxParser;
52    private DocumentBuilder documentBuilder;
53    private Constructor<? extends XmlPullParser> kxmlConstructor;
54    private Constructor<? extends XmlPullParser> expatConstructor;
55
56    @SuppressWarnings("unchecked")
57    @Override protected void setUp() throws Exception {
58        byte[] xmlBytes = getXmlBytes();
59        inputStream = new ByteArrayInputStream(xmlBytes);
60        inputStream.mark(xmlBytes.length);
61
62        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
63        saxParser = saxParserFactory.newSAXParser();
64
65        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
66        documentBuilder = builderFactory.newDocumentBuilder();
67
68        kxmlConstructor = (Constructor) Class.forName("org.kxml2.io.KXmlParser").getConstructor();
69        expatConstructor = (Constructor) Class.forName("org.apache.harmony.xml.ExpatPullParser")
70                .getConstructor();
71    }
72
73    private byte[] getXmlBytes() throws IOException {
74        FileInputStream fileIn = new FileInputStream(xmlFile);
75        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
76        int count;
77        byte[] buffer = new byte[1024];
78        while ((count = fileIn.read(buffer)) != -1) {
79            bytesOut.write(buffer, 0, count);
80        }
81        fileIn.close();
82        return bytesOut.toByteArray();
83    }
84
85    public int timeSax(int reps) throws IOException, SAXException {
86        int elementCount = 0;
87        for (int i = 0; i < reps; i++) {
88            inputStream.reset();
89            ElementCounterSaxHandler elementCounterSaxHandler = new ElementCounterSaxHandler();
90            saxParser.parse(inputStream, elementCounterSaxHandler);
91            elementCount += elementCounterSaxHandler.elementCount;
92        }
93        return elementCount;
94    }
95
96    private static class ElementCounterSaxHandler extends DefaultHandler {
97        int elementCount = 0;
98        @Override public void startElement(String uri, String localName,
99                String qName, Attributes attributes) {
100            elementCount++;
101        }
102    }
103
104    public int timeDom(int reps) throws IOException, SAXException {
105        int elementCount = 0;
106        for (int i = 0; i < reps; i++) {
107            inputStream.reset();
108            Document document = documentBuilder.parse(inputStream);
109            elementCount += countDomElements(document.getDocumentElement());
110        }
111        return elementCount;
112    }
113
114    private int countDomElements(Node node) {
115        int result = 0;
116        for (; node != null; node = node.getNextSibling()) {
117            if (node.getNodeType() == Node.ELEMENT_NODE) {
118                result++;
119            }
120            result += countDomElements(node.getFirstChild());
121        }
122        return result;
123    }
124
125    public int timeExpat(int reps) throws Exception {
126        return testXmlPull(expatConstructor, reps);
127    }
128
129    public int timeKxml(int reps) throws Exception {
130        return testXmlPull(kxmlConstructor, reps);
131    }
132
133    private int testXmlPull(Constructor<? extends XmlPullParser> constructor, int reps)
134            throws Exception {
135        int elementCount = 0;
136        for (int i = 0; i < reps; i++) {
137            inputStream.reset();
138            XmlPullParser xmlPullParser = constructor.newInstance();
139            xmlPullParser.setInput(inputStream, "UTF-8");
140            int type;
141            while ((type = xmlPullParser.next()) != XmlPullParser.END_DOCUMENT) {
142                if (type == XmlPullParser.START_TAG) {
143                    elementCount++;
144                }
145            }
146        }
147        return elementCount;
148    }
149
150    public static void main(String[] args) {
151        Runner.main(XmlParseBenchmark.class, args);
152    }
153}
154