/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package benchmarks.regression;
import com.google.caliper.Param;
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParserFactory;
import org.json.JSONArray;
import org.json.JSONObject;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import org.xmlpull.v1.XmlPullParser;
/**
* Measure throughput of various parsers.
*
* <p>This benchmark requires that ParseBenchmarkData.zip is on the classpath.
* That file contains Twitter feed data, which is representative of what
* applications will be parsing.
*/
public final class ParseBenchmark extends SimpleBenchmark {
@Param Document document;
@Param Api api;
private enum Document {
TWEETS,
READER_SHORT,
READER_LONG
}
private enum Api {
ANDROID_STREAM("json") {
@Override Parser newParser() {
return new AndroidStreamParser();
}
},
ORG_JSON("json") {
@Override Parser newParser() {
return new OrgJsonParser();
}
},
XML_PULL("xml") {
@Override Parser newParser() {
return new GeneralXmlPullParser();
}
},
XML_DOM("xml") {
@Override Parser newParser() {
return new XmlDomParser();
}
},
XML_SAX("xml") {
@Override Parser newParser() {
return new XmlSaxParser();
}
};
final String extension;
private Api(String extension) {
this.extension = extension;
}
abstract Parser newParser();
}
private String text;
private Parser parser;
@Override protected void setUp() throws Exception {
text = resourceToString("/" + document.name() + "." + api.extension);
parser = api.newParser();
}
public void timeParse(int reps) throws Exception {
for (int i = 0; i < reps; i++) {
parser.parse(text);
}
}
public static void main(String... args) throws Exception {
Runner.main(ParseBenchmark.class, args);
}
private static String resourceToString(String path) throws Exception {
InputStream in = ParseBenchmark.class.getResourceAsStream(path);
if (in == null) {
throw new IllegalArgumentException("No such file: " + path);
}
Reader reader = new InputStreamReader(in, "UTF-8");
char[] buffer = new char[8192];
StringWriter writer = new StringWriter();
int count;
while ((count = reader.read(buffer)) != -1) {
writer.write(buffer, 0, count);
}
reader.close();
return writer.toString();
}
interface Parser {
void parse(String data) throws Exception;
}
private static class AndroidStreamParser implements Parser {
@Override public void parse(String data) throws Exception {
android.util.JsonReader jsonReader
= new android.util.JsonReader(new StringReader(data));
readToken(jsonReader);
jsonReader.close();
}
public void readObject(android.util.JsonReader reader) throws IOException {
reader.beginObject();
while (reader.hasNext()) {
reader.nextName();
readToken(reader);
}
reader.endObject();
}
public void readArray(android.util.JsonReader reader) throws IOException {
reader.beginArray();
while (reader.hasNext()) {
readToken(reader);
}
reader.endArray();
}
private void readToken(android.util.JsonReader reader) throws IOException {
switch (reader.peek()) {
case BEGIN_ARRAY:
readArray(reader);
break;
case BEGIN_OBJECT:
readObject(reader);
break;
case BOOLEAN:
reader.nextBoolean();
break;
case NULL:
reader.nextNull();
break;
case NUMBER:
reader.nextLong();
break;
case STRING:
reader.nextString();
break;
default:
throw new IllegalArgumentException("Unexpected token" + reader.peek());
}
}
}
private static class OrgJsonParser implements Parser {
@Override public void parse(String data) throws Exception {
if (data.startsWith("[")) {
new JSONArray(data);
} else if (data.startsWith("{")) {
new JSONObject(data);
} else {
throw new IllegalArgumentException();
}
}
}
private static class GeneralXmlPullParser implements Parser {
@Override public void parse(String data) throws Exception {
XmlPullParser xmlParser = android.util.Xml.newPullParser();
xmlParser.setInput(new StringReader(data));
xmlParser.nextTag();
while (xmlParser.next() != XmlPullParser.END_DOCUMENT) {
xmlParser.getName();
xmlParser.getText();
}
}
}
private static class XmlDomParser implements Parser {
@Override public void parse(String data) throws Exception {
DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new InputSource(new StringReader(data)));
}
}
private static class XmlSaxParser implements Parser {
@Override public void parse(String data) throws Exception {
SAXParserFactory.newInstance().newSAXParser().parse(
new InputSource(new StringReader(data)), new DefaultHandler());
}
}
}