net.yacy.cora.federate.solr.responsewriter.EnhancedXMLResponseWriter.java Source code

Java tutorial

Introduction

Here is the source code for net.yacy.cora.federate.solr.responsewriter.EnhancedXMLResponseWriter.java

Source

/**
 *  FastXMLResponseWriter
 *  Copyright 2012 by Michael Peter Christen
 *  First released 06.08.2012 at http://yacy.net
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program in the file lgpl21.txt
 *  If not, see <http://www.gnu.org/licenses/>.
 */

package net.yacy.cora.federate.solr.responsewriter;

import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.yacy.cora.federate.solr.SolrType;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexableField;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.SolrInputField;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.XML;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.QueryResponseWriter;
import org.apache.solr.response.ResultContext;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.schema.TextField;
import org.apache.solr.schema.TrieDateField;
import org.apache.solr.search.DocIterator;
import org.apache.solr.search.DocList;
import org.apache.solr.search.SolrIndexSearcher;

public class EnhancedXMLResponseWriter implements QueryResponseWriter {

    private static final char lb = '\n';
    private static final char[] XML_START = "<?xml version = \"1.0\" encoding = \"UTF-8\"?>\n<response>\n"
            .toCharArray();
    private static final char[] XML_STOP = "\n</response>\n".toCharArray();
    private static final Set<String> DEFAULT_FIELD_LIST = null;

    public EnhancedXMLResponseWriter() {
        super();
    }

    @Override
    public String getContentType(final SolrQueryRequest request, final SolrQueryResponse response) {
        return CONTENT_TYPE_XML_UTF8;
    }

    @Override
    public void init(@SuppressWarnings("rawtypes") NamedList n) {
    }

    @Override
    public void write(final Writer writer, final SolrQueryRequest request, final SolrQueryResponse rsp)
            throws IOException {
        writer.write(XML_START);
        NamedList<?> values = rsp.getValues();

        assert values.get("responseHeader") != null;
        assert values.get("response") != null;

        SimpleOrderedMap<Object> responseHeader = (SimpleOrderedMap<Object>) rsp.getResponseHeader();
        DocList response = ((ResultContext) values.get("response")).docs;
        @SuppressWarnings("unchecked")
        SimpleOrderedMap<Object> highlighting = (SimpleOrderedMap<Object>) values.get("highlighting");
        writeProps(writer, "responseHeader", responseHeader); // this.writeVal("responseHeader", responseHeader);
        writeDocs(writer, request, response); // this.writeVal("response", response);
        writeProps(writer, "highlighting", highlighting);
        writer.write(XML_STOP);
    }

    public static void write(final Writer writer, final SolrQueryRequest request, final SolrDocumentList sdl)
            throws IOException {
        writer.write(XML_START);
        writeDocs(writer, request, sdl);
        writer.write(XML_STOP);
    }

    private static void writeProps(final Writer writer, final String name, final NamedList<?> val)
            throws IOException {
        if (val == null)
            return;
        int sz = val.size();
        if (sz <= 0)
            startTagClose(writer, "lst", name);
        else
            startTagOpen(writer, "lst", name);
        Object v;
        for (int i = 0; i < sz; i++) {
            String n = val.getName(i);
            v = val.getVal(i);
            if (v instanceof Integer)
                writeTag(writer, "int", n, ((Integer) v).toString(), false);
            else if (v instanceof String)
                writeTag(writer, "str", n, (String) v, true);
            else if (v instanceof String[])
                writeTag(writer, "str", n, (String[]) v, true);
            else if (v instanceof NamedList)
                writeProps(writer, n, (NamedList<?>) v);
        }
        if (sz > 0) {
            writer.write("</lst>");
            writer.write(lb);
        }
    }

    private static final void writeDocs(final Writer writer, final SolrQueryRequest request, final DocList response)
            throws IOException {
        boolean includeScore = false;
        final int sz = response.size();
        writer.write("<result");
        writeAttr(writer, "name", "response");
        writeAttr(writer, "numFound", Long.toString(response.matches()));
        writeAttr(writer, "start", Long.toString(response.offset()));
        if (includeScore) {
            writeAttr(writer, "maxScore", Float.toString(response.maxScore()));
        }
        if (sz == 0) {
            writer.write("/>");
            return;
        }
        writer.write('>');
        writer.write(lb);
        SolrIndexSearcher searcher = request.getSearcher();
        DocIterator iterator = response.iterator();
        includeScore = includeScore && response.hasScores();
        IndexSchema schema = request.getSchema();
        for (int i = 0; i < sz; i++) {
            int id = iterator.nextDoc();
            Document doc = searcher.doc(id, DEFAULT_FIELD_LIST);
            writeDoc(writer, schema, null, doc.getFields(), (includeScore ? iterator.score() : 0.0f), includeScore);
        }
        writer.write("</result>");
        writer.write(lb);
    }

