blob: 0c39cb5e7c3f1185ba7ac9687c69e5f9761c781c [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.storm.solr.mapper;
import org.apache.storm.tuple.ITuple;
import com.google.gson.Gson;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import org.apache.solr.common.util.ContentStream;
import org.apache.solr.common.util.ContentStreamBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public class SolrJsonMapper implements SolrMapper {
private static final Logger logger = LoggerFactory.getLogger(SolrJsonMapper.class);
private static final String CONTENT_TYPE = "application/json";
private final String jsonUpdateUrl;
private final String jsonTupleField;
private final String collection;
public static class Builder {
private String jsonUpdateUrl = "/update/json/docs";
private final String jsonTupleField;
private final String collection;
/**
* {@link SolrJsonMapper} builder class.
* @param collection Name of the Solr collection to update using the SolrRequest
* @param jsonTupleField Name of the tuple field that contains the JSON object used to update the Solr index
*/
public Builder(String collection, String jsonTupleField) {
this.collection = collection;
this.jsonTupleField = jsonTupleField;
}
/**
* {@link SolrJsonMapper} builder class.
* @param solrClient {@link SolrClient} implementation from where to extract the default Solr collection, if any defined.
* @param jsonTupleField Name of the tuple field that contains the JSON object used to update the Solr index
* This doesn't work in secure mode, in secure mode we need to pass the collection
*/
public Builder(SolrClient solrClient, String jsonTupleField) {
String defaultCollection = null;
if (solrClient instanceof CloudSolrClient) {
defaultCollection = ((CloudSolrClient) solrClient).getDefaultCollection();
}
this.collection = defaultCollection;
this.jsonTupleField = jsonTupleField;
}
/**
* Sets the URL endpoint where to send {@link SolrRequest} requests in JSON format. This URL is defined
* by Solr and for the most part you will not have to call this method to to override this value.
* Currently the default value is /update/json/docs.
* This method is available to support future evolutions of the Solr API.
*
* @param jsonUpdateUrl URL endpoint to where send {@link SolrRequest}
* @return {@link Builder object} used to build instances of {@link SolrJsonMapper}
*/
public Builder setJsonUpdateUrl(String jsonUpdateUrl) {
this.jsonUpdateUrl = jsonUpdateUrl;
return this;
}
public SolrJsonMapper build() {
return new SolrJsonMapper(this);
}
}
private SolrJsonMapper(Builder builder) {
jsonTupleField = builder.jsonTupleField ;
collection = builder.collection;
jsonUpdateUrl = builder.jsonUpdateUrl;
}
@Override
public String getCollection() {
return collection;
}
/**
*
* @param tuples
* @return
* @throws SolrMapperException if the tuple does not contain the
*/
@Override
public SolrRequest toSolrRequest(List<? extends ITuple> tuples) throws SolrMapperException {
final String jsonList = getJsonFromTuples(tuples);
return createtSolrRequest(jsonList);
}
@Override
public SolrRequest toSolrRequest(ITuple tuple) throws SolrMapperException {
final String json = getJsonFromTuple(tuple);
return createtSolrRequest(json);
}
private SolrRequest createtSolrRequest(String json) {
final ContentStreamUpdateRequest request = new ContentStreamUpdateRequest(jsonUpdateUrl);
final ContentStream cs = new ContentStreamBase.StringStream(json, CONTENT_TYPE);
request.addContentStream(cs);
if (logger.isDebugEnabled()) {
logger.debug("Request generated with JSON: " + json);
}
return request;
}
// Builds a JSON list
private String getJsonFromTuples(List<? extends ITuple> tuples) throws SolrMapperException {
final StringBuilder jsonListBuilder = new StringBuilder("[");
for (ITuple tuple : tuples) {
final String json = getJsonFromTuple(tuple);
jsonListBuilder.append(json).append(",");
}
jsonListBuilder.setCharAt(jsonListBuilder.length() - 1, ']');
return jsonListBuilder.toString();
}
private String getJsonFromTuple(ITuple tuple) throws SolrMapperException {
String json = "";
if (tuple.contains(jsonTupleField)) {
json = doGetJson(tuple.getValueByField(jsonTupleField));
} else {
throw new SolrMapperException("Tuple does not contain JSON object");
}
return json;
}
private String doGetJson(Object value) {
String json = "";
if (value instanceof String) {
json = (String) value; // Object associated with JSON field is already JSON
} else {
Gson gson = new Gson();
json = gson.toJson(value); // Serializes a Java object to JSON
}
return json;
}
}