SOLR-9127: Excel workbook (.xlsx) response writer. use 'wt=xlsx'

This commit is contained in:
Noble Paul 2016-09-06 13:22:18 +05:30
parent ecbb588f97
commit 1a61fb6858
5 changed files with 683 additions and 2 deletions

View File

@ -78,7 +78,9 @@ prefix, then you will now get an error as these options are incompatible with nu
New Features
----------------------
* SOLR-5725: facet.method=enum can bypass exact counts calculation with facet.exists=true, it just returns 1 for
terms which exists in result docset. (Alexey Kozhemiakin, Sebastian Koziel, Radoslaw Zielinski via Mikhail Khludnev)
terms which exists in result docset. (Alexey Kozhemiakin, Sebastian Koziel, Radoslaw Zielinski via Mikhail Khludnev)
* SOLR-9127: Excel workbook (.xlsx) response writer. use 'wt=xlsx' (Tony Moriarty, noble)
Bug Fixes
----------------------

View File

@ -0,0 +1,414 @@
/*
* 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.handler.extraction;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import org.apache.lucene.index.IndexableField;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.BasicResultContext;
import org.apache.solr.response.RawResponseWriter;
import org.apache.solr.response.ResultContext;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.response.TextResponseWriter;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.schema.StrField;
import org.apache.solr.search.DocList;
import org.apache.solr.search.ReturnFields;
public class XLSXResponseWriter extends RawResponseWriter {
@Override
public void write(OutputStream out, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
// throw away arraywriter just to satisfy super requirements; we're grabbing
// all writes before they go to it anyway
XLSXWriter w = new XLSXWriter(new CharArrayWriter(), req, rsp);
LinkedHashMap<String,String> reqNamesMap = new LinkedHashMap<>();
LinkedHashMap<String,Integer> reqWidthsMap = new LinkedHashMap<>();
Iterator<String> paramNamesIter = req.getParams().getParameterNamesIterator();
while (paramNamesIter.hasNext()) {
String nextParam = paramNamesIter.next();
if (nextParam.startsWith("colname.")) {
String field = nextParam.substring("colname.".length());
reqNamesMap.put(field, req.getParams().get(nextParam));
} else if (nextParam.startsWith("colwidth.")) {
String field = nextParam.substring("colwidth.".length());
reqWidthsMap.put(field, req.getParams().getInt(nextParam));
}
}
try {
w.writeResponse(out, reqNamesMap, reqWidthsMap);
} finally {
w.close();
}
}
@Override
public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
}
class XLSXWriter extends TextResponseWriter {
SolrQueryRequest req;
SolrQueryResponse rsp;
class SerialWriteWorkbook {
SXSSFWorkbook swb;
Sheet sh;
XSSFCellStyle headerStyle;
int rowIndex;
Row curRow;
int cellIndex;
SerialWriteWorkbook() {
this.swb = new SXSSFWorkbook(100);
this.sh = this.swb.createSheet();
this.rowIndex = 0;
this.headerStyle = (XSSFCellStyle)swb.createCellStyle();
this.headerStyle.setFillBackgroundColor(IndexedColors.BLACK.getIndex());
//solid fill
this.headerStyle.setFillPattern((short)1);
Font headerFont = swb.createFont();
headerFont.setFontHeightInPoints((short)14);
headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
headerFont.setColor(IndexedColors.WHITE.getIndex());
this.headerStyle.setFont(headerFont);
}
void addRow() {
curRow = sh.createRow(rowIndex++);
cellIndex = 0;
}
void setHeaderRow() {
curRow.setHeightInPoints((short)21);
}
//sets last created cell to have header style
void setHeaderCell() {
curRow.getCell(cellIndex - 1).setCellStyle(this.headerStyle);
}
//set the width of the most recently created column
void setColWidth(int charWidth) {
//width in poi is units of 1/256th of a character width for some reason
this.sh.setColumnWidth(cellIndex - 1, 256*charWidth);
}
void writeCell(String value) {
Cell cell = curRow.createCell(cellIndex++);
cell.setCellValue(value);
}
void flush(OutputStream out) {
try {
swb.write(out);
} catch (IOException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String stacktrace = sw.toString();
}finally {
swb.dispose();
}
}
}
private SerialWriteWorkbook wb = new SerialWriteWorkbook();
static class XLField {
String name;
SchemaField sf;
}
private Map<String,XLField> xlFields = new LinkedHashMap<String,XLField>();
public XLSXWriter(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp){
super(writer, req, rsp);
this.req = req;
this.rsp = rsp;
}
public void writeResponse(OutputStream out, LinkedHashMap<String, String> colNamesMap,
LinkedHashMap<String, Integer> colWidthsMap) throws IOException {
SolrParams params = req.getParams();
Collection<String> fields = returnFields.getRequestedFieldNames();
Object responseObj = rsp.getValues().get("response");
boolean returnOnlyStored = false;
if (fields==null||returnFields.hasPatternMatching()) {
if (responseObj instanceof SolrDocumentList) {
// get the list of fields from the SolrDocumentList
if(fields==null) {
fields = new LinkedHashSet<String>();
}
for (SolrDocument sdoc: (SolrDocumentList)responseObj) {
fields.addAll(sdoc.getFieldNames());
}
} else {
// get the list of fields from the index
Iterable<String> all = req.getSearcher().getFieldNames();
if (fields == null) {
fields = Sets.newHashSet(all);
} else {
Iterables.addAll(fields, all);
}
}
if (returnFields.wantsScore()) {
fields.add("score");
} else {
fields.remove("score");
}
returnOnlyStored = true;
}
for (String field : fields) {
if (!returnFields.wantsField(field)) {
continue;
}
if (field.equals("score")) {
XLField xlField = new XLField();
xlField.name = "score";
xlFields.put("score", xlField);
continue;
}
SchemaField sf = schema.getFieldOrNull(field);
if (sf == null) {
FieldType ft = new StrField();
sf = new SchemaField(field, ft);
}
// Return only stored fields, unless an explicit field list is specified
if (returnOnlyStored && sf != null && !sf.stored()) {
continue;
}
XLField xlField = new XLField();
xlField.name = field;
xlField.sf = sf;
xlFields.put(field, xlField);
}
wb.addRow();
//write header
for (XLField xlField : xlFields.values()) {
String printName = xlField.name;
int colWidth = 14;
String niceName = colNamesMap.get(xlField.name);
if (niceName != null) {
printName = niceName;
}
Integer niceWidth = colWidthsMap.get(xlField.name);
if (niceWidth != null) {
colWidth = niceWidth.intValue();
}
writeStr(xlField.name, printName, false);
wb.setColWidth(colWidth);
wb.setHeaderCell();
}
wb.setHeaderRow();
wb.addRow();
if (responseObj instanceof ResultContext) {
writeDocuments(null, (ResultContext)responseObj );
}
else if (responseObj instanceof DocList) {
ResultContext ctx = new BasicResultContext((DocList)responseObj, returnFields, null, null, req);
writeDocuments(null, ctx );
} else if (responseObj instanceof SolrDocumentList) {
writeSolrDocumentList(null, (SolrDocumentList)responseObj, returnFields );
}
wb.flush(out);
wb = null;
}
@Override
public void close() throws IOException {
super.close();
}
@Override
public void writeNamedList(String name, NamedList val) throws IOException {
}
@Override
public void writeStartDocumentList(String name,
long start, int size, long numFound, Float maxScore) throws IOException
{
// nothing
}
@Override
public void writeEndDocumentList() throws IOException
{
// nothing
}
//NOTE: a document cannot currently contain another document
List tmpList;
@Override
public void writeSolrDocument(String name, SolrDocument doc, ReturnFields returnFields, int idx ) throws IOException {
if (tmpList == null) {
tmpList = new ArrayList(1);
tmpList.add(null);
}
for (XLField xlField : xlFields.values()) {
Object val = doc.getFieldValue(xlField.name);
int nVals = val instanceof Collection ? ((Collection)val).size() : (val==null ? 0 : 1);
if (nVals == 0) {
writeNull(xlField.name);
continue;
}
if ((xlField.sf != null && xlField.sf.multiValued()) || nVals > 1) {
Collection values;
// normalize to a collection
if (val instanceof Collection) {
values = (Collection)val;
} else {
tmpList.set(0, val);
values = tmpList;
}
writeArray(xlField.name, values.iterator());
} else {
// normalize to first value
if (val instanceof Collection) {
Collection values = (Collection)val;
val = values.iterator().next();
}
writeVal(xlField.name, val);
}
}
wb.addRow();
}
@Override
public void writeStr(String name, String val, boolean needsEscaping) throws IOException {
wb.writeCell(val);
}
@Override
public void writeMap(String name, Map val, boolean excludeOuter, boolean isFirstVal) throws IOException {
}
@Override
public void writeArray(String name, Iterator val) throws IOException {
StringBuffer output = new StringBuffer();
while (val.hasNext()) {
Object v = val.next();
if (v instanceof IndexableField) {
IndexableField f = (IndexableField)v;
if (v instanceof Date) {
output.append(((Date) val).toInstant().toString() + "; ");
} else {
output.append(f.stringValue() + "; ");
}
} else {
output.append(v.toString() + "; ");
}
}
if (output.length() > 0) {
output.deleteCharAt(output.length()-1);
output.deleteCharAt(output.length()-1);
}
writeStr(name, output.toString(), false);
}
@Override
public void writeNull(String name) throws IOException {
wb.writeCell("");
}
@Override
public void writeInt(String name, String val) throws IOException {
wb.writeCell(val);
}
@Override
public void writeLong(String name, String val) throws IOException {
wb.writeCell(val);
}
@Override
public void writeBool(String name, String val) throws IOException {
wb.writeCell(val);
}
@Override
public void writeFloat(String name, String val) throws IOException {
wb.writeCell(val);
}
@Override
public void writeDouble(String name, String val) throws IOException {
wb.writeCell(val);
}
@Override
public void writeDate(String name, Date val) throws IOException {
writeDate(name, val.toInstant().toString());
}
@Override
public void writeDate(String name, String val) throws IOException {
wb.writeCell(val);
}
}

View File

@ -415,6 +415,7 @@
-->
<dynamicField name="*_i" type="int" indexed="true" stored="true"/>
<dynamicField name="*_s" type="string" indexed="true" stored="true"/>
<dynamicField name="*_ss" type="string" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="*_s1" type="string" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="*_l" type="long" indexed="true" stored="true"/>
<dynamicField name="*_t" type="text" indexed="true" stored="true"/>
@ -422,6 +423,7 @@
<dynamicField name="*_f" type="float" indexed="true" stored="true"/>
<dynamicField name="*_d" type="double" indexed="true" stored="true"/>
<dynamicField name="*_dt" type="date" indexed="true" stored="true"/>
<dynamicField name="*_dt1" type="date" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="*_sI" type="string" indexed="true" stored="false"/>
<dynamicField name="*_sS" type="string" indexed="false" stored="true"/>

View File

@ -0,0 +1,257 @@
/*
* 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.handler.extraction;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Instant;
import java.util.Date;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.QueryResponseWriter;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.response.RawResponseWriter;
import org.apache.solr.search.SolrReturnFields;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestXLSXResponseWriter extends SolrTestCaseJ4 {
private static XLSXResponseWriter writerXlsx;
@BeforeClass
public static void beforeClass() throws Exception {
System.setProperty("enable.update.log", "false");
initCore("solrconfig.xml","schema.xml",getFile("extraction/solr").getAbsolutePath());
createIndex();
//find a reference to the default response writer so we can redirect its output later
SolrCore testCore = h.getCore();
QueryResponseWriter writer = testCore.getQueryResponseWriter("xlsx");
if (writer instanceof XLSXResponseWriter) {
writerXlsx = (XLSXResponseWriter) testCore.getQueryResponseWriter("xlsx");
} else {
throw new Exception("XLSXResponseWriter not registered with solr core");
}
}
public static void createIndex() {
assertU(adoc("id","1", "foo_i","-1", "foo_s","hi", "foo_l","12345678987654321", "foo_b","false", "foo_f","1.414","foo_d","-1.0E300","foo_dt1","2000-01-02T03:04:05Z"));
assertU(adoc("id","2", "v_ss","hi", "v_ss","there", "v2_ss","nice", "v2_ss","output", "shouldbeunstored","foo"));
assertU(adoc("id","3", "shouldbeunstored","foo"));
assertU(adoc("id","4", "foo_s1","foo"));
assertU(commit());
}
@AfterClass
public static void cleanupWriter() throws Exception {
writerXlsx = null;
}
@Test
public void testStructuredDataViaBaseWriters() throws IOException, Exception {
SolrQueryResponse rsp = new SolrQueryResponse();
// Don't send a ContentStream back, this will fall back to the configured base writer.
// But abuse the CONTENT key to ensure writer is also checking type
rsp.add(RawResponseWriter.CONTENT, "test");
rsp.add("foo", "bar");
SolrQueryRequest r = req();
// check Content-Type
assertEquals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", writerXlsx.getContentType(r, rsp));
// test our basic types,and that fields come back in the requested order
XSSFSheet resultSheet = getWSResultForQuery(req("q","id:1", "wt","xlsx", "fl","id,foo_s,foo_i,foo_l,foo_b,foo_f,foo_d,foo_dt1"));
assertEquals("id,foo_s,foo_i,foo_l,foo_b,foo_f,foo_d,foo_dt1\n1,hi,-1,12345678987654321,F,1.414,-1.0E300,2000-01-02T03:04:05Z\n"
, getStringFromSheet(resultSheet));
resultSheet = getWSResultForQuery(req("q","id:1^0", "wt","xlsx", "fl","id,score,foo_s"));
// test retrieving score
assertEquals("id,score,foo_s\n1,0.0,hi\n", getStringFromSheet(resultSheet));
resultSheet = getWSResultForQuery(req("q","id:1^0", "wt","xlsx", "colname.id", "I.D.", "colwidth.id", "10",
"fl","id,score,foo_s"));
// test override colname/width
assertEquals("I.D.,score,foo_s\n1,0.0,hi\n", getStringFromSheet(resultSheet));
// test colwidth (value returned is in 256ths of a character as per excel standard)
assertEquals(10*256, resultSheet.getColumnWidth(0));
resultSheet = getWSResultForQuery(req("q","id:2", "wt","xlsx", "fl","id,v_ss"));
// test multivalued
assertEquals("id,v_ss\n2,hi; there\n", getStringFromSheet(resultSheet));
// test retrieving fields from index
resultSheet = getWSResultForQuery(req("q","*:*", "wt","xslx", "fl","*,score"));
String result = getStringFromSheet(resultSheet);
for (String field : "id,foo_s,foo_i,foo_l,foo_b,foo_f,foo_d,foo_dt1,v_ss,v2_ss,score".split(",")) {
assertTrue(result.indexOf(field) >= 0);
}
// test null values
resultSheet = getWSResultForQuery(req("q","id:2", "wt","xlsx", "fl","id,foo_s,v_ss"));
assertEquals("id,foo_s,v_ss\n2,,hi; there\n", getStringFromSheet(resultSheet));
// now test SolrDocumentList
SolrDocument d = new SolrDocument();
SolrDocument d1 = d;
d.addField("id","1");
d.addField("foo_i",-1);
d.addField("foo_s","hi");
d.addField("foo_l","12345678987654321L");
d.addField("foo_b",false);
d.addField("foo_f",1.414f);
d.addField("foo_d",-1.0E300);
d.addField("foo_dt1", new Date(Instant.parse("2000-01-02T03:04:05Z").toEpochMilli()));
d.addField("score", "2.718");
d = new SolrDocument();
SolrDocument d2 = d;
d.addField("id","2");
d.addField("v_ss","hi");
d.addField("v_ss","there");
d.addField("v2_ss","nice");
d.addField("v2_ss","output");
d.addField("score", "89.83");
d.addField("shouldbeunstored","foo");
SolrDocumentList sdl = new SolrDocumentList();
sdl.add(d1);
sdl.add(d2);
SolrQueryRequest req = req("q","*:*");
rsp = new SolrQueryResponse();
rsp.addResponse(sdl);
rsp.setReturnFields( new SolrReturnFields("id,foo_s", req) );
resultSheet = getWSResultForQuery(req, rsp);
assertEquals("id,foo_s\n1,hi\n2,\n", getStringFromSheet(resultSheet));
// try scores
rsp.setReturnFields( new SolrReturnFields("id,score,foo_s", req) );
resultSheet = getWSResultForQuery(req, rsp);
assertEquals("id,score,foo_s\n1,2.718,hi\n2,89.83,\n", getStringFromSheet(resultSheet));
// get field values from docs... should be ordered and not include score unless requested
rsp.setReturnFields( new SolrReturnFields("*", req) );
resultSheet = getWSResultForQuery(req, rsp);
assertEquals("id,foo_i,foo_s,foo_l,foo_b,foo_f,foo_d,foo_dt1,v_ss,v2_ss\n" +
"1,-1,hi,12345678987654321L,false,1.414,-1.0E300,2000-01-02T03:04:05Z,,\n" +
"2,,,,,,,,hi; there,nice; output\n", getStringFromSheet(resultSheet));
// get field values and scores - just check that the scores are there... we don't guarantee where
rsp.setReturnFields( new SolrReturnFields("*,score", req) );
resultSheet = getWSResultForQuery(req, rsp);
String s = getStringFromSheet(resultSheet);
assertTrue(s.indexOf("score") >=0 && s.indexOf("2.718") > 0 && s.indexOf("89.83") > 0 );
// Test field globs
rsp.setReturnFields( new SolrReturnFields("id,foo*", req) );
resultSheet = getWSResultForQuery(req, rsp);
assertEquals("id,foo_i,foo_s,foo_l,foo_b,foo_f,foo_d,foo_dt1\n" +
"1,-1,hi,12345678987654321L,false,1.414,-1.0E300,2000-01-02T03:04:05Z\n" +
"2,,,,,,,\n", getStringFromSheet(resultSheet));
rsp.setReturnFields( new SolrReturnFields("id,*_d*", req) );
resultSheet = getWSResultForQuery(req, rsp);
assertEquals("id,foo_d,foo_dt1\n" +
"1,-1.0E300,2000-01-02T03:04:05Z\n" +
"2,,\n", getStringFromSheet(resultSheet));
// Test function queries
rsp.setReturnFields( new SolrReturnFields("sum(1,1),id,exists(foo_s1),div(9,1),foo_f", req) );
resultSheet = getWSResultForQuery(req, rsp);
assertEquals("sum(1,1),id,exists(foo_s1),div(9,1),foo_f\n" +
",1,,,1.414\n" +
",2,,,\n", getStringFromSheet(resultSheet));
// Test transformers
rsp.setReturnFields( new SolrReturnFields("mydocid:[docid],[explain]", req) );
resultSheet = getWSResultForQuery(req, rsp);
assertEquals("mydocid,[explain]\n" +
",\n" +
",\n", getStringFromSheet(resultSheet));
req.close();
}
@Test
public void testPseudoFields() throws Exception {
// Use Pseudo Field
SolrQueryRequest req = req("q","id:1", "wt","xlsx", "fl","XXX:id,foo_s");
XSSFSheet resultSheet = getWSResultForQuery(req);
assertEquals("XXX,foo_s\n1,hi\n", getStringFromSheet(resultSheet));
String txt = getStringFromSheet(getWSResultForQuery(req("q","id:1", "wt","xlsx", "fl","XXX:id,YYY:[docid],FOO:foo_s")));
String[] lines = txt.split("\n");
assertEquals(2, lines.length);
assertEquals("XXX,YYY,FOO", lines[0] );
assertEquals("1,0,hi", lines[1] );
//assertions specific to multiple pseudofields functions like abs, div, exists, etc.. (SOLR-5423)
String funcText = getStringFromSheet(getWSResultForQuery(req("q","*", "wt","xlsx", "fl","XXX:id,YYY:exists(foo_s1)")));
String[] funcLines = funcText.split("\n");
assertEquals(5, funcLines.length);
assertEquals("XXX,YYY", funcLines[0] );
assertEquals("1,false", funcLines[1] );
assertEquals("3,false", funcLines[3] );
}
// returns first worksheet as XLSXResponseWriter only returns one sheet
private XSSFSheet getWSResultForQuery(SolrQueryRequest req) throws IOException, Exception {
SolrQueryResponse rsp = h.queryAndResponse("standard", req);
return getWSResultForQuery(req, rsp);
}
private XSSFSheet getWSResultForQuery(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException, Exception {
ByteArrayOutputStream xmlBout = new ByteArrayOutputStream();
writerXlsx.write(xmlBout, req, rsp);
XSSFWorkbook output = new XSSFWorkbook(new ByteArrayInputStream(xmlBout.toByteArray()));
XSSFSheet sheet = output.getSheetAt(0);
req.close();
output.close();
return sheet;
}
private String getStringFromSheet(XSSFSheet sheet) {
StringBuilder output = new StringBuilder();
for (Row row: sheet) {
for (Cell cell: row) {
output.append(cell.getStringCellValue());
output.append(",");
}
output.setLength(output.length() - 1);
output.append("\n");
}
return output.toString();
}
}

View File

@ -2215,6 +2215,12 @@ public final class SolrCore implements SolrInfoMBean, Closeable {
m.put("smile", new SmileResponseWriter());
m.put(ReplicationHandler.FILE_STREAM, getFileStreamWriter());
DEFAULT_RESPONSE_WRITERS = Collections.unmodifiableMap(m);
try {
m.put("xlsx",
(QueryResponseWriter) Class.forName("org.apache.solr.handler.extraction.XLSXResponseWriter").newInstance());
} catch (Exception e) {
//don't worry; solrcell contrib not in class path
}
}
private static BinaryResponseWriter getFileStreamWriter() {
@ -2237,7 +2243,7 @@ public final class SolrCore implements SolrInfoMBean, Closeable {
}
public interface RawWriter {
public void write(OutputStream os) throws IOException ;
void write(OutputStream os) throws IOException ;
}
/** Configure the query response writers. There will always be a default writer; additional