    private static final void writeDocs(final Writer writer,
            @SuppressWarnings("unused") final SolrQueryRequest request, final SolrDocumentList docs)
            throws IOException {
        boolean includeScore = false;
        final int sz = docs.size();
        writer.write("<result");
        writeAttr(writer, "name", "response");
        writeAttr(writer, "numFound", Long.toString(docs.getNumFound()));
        writeAttr(writer, "start", Long.toString(docs.getStart()));
        if (includeScore) {
            writeAttr(writer, "maxScore", Float.toString(docs.getMaxScore()));
        }
        if (sz == 0) {
            writer.write("/>");
            return;
        }
        writer.write('>');
        writer.write(lb);
        Iterator<SolrDocument> iterator = docs.iterator();
        for (int i = 0; i < sz; i++) {
            SolrDocument doc = iterator.next();
            writeDoc(writer, doc);
        }
        writer.write("</result>");
        writer.write(lb);
    }

    private static final void writeDoc(final Writer writer, final IndexSchema schema, final String name,
            final List<IndexableField> fields, final float score, final boolean includeScore) throws IOException {
        startTagOpen(writer, "doc", name);

        if (includeScore) {
            writeTag(writer, "float", "score", Float.toString(score), false);
        }

        int sz = fields.size();
        int fidx1 = 0, fidx2 = 0;
        while (fidx1 < sz) {
            IndexableField value = fields.get(fidx1);
            String fieldName = value.name();
            fidx2 = fidx1 + 1;
            while (fidx2 < sz && fieldName.equals(fields.get(fidx2).name())) {
                fidx2++;
            }
            SchemaField sf = schema == null ? null : schema.getFieldOrNull(fieldName);
            if (sf == null) {
                sf = new SchemaField(fieldName, new TextField());
            }
            FieldType type = sf.getType();
            if (fidx1 + 1 == fidx2) {
                if (sf.multiValued()) {
                    startTagOpen(writer, "arr", fieldName);
                    writer.write(lb);
                    String sv = value.stringValue();
                    writeField(writer, type.getTypeName(), null, sv); //sf.write(this, null, f1);
                    writer.write("</arr>");
                } else {
                    writeField(writer, type.getTypeName(), value.name(), value.stringValue()); //sf.write(this, f1.name(), f1);
                }
            } else {
                startTagOpen(writer, "arr", fieldName);
                writer.write(lb);
                for (int i = fidx1; i < fidx2; i++) {
                    String sv = fields.get(i).stringValue();
                    writeField(writer, type.getTypeName(), null, sv); //sf.write(this, null, (Fieldable)this.tlst.get(i));
                }
                writer.write("</arr>");
                writer.write(lb);
            }
            fidx1 = fidx2;
        }
        writer.write("</doc>");
        writer.write(lb);
    }

    public static final void writeDoc(final Writer writer, final SolrInputDocument sid) throws IOException {
        startTagOpen(writer, "doc", null);
        for (String key : sid.getFieldNames()) {
            SolrInputField sif = sid.getField(key);
            Object value = sif.getValue();
            if (value == null) {
            } else if (value instanceof Collection<?>) {
                startTagOpen(writer, "arr", key);
                writer.write(lb);
                for (Object o : (Collection<?>) value) {
                    writeField(writer, null, o);
                }
                writer.write("</arr>");
                writer.write(lb);
            } else {
                writeField(writer, key, value);
            }
        }
        writer.write("</doc>");
        writer.write(lb);
    }

