blob: 88f8eddbaca21ebae9ae1433f0df202ceb3c4b90 [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.manifoldcf.agents.output.searchblox;
import java.io.IOException;
import java.io.StringReader;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import org.apache.manifoldcf.agents.output.searchblox.SearchBloxDocument.IndexingFormat;
import org.apache.manifoldcf.crawler.system.Logging;
import org.apache.xerces.parsers.DOMParser;
import org.jboss.resteasy.plugins.providers.StringTextStar;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* SearchBox REST Client
*
* @author Rafa Haro <rharo@apache.org>
*/
public class SearchBloxClient {
// TODO All this might need to be included in a configuration file
public static final String DEFAULT_ENDPOINT = "http://localhost:8080/searchblox/rest/v1/api";
private static final String ADD_PATH = "add";
private static final String DELETE_PATH = "delete";
private static final String STATUS_PATH = "status";
private static final String CREATE_PATH = "coladd";
private static final String CLEAR_PATH = "clear";
private static final String STATUS_NODE = "statuscode";
private static final Pattern status_pattern = Pattern.compile("^status code\\s?:\\s([0-9]+)$");
public static enum ResponseCode {
DOCUMENT_INDEXED(100),
DOCUMENT_REJECTED(101),
DOCUMENT_DELETED(200, 2001),
DOCUMENT_NOT_EXIST(201, 2002),
DOCUMENT_NOT_FOUND(301),
COLLECTION_CLEARED(400),
ERROR_CLEARING_COLLECTION(401),
COLLECTION_CREATED(900),
INVALID_COLLECTION_NAME(500, 501),
INVALID_REQUEST(501),
INVALID_DOCUMENT_LOCATION(502),
NOT_CUSTOM_COLLECTION(503),
LIMIT_EXCEEDED(504),
INVALID_LICENSE_ID(601),
SERVER_UNREACHABLE(700);
private int code;
private int jsonCode;
ResponseCode(int code) {
this.code = code;
}
ResponseCode(int code, int jsonCode) {
this.code = code;
this.jsonCode = jsonCode;
}
static ResponseCode getCodeFromValue(int value){
for(ResponseCode e:ResponseCode.values())
if(value == e.code)
return e;
return null;
}
static ResponseCode getCodeFromValue(int value, boolean json){
for(ResponseCode e:ResponseCode.values())
if((json && value == e.jsonCode) || (value == e.code)) {
return e;
}
return null;
}
int getCode(){
return code;
}
int getJsonCode() {
return jsonCode;
}
}
private String apikey;
private Client client;
private UriBuilder uriBuilder;
public SearchBloxClient(String apikey, ClientBuilder builder, String endpoint) {
this.apikey = apikey;
builder.register(StringTextStar.class);
this.client = builder.build();
if (endpoint != null && !endpoint.isEmpty()) {
uriBuilder = UriBuilder.fromUri(endpoint);
} else {
uriBuilder = UriBuilder.fromUri(DEFAULT_ENDPOINT);
}
}
public ResponseCode addUpdateDocument(SearchBloxDocument document, String format)
throws SearchBloxException {
return post(document, format, SearchBloxDocument.DocumentAction.ADD_UPDATE);
}
public ResponseCode deleteDocument(SearchBloxDocument document, String format)
throws SearchBloxException {
return post(document, format, SearchBloxDocument.DocumentAction.DELETE);
}
public ResponseCode createCollection(String colname, String format)
throws SearchBloxException {
SearchBloxDocument document = new SearchBloxDocument(apikey);
document.colName = colname;
return post(document, format, SearchBloxDocument.DocumentAction.CREATE);
}
public ResponseCode clearCollection(String colname, String format)
throws SearchBloxException {
SearchBloxDocument document = new SearchBloxDocument(apikey);
document.colName = colname;
return post(document, format, SearchBloxDocument.DocumentAction.CLEAR);
}
public boolean ping(String format)
throws SearchBloxException {
SearchBloxDocument document = new SearchBloxDocument(apikey);
document.colName = UUID.randomUUID().toString();
document.uid = UUID.randomUUID().toString();
ResponseCode result = post(document, format, SearchBloxDocument.DocumentAction.STATUS);
return result == ResponseCode.INVALID_COLLECTION_NAME;
}
private ResponseCode post(SearchBloxDocument document, String format, SearchBloxDocument.DocumentAction action)
throws SearchBloxException {
SearchBloxDocument.IndexingFormat iFormat = SearchBloxDocument.IndexingFormat.valueOf(format.toUpperCase());
if (iFormat == null) {
Logging.connectors.error("[Post request] Format not recognized " +format);
throw new SearchBloxException("Unknown Serialization Format " + format);
}
boolean isJson = iFormat.equals(SearchBloxDocument.IndexingFormat.JSON);
UriBuilder uri = uriBuilder.clone();
if (action == SearchBloxDocument.DocumentAction.ADD_UPDATE) {
uri = uri.path(ADD_PATH);
} else if (action == SearchBloxDocument.DocumentAction.DELETE) {
uri = uri.path(DELETE_PATH);
} else if (action == SearchBloxDocument.DocumentAction.STATUS) {
uri = uri.path(STATUS_PATH);
} else if (action == SearchBloxDocument.DocumentAction.CREATE) {
uri = uri.path(CREATE_PATH);
} else if (action == SearchBloxDocument.DocumentAction.CLEAR) {
uri = uri.path(CLEAR_PATH);
}
WebTarget target = client.target(uri.build());
Builder httpRequest = target.request();
if (iFormat == SearchBloxDocument.IndexingFormat.JSON) {
httpRequest.accept(MediaType.APPLICATION_JSON_TYPE);
}else{
httpRequest.accept(MediaType.APPLICATION_XML_TYPE);
}
document.apiKey = this.apikey;
String body = document.toString(iFormat, action);
Logging.connectors.debug("Document for document: " + document.uid +":" + body);
MediaType type = MediaType.TEXT_PLAIN_TYPE;
if (iFormat == SearchBloxDocument.IndexingFormat.JSON) {
type = MediaType.APPLICATION_JSON_TYPE;
}
Entity<String> entity = Entity.entity(body, type);
Response response = null;
try {
response = httpRequest.post(entity);
}
catch(Exception e) {
// return e.getCause() instanceof ConnectException ? ResponseCode.SERVER_UNREACHABLE : ResponseCode.INVALID_COLLECTION_NAME;
Logging.connectors.error("[No Connection] Error trying to connect ",e);
return ResponseCode.SERVER_UNREACHABLE;
}
String rawResponse = response.readEntity(String.class);
if(iFormat == IndexingFormat.XML){
DOMParser parser = new DOMParser();
try {
parser.parse(new InputSource(new StringReader(rawResponse)));
} catch (SAXException | IOException e) {
Logging.connectors.error("[Response parsing] Dom parsing error", e);
throw new SearchBloxException(e);
}
Document doc = parser.getDocument();
NodeList nodeList = doc.getElementsByTagName(STATUS_NODE);
if (nodeList == null || nodeList.getLength() == 0) {
String message = "[Response Parsing] Status code not found";
Logging.connectors.error(message);
throw new SearchBloxException(message);
}
String codeStr = nodeList.item(0).getTextContent();
int statusCode = Integer.parseInt(codeStr);
return ResponseCode.getCodeFromValue(statusCode, isJson);
}else{
// try {
// JSONObject json = new JSONObject(rawResponse);
// String codeStr = json.getString(STATUS_NODE);
Matcher matcher = status_pattern.matcher(rawResponse);
String codeStr = null;
if(matcher.find())
codeStr = matcher.group(1);
if(codeStr == null){
String message = "[Response parsing] Response code parsing error";
Logging.connectors.error(message);
throw new SearchBloxException(message);
}
int statusCode = Integer.parseInt(codeStr);
return ResponseCode.getCodeFromValue(statusCode, isJson);
// } catch (JSONException e) {
// Logging.connectors.error("[Response parsing] Response JSON parsing error", e);
// throw new SearchBloxException(e);
// }
}
}
}