001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.solr.request;
017:
018: import org.apache.lucene.document.Document;
019: import org.apache.solr.schema.IndexSchema;
020: import org.apache.solr.search.DocList;
021: import org.apache.solr.search.SolrIndexSearcher;
022: import org.apache.solr.util.NamedList;
023:
024: import java.io.IOException;
025: import java.io.Writer;
026: import java.util.Collection;
027: import java.util.Date;
028: import java.util.Iterator;
029: import java.util.Map;
030: import java.util.Set;
031:
032: /** Base class for text-oriented response writers.
033: *
034: * @author yonik
035: * @version $Id$
036: */
037: public abstract class TextResponseWriter {
038:
039: protected final Writer writer;
040: protected final IndexSchema schema;
041: protected final SolrQueryRequest req;
042: protected final SolrQueryResponse rsp;
043:
044: // the default set of fields to return for each document
045: protected Set<String> returnFields;
046:
047: protected int level;
048: protected boolean doIndent;
049:
050: public TextResponseWriter(Writer writer, SolrQueryRequest req,
051: SolrQueryResponse rsp) {
052: this .writer = writer;
053: this .schema = req.getSchema();
054: this .req = req;
055: this .rsp = rsp;
056: String indent = req.getParam("indent");
057: if (indent != null && !"".equals(indent)
058: && !"off".equals(indent)) {
059: doIndent = true;
060: }
061: returnFields = rsp.getReturnFields();
062: }
063:
064: /** returns the Writer that the response is being written to */
065: public Writer getWriter() {
066: return writer;
067: }
068:
069: // use a combination of tabs and spaces to minimize the size of an indented response.
070: private static final String[] indentArr = new String[] { "\n",
071: "\n ", "\n ", "\n\t", "\n\t ", "\n\t ", // could skip this one (the only 3 char seq)
072: "\n\t\t", "\n\t\t " };
073:
074: public void indent() throws IOException {
075: if (doIndent)
076: indent(level);
077: }
078:
079: public void indent(int lev) throws IOException {
080: int arrsz = indentArr.length - 1;
081: // power-of-two intent array (gratuitous optimization :-)
082: String istr = indentArr[lev & (indentArr.length - 1)];
083: writer.write(istr);
084: }
085:
086: //
087: // Functions to manipulate the current logical nesting level.
088: // Any indentation will be partially based on level.
089: //
090: public void setLevel(int level) {
091: this .level = level;
092: }
093:
094: public int level() {
095: return level;
096: }
097:
098: public int incLevel() {
099: return ++level;
100: }
101:
102: public int decLevel() {
103: return --level;
104: }
105:
106: public void setIndent(boolean doIndent) {
107: this .doIndent = doIndent;
108: }
109:
110: public abstract void writeNamedList(String name, NamedList val)
111: throws IOException;
112:
113: public void writeVal(String name, Object val) throws IOException {
114:
115: // if there get to be enough types, perhaps hashing on the type
116: // to get a handler might be faster (but types must be exact to do that...)
117:
118: // go in order of most common to least common
119: if (val == null) {
120: writeNull(name);
121: } else if (val instanceof String) {
122: writeStr(name, val.toString(), true);
123: // micro-optimization... using toString() avoids a cast first
124: } else if (val instanceof Integer) {
125: writeInt(name, val.toString());
126: } else if (val instanceof Boolean) {
127: writeBool(name, val.toString());
128: } else if (val instanceof Long) {
129: writeLong(name, val.toString());
130: } else if (val instanceof Date) {
131: writeDate(name, (Date) val);
132: } else if (val instanceof Float) {
133: // we pass the float instead of using toString() because
134: // it may need special formatting. same for double.
135: writeFloat(name, ((Float) val).floatValue());
136: } else if (val instanceof Double) {
137: writeDouble(name, ((Double) val).doubleValue());
138: } else if (val instanceof Document) {
139: writeDoc(name, (Document) val, returnFields, 0.0f, false);
140: } else if (val instanceof DocList) {
141: // requires access to IndexReader
142: writeDocList(name, (DocList) val, returnFields, null);
143: // }
144: // else if (val instanceof DocSet) {
145: // how do we know what fields to read?
146: // todo: have a DocList/DocSet wrapper that
147: // restricts the fields to write...?
148: } else if (val instanceof Map) {
149: writeMap(name, (Map) val, false, true);
150: } else if (val instanceof NamedList) {
151: writeNamedList(name, (NamedList) val);
152: } else if (val instanceof Iterable) {
153: writeArray(name, ((Iterable) val).iterator());
154: } else if (val instanceof Object[]) {
155: writeArray(name, (Object[]) val);
156: } else if (val instanceof Iterator) {
157: writeArray(name, (Iterator) val);
158: } else {
159: // default... for debugging only
160: writeStr(name, val.getClass().getName() + ':'
161: + val.toString(), true);
162: }
163: }
164:
165: // names are passed when writing primitives like writeInt to allow many different
166: // types of formats, including those where the name may come after the value (like
167: // some XML formats).
168:
169: public abstract void writeDoc(String name, Document doc,
170: Set<String> returnFields, float score, boolean includeScore)
171: throws IOException;
172:
173: public abstract void writeDocList(String name, DocList ids,
174: Set<String> fields, Map otherFields) throws IOException;
175:
176: public abstract void writeStr(String name, String val,
177: boolean needsEscaping) throws IOException;
178:
179: public abstract void writeMap(String name, Map val,
180: boolean excludeOuter, boolean isFirstVal)
181: throws IOException;
182:
183: public abstract void writeArray(String name, Object[] val)
184: throws IOException;
185:
186: public abstract void writeArray(String name, Iterator val)
187: throws IOException;
188:
189: public abstract void writeNull(String name) throws IOException;
190:
191: /** if this form of the method is called, val is the Java string form of an int */
192: public abstract void writeInt(String name, String val)
193: throws IOException;
194:
195: public void writeInt(String name, int val) throws IOException {
196: writeInt(name, Integer.toString(val));
197: }
198:
199: /** if this form of the method is called, val is the Java string form of a long */
200: public abstract void writeLong(String name, String val)
201: throws IOException;
202:
203: public void writeLong(String name, long val) throws IOException {
204: writeLong(name, Long.toString(val));
205: }
206:
207: /** if this form of the method is called, val is the Java string form of a boolean */
208: public abstract void writeBool(String name, String val)
209: throws IOException;
210:
211: public void writeBool(String name, boolean val) throws IOException {
212: writeBool(name, Boolean.toString(val));
213: }
214:
215: /** if this form of the method is called, val is the Java string form of a float */
216: public abstract void writeFloat(String name, String val)
217: throws IOException;
218:
219: public void writeFloat(String name, float val) throws IOException {
220: writeFloat(name, Float.toString(val));
221: }
222:
223: /** if this form of the method is called, val is the Java string form of a double */
224: public abstract void writeDouble(String name, String val)
225: throws IOException;
226:
227: public void writeDouble(String name, double val) throws IOException {
228: writeDouble(name, Double.toString(val));
229: }
230:
231: public abstract void writeDate(String name, Date val)
232: throws IOException;
233:
234: /** if this form of the method is called, val is the Solr ISO8601 based date format */
235: public abstract void writeDate(String name, String val)
236: throws IOException;
237: }
|