blob: 983a6925a9a44746ce3a05355f72a5cfc4d7c30e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.solr.common.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.FastStreamingDocsCallback;
import org.apache.solr.client.solrj.impl.BinaryRequestWriter;
import org.apache.solr.client.solrj.impl.StreamingBinaryResponseParser;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.util.FastJavaBinDecoder.Tag;
public class TestFastJavabinDecoder extends SolrTestCaseJ4 {
public void testTagRead() throws Exception {
BinaryRequestWriter.BAOS baos = new BinaryRequestWriter.BAOS();
FastOutputStream faos = FastOutputStream.wrap(baos);
try (JavaBinCodec codec = new JavaBinCodec(faos, null)) {
codec.writeVal(10);
codec.writeVal(100);
codec.writeVal("Hello!");
}
faos.flushBuffer();
faos.close();
FastInputStream fis = new FastInputStream(null, baos.getbuf(), 0, baos.size());
try (FastJavaBinDecoder.StreamCodec scodec = new FastJavaBinDecoder.StreamCodec(fis)) {
scodec.start();
Tag tag = scodec.getTag();
assertEquals(Tag._SINT, tag);
assertEquals(10, scodec.readSmallInt(scodec.dis));
tag = scodec.getTag();
assertEquals(Tag._SINT, tag);
assertEquals(100, scodec.readSmallInt(scodec.dis));
tag = scodec.getTag();
assertEquals(Tag._STR, tag);
assertEquals("Hello!", scodec.readStr(fis));
}
}
public void testSimple() throws IOException {
String sampleObj = "{k : v , " +
"mapk : {k1: v1, k2 : [v2_1 , v2_2 ]}," +
"listk : [ 1, 2, 3 ]," +
"maps : [ {id: kov1}, {id : kov2} ,{id:kov3 , longv : 234} ]," +
"}";
@SuppressWarnings({"rawtypes"})
Map m = (Map) Utils.fromJSONString(sampleObj);
BinaryRequestWriter.BAOS baos = new BinaryRequestWriter.BAOS();
try (JavaBinCodec jbc = new JavaBinCodec()) {
jbc.marshal(m, baos);
}
@SuppressWarnings({"rawtypes"})
Map m2;
try (JavaBinCodec jbc = new JavaBinCodec()) {
m2 = (Map) jbc.unmarshal(new FastInputStream(null, baos.getbuf(), 0, baos.size()));
}
@SuppressWarnings({"rawtypes"})
LinkedHashMap fastMap = (LinkedHashMap) new FastJavaBinDecoder()
.withInputStream(new FastInputStream(null, baos.getbuf(), 0, baos.size()))
.decode(FastJavaBinDecoder.getEntryListener());
assertEquals(Utils.writeJson(m2, new StringWriter(), true).toString(),
Utils.writeJson(fastMap, new StringWriter(), true).toString());
@SuppressWarnings({"unchecked"})
Object newMap = new FastJavaBinDecoder()
.withInputStream(new FastInputStream(null, baos.getbuf(), 0, baos.size()))
.decode(e -> {
e.listenContainer(new LinkedHashMap<>(), e_ -> {
Map rootMap = (Map) e_.ctx();
if (e_.type() == DataEntry.Type.ENTRY_ITER) {
e_.listenContainer(rootMap.computeIfAbsent(e_.name(), o -> new ArrayList<Object>()),
FastJavaBinDecoder.getEntryListener());
} else if (e_.type() == DataEntry.Type.KEYVAL_ITER) {
e_.listenContainer(rootMap.computeIfAbsent(e_.name(), o -> new LinkedHashMap<Object,Object>()), e1 -> {
Map<CharSequence,String> m1 = (Map<CharSequence,String>) e1.ctx();
if ("k1".equals(e1.name())) {
m1.put(e1.name(), e1.val().toString());
}
//eat up k2
});
} else if (e_.type() == DataEntry.Type.STR) {
rootMap.put(e_.name(), e_.val().toString());
}
});
});
((Map) m2.get("mapk")).remove("k2");
assertEquals(Utils.writeJson(m2, new StringWriter(), true).toString(),
Utils.writeJson(newMap, new StringWriter(), true).toString());
}
public void testFastJavabinStreamingDecoder() throws IOException {
BinaryRequestWriter.BAOS baos = new BinaryRequestWriter.BAOS();
try (InputStream is = getClass().getResourceAsStream("/solrj/javabin_sample.bin")) {
IOUtils.copy(is, baos);
}
SolrDocumentList list;
try (JavaBinCodec jbc = new JavaBinCodec()) {
@SuppressWarnings({"rawtypes"})
SimpleOrderedMap o = (SimpleOrderedMap) jbc.unmarshal(baos.toByteArray());
list = (SolrDocumentList) o.get("response");
}
System.out.println(" " + list.getNumFound() + " , " + list.getStart() + " , " + list.getMaxScore());
class Pojo {
long _idx;
CharSequence id;
boolean inStock;
float price;
@SuppressWarnings({"rawtypes"})
List<NamedList> children;
}
StreamingBinaryResponseParser parser = new StreamingBinaryResponseParser(new FastStreamingDocsCallback() {
@Override
public Object initDocList(Long numFound, Long start, Float maxScore) {
assertEquals((Long) list.getNumFound(), numFound);
assertEquals((Long) list.getStart(), start);
assertEquals(list.getMaxScore(), maxScore);
return new int[1];
}
@Override
public Object startDoc(Object docListObj) {
Pojo pojo = new Pojo();
pojo._idx = ((int[]) docListObj)[0]++;
return pojo;
}
@Override
public void field(DataEntry field, Object docObj) {
Pojo pojo = (Pojo) docObj;
if ("id".equals(field.name())) {
pojo.id = ((Utf8CharSequence) field.val()).clone();
} else if (field.type() == DataEntry.Type.BOOL && "inStock".equals(field.name())) {
pojo.inStock = field.boolVal();
} else if (field.type() == DataEntry.Type.FLOAT && "price".equals(field.name())) {
pojo.price = field.floatVal();
}
}
@Override
public void endDoc(Object docObj) {
Pojo pojo = (Pojo) docObj;
SolrDocument doc = list.get((int) pojo._idx);
assertEquals(doc.get("id"), pojo.id.toString());
if (doc.get("inStock") != null)
assertEquals(doc.get("inStock"), pojo.inStock);
if (doc.get("price") != null)
assertEquals((Float) doc.get("price"), pojo.price, 0.001);
}
});
parser.processResponse(new FastInputStream(null, baos.getbuf(), 0, baos.size()), null);
}
@SuppressWarnings({"unchecked"})
public void testParsingWithChildDocs() throws IOException {
SolrDocument d1 = TestJavaBinCodec.generateSolrDocumentWithChildDocs();
d1.setField("id", "101");
SolrDocument d2 = TestJavaBinCodec.generateSolrDocumentWithChildDocs();
d2.setField("id", "102");
d2.setField("longs", Arrays.asList(100l, 200l));
SolrDocumentList sdocs = new SolrDocumentList();
sdocs.setStart(0);
sdocs.setNumFound(2);
sdocs.add(d1);
sdocs.add(d2);
@SuppressWarnings({"rawtypes"})
SimpleOrderedMap orderedMap = new SimpleOrderedMap();
orderedMap.add("response", sdocs);
BinaryRequestWriter.BAOS baos = new BinaryRequestWriter.BAOS();
try (JavaBinCodec jbc = new JavaBinCodec()) {
jbc.marshal(orderedMap, baos);
}
boolean[] useListener = new boolean[1];
useListener[0] = true;
class Pojo {
CharSequence id;
CharSequence subject;
CharSequence cat;
long[] longs;
final List<Pojo> children = new ArrayList<>();
public void compare(SolrDocument d) {
assertEquals(id, d.getFieldValue("id"));
assertEquals(subject, d.getFieldValue("subject"));
assertEquals(cat, d.getFieldValue("cat"));
assertEquals(d.getChildDocumentCount(), children.size());
@SuppressWarnings({"unchecked"})
List<Long> l = (List<Long>) d.getFieldValue("longs");
if(l != null){
assertNotNull(longs);
for (int i = 0; i < l.size(); i++) {
Long v = l.get(i);
assertEquals(v.longValue(), longs[i]);
}
}
List<SolrDocument> childDocuments = d.getChildDocuments();
if (childDocuments == null) return;
for (int i = 0; i < childDocuments.size(); i++) {
children.get(i).compare(childDocuments.get(i));
}
}
}
List<Pojo> l = new ArrayList<>();
StreamingBinaryResponseParser binaryResponseParser = new StreamingBinaryResponseParser(new FastStreamingDocsCallback() {
@Override
public Object initDocList(Long numFound, Long start, Float maxScore) {
return l;
}
@Override
@SuppressWarnings({"unchecked"})
public Object startDoc(Object docListObj) {
Pojo pojo = new Pojo();
((List) docListObj).add(pojo);
return pojo;
}
@Override
public void field(DataEntry field, Object docObj) {
Pojo pojo = (Pojo) docObj;
if (field.name().equals("id")) {
pojo.id = field.strValue();
} else if (field.name().equals("subject")) {
pojo.subject = field.strValue();
} else if (field.name().equals("cat")) {
pojo.cat = field.strValue();
} else if (field.type() == DataEntry.Type.ENTRY_ITER && "longs".equals(field.name())) {
if(useListener[0]){
field.listenContainer(pojo.longs = new long[field.length()], READLONGS);
} else {
@SuppressWarnings({"unchecked"})
List<Long> longList = (List<Long>) field.val();
pojo.longs = new long[longList.size()];
for (int i = 0; i < longList.size(); i++) {
pojo.longs[i] = longList.get(i);
}
}
}
}
@Override
public Object startChildDoc(Object parentDocObj) {
Pojo parent = (Pojo) parentDocObj;
Pojo child = new Pojo();
parent.children.add(child);
return child;
}
});
binaryResponseParser.processResponse(new FastInputStream(null, baos.getbuf(), 0, baos.size()), null);
for (int i = 0; i < sdocs.size(); i++) {
l.get(i).compare(sdocs.get(i));
}
l.clear();
useListener[0] = false;
binaryResponseParser.processResponse(new FastInputStream(null, baos.getbuf(), 0, baos.size()), null);
for (int i = 0; i < sdocs.size(); i++) {
l.get(i).compare(sdocs.get(i));
}
}
static final DataEntry.EntryListener READLONGS = e -> {
if (e.type() != DataEntry.Type.LONG) return;
long[] array = (long[]) e.ctx();
array[(int) e.index()] = e.longVal();
};
}