*/
public class IndexApi {
+ private static final String HEADER_VALIDATION_SUCCESS = "SUCCESS";
+
protected SearchServiceApi searchService = null;
/**
// Finally, return the response.
return response;
}
+
+ /**
+ * This function accepts any JSON and will "blindly" write it to the
+ * document store.
+ *
+ * Note, eventually this "dynamic" flow should follow the same JSON-Schema
+ * validation procedure as the normal create index flow.
+ *
+ * @param dynamicSchema - The JSON string that will be sent to the document store.
+ * @param index - The name of the index to be created.
+ * @param documentStore - The document store specific interface.
+ * @return The result of the document store interface's operation.
+ */
+ public Response processCreateDynamicIndex(String dynamicSchema, HttpServletRequest request,
+ HttpHeaders headers, String index, DocumentStoreInterface documentStore) {
+
+ Response response = null;
+
+ Response validationResponse = validateRequest(request, headers, index, SearchDbMsgs.INDEX_CREATE_FAILURE);
+
+ if (validationResponse.getStatus() != Response.Status.OK.getStatusCode()) {
+ response = validationResponse;
+ } else {
+ OperationResult result = documentStore.createDynamicIndex(index, dynamicSchema);
+
+ int resultCode = (result.getResultCode() == 200) ? 201 : result.getResultCode();
+ String resultString = (result.getFailureCause() == null) ? result.getResult() : result.getFailureCause();
+
+ response = Response.status(resultCode).entity(resultString).build();
+ }
+
+ return response;
+ }
/**
return errorResponse(Response.Status.FORBIDDEN, "Authentication failure.", request);
}
-
try {
// Send the request to the document store.
response = responseFromOperationResult(documentStore.deleteIndex(index));
.entity(e.getMessage())
.build();
}
-
-
+
// Log the result.
if ((response.getStatus() >= 200) && (response.getStatus() < 300)) {
logger.info(SearchDbMsgs.DELETED_INDEX, index);
.entity(msg)
.build();
}
-
-
+
+ /**
+ * A helper method used for validating/authenticating an incoming request.
+ *
+ * @param request - The http request that will be validated.
+ * @param headers - The http headers that will be validated.
+ * @param index - The name of the index that the document store request is being made against.
+ * @param failureMsgEnum - The logging message to be used upon validation failure.
+ * @return A success or failure response
+ */
+ private Response validateRequest(HttpServletRequest request, HttpHeaders headers, String index, SearchDbMsgs failureMsgEnum) {
+ try {
+ if (!searchService.validateRequest(headers, request, ApiUtils.Action.POST, ApiUtils.SEARCH_AUTH_POLICY_NAME)) {
+ logger.warn(failureMsgEnum, index, "Authentication failure.");
+ return errorResponse(Response.Status.FORBIDDEN, "Authentication failure.", request);
+ }
+ } catch (Exception e) {
+ logger.warn(failureMsgEnum, index, "Unexpected authentication failure - cause: " + e.getMessage());
+ return errorResponse(Response.Status.FORBIDDEN, "Authentication failure.", request);
+ }
+ return Response.status(Response.Status.OK).entity(HEADER_VALIDATION_SUCCESS).build();
+ }
}
return indexApi.processCreateIndex(requestBody, request, headers, index, documentStore);
}
+ @PUT
+ @Path("/indexes/dynamic/{index}")
+ @Consumes({MediaType.APPLICATION_JSON})
+ public Response processCreateDynamicIndex(String requestBody,
+ @Context HttpServletRequest request,
+ @Context HttpHeaders headers,
+ @PathParam("index") String index) {
+
+ // Forward the request to our index API to create the index.
+ IndexApi indexApi = new IndexApi(this);
+ return indexApi.processCreateDynamicIndex(requestBody, request, headers, index, documentStore);
+ }
@DELETE
@Path("/indexes/{index}")
public OperationResult createIndex(String index, DocumentSchema documentSchema);
+ public OperationResult createDynamicIndex(String index, String dynamicSchema);
+
public OperationResult deleteIndex(String indexName) throws DocumentStoreOperationException;
public DocumentOperationResult createDocument(String indexName,
return result;
}
+ @Override
+ public OperationResult createDynamicIndex(String index, String dynamicSchema) {
+ OperationResult result = new OperationResult();
+ result.setResultCode(500);
+
+ try {
+ result = createTable(index, dynamicSchema);
+
+ // ElasticSearch will return us a 200 code on success when we
+ // want to report a 201, so translate the result here.
+ result.setResultCode((result.getResultCode() == 200) ? 201 : result.getResultCode());
+ if (isSuccess(result)) {
+ result.setResult("{\"url\": \"" + ApiUtils.buildIndexUri(index) + "\"}");
+ }
+ } catch (DocumentStoreOperationException e) {
+ result.setFailureCause("Document store operation failure. Cause: " + e.getMessage());
+ }
+
+ return result;
+ }
@Override
public OperationResult deleteIndex(String indexName) throws DocumentStoreOperationException {
return opResult;
}
+ /**
+ * Will send the passed in JSON payload to Elasticsearch using the
+ * provided index name in an attempt to create the index.
+ *
+ * @param indexName - The name of the index to be created
+ * @param settingsAndMappings - The actual JSON object that will define the index
+ * @return - The operation result of writing into Elasticsearch
+ * @throws DocumentStoreOperationException
+ */
+ protected OperationResult createTable(String indexName, String settingsAndMappings) throws DocumentStoreOperationException {
+ OperationResult result = new OperationResult();
+ result.setResultCode(500);
+ result.setResult(INTERNAL_SERVER_ERROR_ELASTIC_SEARCH_OPERATION_FAULT);
+
+ // Grab the current time so we can use it to generate a metrics log.
+ MdcOverride override = getStartTime(new MdcOverride());
+
+ String fullUrl = getFullUrl("/" + indexName + "/", false);
+ HttpURLConnection conn = initializeConnection(fullUrl);
+
+ try {
+ conn.setRequestMethod("PUT");
+ } catch (ProtocolException e) {
+ shutdownConnection(conn);
+ throw new DocumentStoreOperationException("Failed to set HTTP request method to PUT.", e);
+ }
+
+ attachContent(conn, settingsAndMappings);
+ handleResponse(conn, result);
+
+ // Generate a metrics log so we can track how long the operation took.
+ metricsLogger.info(SearchDbMsgs.CREATE_INDEX_TIME,
+ new LogFields()
+ .setField(LogLine.DefinedFields.RESPONSE_CODE, result.getResultCode())
+ .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, result.getResultCode()),
+ override,
+ indexName);
+
+ return result;
+ }
+
@Override
public DocumentOperationResult createDocument(String indexName,
DocumentStoreDataEntity document,
private final String TOP_URI = "/test/indexes/";
private final String SIMPLE_DOC_SCHEMA_JSON = "src/test/resources/json/simpleDocument.json";
-
+ private final String DYNAMIC_INDEX_PAYLOAD = "src/test/resources/json/dynamicIndex.json";
@Override
protected Application configure() {
tokenizedResult[2].equals(EXPECTED_MAPPINGS));
}
+ /**
+ * Tests the dynamic shcema creation flow that send the request
+ * JSON to the data store without any JSON validation against a schema
+ *
+ * @throws IOException
+ */
+ @Test
+ public void createDynamicIndexTest() throws IOException {
+ String indexName = "super-ultra-dynamic-mega-index";
+ String dynamicUri = TOP_URI + "dynamic/";
+ File indexFile = new File(DYNAMIC_INDEX_PAYLOAD);
+ String indexPayload = TestUtils.readFileToString(indexFile);
+
+ String result = target(dynamicUri + indexName).request().put(Entity.json(indexPayload), String.class);
+
+ assertEquals(indexPayload, result);
+ }
/**
* This test validates that a 'create index' request with an improperly
return super.processCreateIndex(requestBody, request, headers, index);
}
+ @PUT
+ @Path("/indexes/dynamic/{index}")
+ @Consumes({MediaType.APPLICATION_JSON})
+ @Override
+ public Response processCreateDynamicIndex(String requestBody,
+ @Context HttpServletRequest request,
+ @Context HttpHeaders headers,
+ @PathParam("index") String index) {
+
+ return super.processCreateDynamicIndex(requestBody, request, headers, index);
+ }
+
@DELETE
@Path("/indexes/{index}")
@Consumes({MediaType.APPLICATION_JSON})
return opResult;
}
+ @Override
+ public OperationResult createDynamicIndex(String index, String dynamicSchema) {
+ OperationResult opResult = new OperationResult();
+ opResult.setResultCode(200);
+ // Directly return the json as this flow should not edit the json in any way
+ opResult.setResult(dynamicSchema);
+ return opResult;
+ }
@Override
public OperationResult deleteIndex(String indexName) throws DocumentStoreOperationException {
--- /dev/null
+{
+ "mappings": {
+ "dynamic_templates": [{
+ "strings": {
+ "match_mapping_type": "string",
+ "match": "*",
+ "mapping": {
+ "type": "string",
+ "index": "not_analyzed"
+ }
+ }
+ }
+ ]
+ }
+}
\ No newline at end of file