/**
* Copyright (C) 2014 Stratio (http://stratio.com)
*
* Licensed 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 com.stratio.decision.functions;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.spark.api.java.JavaPairRDD;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import com.google.common.collect.Iterables;
import com.stratio.decision.commons.constants.StreamAction;
import com.stratio.decision.commons.messages.ColumnNameTypeValue;
import com.stratio.decision.commons.messages.StratioStreamingMessage;
import com.stratio.decision.service.SolrOperationsService;
import com.stratio.decision.utils.RetryStrategy;
import scala.Tuple2;
public class SaveToSolrActionExecutionFunction extends BaseActionExecutionFunction {
private static final long serialVersionUID = 3522740757019463301L;
private static final Logger log = LoggerFactory.getLogger(SaveToSolrActionExecutionFunction.class);
private Map<String, SolrClient> solrClients = new HashMap<>();
private List<String> solrCores = new ArrayList<String>();
private transient SolrOperationsService solrOperationsService;
private RetryStrategy retryStrategy;
private final String dataDir;
private final String solrHost;
private final String zkHost;
private final Boolean isCloud;
private final Integer maxBatchSize;
public SaveToSolrActionExecutionFunction(String solrHost, String zkHost, Boolean isCloud, String dataDir, Integer
maxBatchSize) {
this.solrHost = solrHost;
this.zkHost = zkHost;
this.dataDir = dataDir;
this.isCloud = isCloud;
this.retryStrategy = new RetryStrategy();
this.maxBatchSize = maxBatchSize!=null?maxBatchSize:-1;
}
public SaveToSolrActionExecutionFunction(String solrHost, String zkHost, Boolean isCloud, String dataDir, Integer
maxBatchSize, SolrOperationsService solrOperationsService) {
this.solrHost = solrHost;
this.zkHost = zkHost;
this.dataDir = dataDir;
this.isCloud = isCloud;
this.solrOperationsService = solrOperationsService;
this.retryStrategy = new RetryStrategy();
this.maxBatchSize = maxBatchSize!=null?maxBatchSize:-1;
}
@Override
public Boolean check() throws Exception {
try {
getSolrOperationsService().getCoreList();
return true;
} catch (Exception e) {
return false;
}
}
@Override
public void process(Iterable<StratioStreamingMessage> messages) throws Exception {
Integer partitionSize = maxBatchSize;
if (partitionSize <= 0){
partitionSize = Iterables.size(messages);
}
Iterable<List<StratioStreamingMessage>> partitionIterables = Iterables.partition(messages, partitionSize);
try {
for (List<StratioStreamingMessage> messageList : partitionIterables) {
Map<String, Collection<SolrInputDocument>> elemntsToInsert = new HashMap<String, Collection<SolrInputDocument>>();
int count = 0;
for (StratioStreamingMessage stratioStreamingMessage : messageList) {
count += 1;
SolrInputDocument document = new SolrInputDocument();
document.addField("stratio_decision_id", System.nanoTime() + "-" + count);
for (ColumnNameTypeValue column : stratioStreamingMessage.getColumns()) {
document.addField(column.getColumn(), column.getValue());
}
checkCore(stratioStreamingMessage);
Collection<SolrInputDocument> collection = elemntsToInsert
.get(stratioStreamingMessage.getStreamName());
if (collection == null) {
collection = new HashSet<>();
}
collection.add(document);
elemntsToInsert.put(stratioStreamingMessage.getStreamName(), collection);
}
while (retryStrategy.shouldRetry()) {
try {
for (Map.Entry<String, Collection<SolrInputDocument>> elem : elemntsToInsert.entrySet()) {
getSolrclient(elem.getKey()).add(elem.getValue());
}
break;
} catch (SolrException e) {
try {
log.error("Solr cloud status not yet properly initialized, retrying");
retryStrategy.errorOccured();
} catch (RuntimeException ex) {
log.error("Error while initializing Solr Cloud core ", ex.getMessage());
}
}
}
flushClients();
}
} catch (Exception ex) {
log.error("Error in Solr: " + ex.getMessage());
}
}
private void checkCore(StratioStreamingMessage message) throws IOException, SolrServerException, ParserConfigurationException, TransformerException, SAXException, URISyntaxException, InterruptedException {
String core = message.getStreamName();
//check if core exists
if (solrCores.size() == 0) {
// Initialize solrcores list
solrCores = getSolrOperationsService().getCoreList();
}
if (!solrCores.contains(core)) {
// Create Core
getSolrOperationsService().createCore(message);
// Update core list
solrCores = getSolrOperationsService().getCoreList();
}
}
private SolrClient getClient(StratioStreamingMessage message) throws IOException, SolrServerException, URISyntaxException, TransformerException, SAXException, ParserConfigurationException {
String core = message.getStreamName();
if (solrClients.containsKey(core)) {
//we have a client for this core
return solrClients.get(core);
} else {
SolrClient solrClient = getSolrclient(core);
solrClients.put(core, solrClient);
return solrClient;
}
}
private void flushClients() throws IOException, SolrServerException, URISyntaxException {
//Do commit in all Solrclients
for (String core : solrClients.keySet()) {
getSolrclient(core).commit();
}
}
private SolrClient getSolrclient(String core) {
SolrClient solrClient;
if (solrClients.containsKey(core)) {
//we have a client for this core
return solrClients.get(core);
} else {
if (isCloud) {
solrClient = new CloudSolrClient(zkHost);
((CloudSolrClient) solrClient).setDefaultCollection(core);
} else {
solrClient = new HttpSolrClient("http://" + solrHost + "/solr/" + core);
}
solrClients.put(core, solrClient);
}
return solrClient;
}
private SolrOperationsService getSolrOperationsService() {
if (solrOperationsService == null) {
solrOperationsService = (SolrOperationsService) ActionBaseContext.getInstance().getContext().getBean
("solrOperationsService");
}
return solrOperationsService;
}
}