    public static final void writeDoc(final Writer writer, final SolrDocument doc) throws IOException {
        startTagOpen(writer, "doc", null);
        final Map<String, Object> fields = doc.getFieldValueMap();
        for (String key : fields.keySet()) {
            if (key == null)
                continue;
            Object value = doc.get(key);
            if (value == null) {
            } else if (value instanceof Collection<?>) {
                startTagOpen(writer, "arr", key);
                writer.write(lb);
                for (Object o : ((Collection<?>) value)) {
                    writeField(writer, null, o);
                }
                writer.write("</arr>");
                writer.write(lb);
            } else {
                writeField(writer, key, value);
            }
        }
        writer.write("</doc>");
        writer.write(lb);
    }

    @SuppressWarnings({ "static-access", "deprecation" })
    private static void writeField(final Writer writer, final String typeName, final String name,
            final String value) throws IOException {
        if (typeName.equals(SolrType.text_general.printName()) || typeName.equals(SolrType.string.printName())
                || typeName.equals(SolrType.text_en_splitting_tight.printName())) {
            writeTag(writer, "str", name, value, true);
        } else if (typeName.equals(SolrType.bool.printName())) {
            writeTag(writer, "bool", name, "F".equals(value) ? "false" : "true", true);
        } else if (typeName.equals(SolrType.num_integer.printName())) {
            writeTag(writer, "int", name, value, true);
        } else if (typeName.equals(SolrType.num_long.printName())) {
            writeTag(writer, "long", name, value, true);
        } else if (typeName.equals(SolrType.date.printName())) {
            writeTag(writer, "date", name, TrieDateField.formatExternal(new Date(Long.parseLong(value))), true);
        } else if (typeName.equals(SolrType.num_float.printName())) {
            writeTag(writer, "float", name, value, true);
        } else if (typeName.equals(SolrType.num_double.printName())) {
            writeTag(writer, "double", name, value, true);
        }
    }

    @SuppressWarnings({ "static-access", "deprecation" })
    private static void writeField(final Writer writer, final String name, final Object value) throws IOException {
        if (value instanceof String) {
            writeTag(writer, "str", name, (String) value, true);
        } else if (value instanceof Boolean) {
            writeTag(writer, "bool", name, ((Boolean) value).toString(), true);
        } else if (value instanceof Integer) {
            writeTag(writer, "int", name, ((Integer) value).toString(), true);
        } else if (value instanceof Long) {
            writeTag(writer, "long", name, ((Long) value).toString(), true);
        } else if (value instanceof Date) {
            writeTag(writer, "date", name, TrieDateField.formatExternal((Date) value), true);
        } else if (value instanceof Float) {
            writeTag(writer, "float", name, ((Float) value).toString(), true);
        } else if (value instanceof Double) {
            writeTag(writer, "double", name, ((Double) value).toString(), true);
        }
    }

    private static void writeTag(final Writer writer, final String tag, final String nameAttr, final String val,
            final boolean escape) throws IOException {
        int contentLen = val.length();
        if (contentLen == 0) {
            startTagClose(writer, tag, nameAttr);
            return;
        }
        startTagOpen(writer, tag, nameAttr);
        if (escape) {
            XML.escapeCharData(val, writer);
        } else {
            writer.write(val, 0, contentLen);
        }
        writer.write("</");
        writer.write(tag);
        writer.write('>');
        writer.write(lb);
    }

    private static void writeTag(final Writer writer, final String tag, final String nameAttr, final String[] vals,
            final boolean escape) throws IOException {
        startTagOpen(writer, "arr", nameAttr);
        for (String val : vals) {
            writeTag(writer, tag, null, val, escape);
        }
        writer.write("</arr>");
        writer.write(lb);
    }

    private static void startTagOpen(final Writer writer, final String tag, final String nameAttr)
            throws IOException {
        writer.write('<');
        writer.write(tag);
        if (nameAttr != null)
            writeAttr(writer, "name", nameAttr);
        writer.write('>'); //writer.write(lb);
    }

    private static void startTagClose(final Writer writer, final String tag, final String nameAttr)
            throws IOException {
        writer.write('<');
        writer.write(tag);
        if (nameAttr != null)
            writeAttr(writer, "name", nameAttr);
        writer.write("/>");
        writer.write(lb);
    }

    private static void writeAttr(final Writer writer, final String nameAttr, final String val) throws IOException {
        writer.write(' ');
        writer.write(nameAttr);
        writer.write("=\"");
        XML.escapeAttributeValue(val, writer);
        writer.write('"');
    }

}