1
package org.apache.solr.handler;
3
* Licensed to the Apache Software Foundation (ASF) under one or more
4
* contributor license agreements. See the NOTICE file distributed with
5
* this work for additional information regarding copyright ownership.
6
* The ASF licenses this file to You under the Apache License, Version 2.0
7
* (the "License"); you may not use this file except in compliance with
8
* the License. You may obtain a copy of the License at
10
* http://www.apache.org/licenses/LICENSE-2.0
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
19
import org.apache.solr.update.processor.UpdateRequestProcessor;
20
import org.apache.solr.update.AddUpdateCommand;
21
import org.apache.solr.update.CommitUpdateCommand;
22
import org.apache.solr.update.RollbackUpdateCommand;
23
import org.apache.solr.update.DeleteUpdateCommand;
24
import org.apache.solr.request.SolrQueryRequest;
25
import org.apache.solr.response.SolrQueryResponse;
26
import org.apache.solr.common.util.ContentStream;
27
import org.apache.solr.common.util.ContentStreamBase;
28
import org.apache.solr.common.util.StrUtils;
29
import org.apache.solr.common.SolrException;
30
import org.apache.solr.common.SolrInputDocument;
31
import org.apache.solr.common.params.ModifiableSolrParams;
32
import org.apache.solr.common.params.SolrParams;
33
import org.apache.solr.common.params.UpdateParams;
34
import org.apache.commons.io.IOUtils;
36
import javax.xml.stream.XMLStreamReader;
37
import javax.xml.stream.XMLStreamException;
38
import javax.xml.stream.FactoryConfigurationError;
39
import javax.xml.stream.XMLStreamConstants;
40
import javax.xml.stream.XMLInputFactory;
41
import javax.xml.transform.TransformerConfigurationException;
42
import java.io.ByteArrayInputStream;
43
import java.io.InputStream;
44
import java.io.IOException;
51
class XMLLoader extends ContentStreamLoader {
52
protected UpdateRequestProcessor processor;
53
protected XMLInputFactory inputFactory;
55
public XMLLoader(UpdateRequestProcessor processor, XMLInputFactory inputFactory) {
56
this.processor = processor;
57
this.inputFactory = inputFactory;
61
public void load(SolrQueryRequest req, SolrQueryResponse rsp, ContentStream stream) throws Exception {
62
errHeader = "XMLLoader: " + stream.getSourceInfo();
63
InputStream is = null;
64
XMLStreamReader parser = null;
66
is = stream.getStream();
67
final String charset = ContentStreamBase.getCharsetFromContentType(stream.getContentType());
68
if (XmlUpdateRequestHandler.log.isTraceEnabled()) {
69
final byte[] body = IOUtils.toByteArray(is);
70
// TODO: The charset may be wrong, as the real charset is later
71
// determined by the XML parser, the content-type is only used as a hint!
72
XmlUpdateRequestHandler.log.trace("body", new String(body, (charset == null) ?
73
ContentStreamBase.DEFAULT_CHARSET : charset));
74
IOUtils.closeQuietly(is);
75
is = new ByteArrayInputStream(body);
77
parser = (charset == null) ?
78
inputFactory.createXMLStreamReader(is) : inputFactory.createXMLStreamReader(is, charset);
79
this.processUpdate(req, processor, parser);
80
} catch (XMLStreamException e) {
81
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e.getMessage(), e);
83
if (parser != null) parser.close();
84
IOUtils.closeQuietly(is);
88
/* Support legacy Update signature */
89
void processUpdate(UpdateRequestProcessor processor, XMLStreamReader parser) throws TransformerConfigurationException, XMLStreamException, IOException, FactoryConfigurationError, InstantiationException, IllegalAccessException {
90
processUpdate(null, processor, parser);
96
void processUpdate(SolrQueryRequest req, UpdateRequestProcessor processor, XMLStreamReader parser)
97
throws XMLStreamException, IOException, FactoryConfigurationError,
98
InstantiationException, IllegalAccessException,
99
TransformerConfigurationException {
100
AddUpdateCommand addCmd = null;
101
// Need to instansiate a SolrParams, even if req is null, for backward compat with legacyUpdate
102
SolrParams params = (req != null) ? req.getParams() : new ModifiableSolrParams();
104
int event = parser.next();
106
case XMLStreamConstants.END_DOCUMENT:
110
case XMLStreamConstants.START_ELEMENT:
111
String currTag = parser.getLocalName();
112
if (currTag.equals(XmlUpdateRequestHandler.ADD)) {
113
XmlUpdateRequestHandler.log.trace("SolrCore.update(add)");
115
addCmd = new AddUpdateCommand();
117
// First look for commitWithin parameter on the request, will be overwritten for individual <add>'s
118
addCmd.commitWithin = params.getInt(UpdateParams.COMMIT_WITHIN, -1);
120
boolean overwrite = true; // the default
122
Boolean overwritePending = null;
123
Boolean overwriteCommitted = null;
124
for (int i = 0; i < parser.getAttributeCount(); i++) {
125
String attrName = parser.getAttributeLocalName(i);
126
String attrVal = parser.getAttributeValue(i);
127
if (XmlUpdateRequestHandler.OVERWRITE.equals(attrName)) {
128
overwrite = StrUtils.parseBoolean(attrVal);
129
} else if (XmlUpdateRequestHandler.ALLOW_DUPS.equals(attrName)) {
130
overwrite = !StrUtils.parseBoolean(attrVal);
131
} else if (XmlUpdateRequestHandler.COMMIT_WITHIN.equals(attrName)) {
132
addCmd.commitWithin = Integer.parseInt(attrVal);
133
} else if (XmlUpdateRequestHandler.OVERWRITE_PENDING.equals(attrName)) {
134
overwritePending = StrUtils.parseBoolean(attrVal);
135
} else if (XmlUpdateRequestHandler.OVERWRITE_COMMITTED.equals(attrName)) {
136
overwriteCommitted = StrUtils.parseBoolean(attrVal);
138
XmlUpdateRequestHandler.log.warn("Unknown attribute id in add:" + attrName);
142
// check if these flags are set
143
if (overwritePending != null && overwriteCommitted != null) {
144
if (overwritePending != overwriteCommitted) {
145
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
146
"can't have different values for 'overwritePending' and 'overwriteCommitted'");
148
overwrite = overwritePending;
150
addCmd.overwriteCommitted = overwrite;
151
addCmd.overwritePending = overwrite;
152
addCmd.allowDups = !overwrite;
153
} else if ("doc".equals(currTag)) {
154
// if(addCmd != null) {
155
XmlUpdateRequestHandler.log.trace("adding doc...");
157
addCmd.solrDoc = readDoc(parser);
158
processor.processAdd(addCmd);
160
// throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unexpected <doc> tag without an <add> tag surrounding it.");
162
} else if (XmlUpdateRequestHandler.COMMIT.equals(currTag) || XmlUpdateRequestHandler.OPTIMIZE.equals(currTag)) {
163
XmlUpdateRequestHandler.log.trace("parsing " + currTag);
165
CommitUpdateCommand cmd = new CommitUpdateCommand(XmlUpdateRequestHandler.OPTIMIZE.equals(currTag));
167
boolean sawWaitSearcher = false, sawWaitFlush = false;
168
for (int i = 0; i < parser.getAttributeCount(); i++) {
169
String attrName = parser.getAttributeLocalName(i);
170
String attrVal = parser.getAttributeValue(i);
171
if (XmlUpdateRequestHandler.WAIT_FLUSH.equals(attrName)) {
172
cmd.waitFlush = StrUtils.parseBoolean(attrVal);
174
} else if (XmlUpdateRequestHandler.WAIT_SEARCHER.equals(attrName)) {
175
cmd.waitSearcher = StrUtils.parseBoolean(attrVal);
176
sawWaitSearcher = true;
177
} else if (UpdateParams.MAX_OPTIMIZE_SEGMENTS.equals(attrName)) {
178
cmd.maxOptimizeSegments = Integer.parseInt(attrVal);
179
} else if (UpdateParams.EXPUNGE_DELETES.equals(attrName)) {
180
cmd.expungeDeletes = StrUtils.parseBoolean(attrVal);
182
XmlUpdateRequestHandler.log.warn("unexpected attribute commit/@" + attrName);
186
// If waitFlush is specified and waitSearcher wasn't, then
187
// clear waitSearcher.
188
if (sawWaitFlush && !sawWaitSearcher) {
189
cmd.waitSearcher = false;
191
processor.processCommit(cmd);
193
else if (XmlUpdateRequestHandler.ROLLBACK.equals(currTag)) {
194
XmlUpdateRequestHandler.log.trace("parsing " + currTag);
196
RollbackUpdateCommand cmd = new RollbackUpdateCommand();
198
processor.processRollback(cmd);
200
else if (XmlUpdateRequestHandler.DELETE.equals(currTag)) {
201
XmlUpdateRequestHandler.log.trace("parsing delete");
202
processDelete(processor, parser);
212
void processDelete(UpdateRequestProcessor processor, XMLStreamReader parser) throws XMLStreamException, IOException {
214
DeleteUpdateCommand deleteCmd = new DeleteUpdateCommand();
215
deleteCmd.fromPending = true;
216
deleteCmd.fromCommitted = true;
217
for (int i = 0; i < parser.getAttributeCount(); i++) {
218
String attrName = parser.getAttributeLocalName(i);
219
String attrVal = parser.getAttributeValue(i);
220
if ("fromPending".equals(attrName)) {
221
deleteCmd.fromPending = StrUtils.parseBoolean(attrVal);
222
} else if ("fromCommitted".equals(attrName)) {
223
deleteCmd.fromCommitted = StrUtils.parseBoolean(attrVal);
225
XmlUpdateRequestHandler.log.warn("unexpected attribute delete/@" + attrName);
229
StringBuilder text = new StringBuilder();
231
int event = parser.next();
233
case XMLStreamConstants.START_ELEMENT:
234
String mode = parser.getLocalName();
235
if (!("id".equals(mode) || "query".equals(mode))) {
236
XmlUpdateRequestHandler.log.warn("unexpected XML tag /delete/" + mode);
237
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
238
"unexpected XML tag /delete/" + mode);
243
case XMLStreamConstants.END_ELEMENT:
244
String currTag = parser.getLocalName();
245
if ("id".equals(currTag)) {
246
deleteCmd.id = text.toString();
247
} else if ("query".equals(currTag)) {
248
deleteCmd.query = text.toString();
249
} else if ("delete".equals(currTag)) {
252
XmlUpdateRequestHandler.log.warn("unexpected XML tag /delete/" + currTag);
253
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
254
"unexpected XML tag /delete/" + currTag);
256
processor.processDelete(deleteCmd);
258
deleteCmd.query = null;
261
// Add everything to the text
262
case XMLStreamConstants.SPACE:
263
case XMLStreamConstants.CDATA:
264
case XMLStreamConstants.CHARACTERS:
265
text.append(parser.getText());
273
* Given the input stream, read a document
277
SolrInputDocument readDoc(XMLStreamReader parser) throws XMLStreamException {
278
SolrInputDocument doc = new SolrInputDocument();
280
String attrName = "";
281
for (int i = 0; i < parser.getAttributeCount(); i++) {
282
attrName = parser.getAttributeLocalName(i);
283
if ("boost".equals(attrName)) {
284
doc.setDocumentBoost(Float.parseFloat(parser.getAttributeValue(i)));
286
XmlUpdateRequestHandler.log.warn("Unknown attribute doc/@" + attrName);
290
StringBuilder text = new StringBuilder();
293
boolean isNull = false;
295
int event = parser.next();
297
// Add everything to the text
298
case XMLStreamConstants.SPACE:
299
case XMLStreamConstants.CDATA:
300
case XMLStreamConstants.CHARACTERS:
301
text.append(parser.getText());
304
case XMLStreamConstants.END_ELEMENT:
305
if ("doc".equals(parser.getLocalName())) {
307
} else if ("field".equals(parser.getLocalName())) {
309
doc.addField(name, text.toString(), boost);
315
case XMLStreamConstants.START_ELEMENT:
317
String localName = parser.getLocalName();
318
if (!"field".equals(localName)) {
319
XmlUpdateRequestHandler.log.warn("unexpected XML tag doc/" + localName);
320
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
321
"unexpected XML tag doc/" + localName);
325
for (int i = 0; i < parser.getAttributeCount(); i++) {
326
attrName = parser.getAttributeLocalName(i);
327
attrVal = parser.getAttributeValue(i);
328
if ("name".equals(attrName)) {
330
} else if ("boost".equals(attrName)) {
331
boost = Float.parseFloat(attrVal);
332
} else if ("null".equals(attrName)) {
333
isNull = StrUtils.parseBoolean(attrVal);
335
XmlUpdateRequestHandler.log.warn("Unknown attribute doc/field/@" + attrName);