Java tutorial
/* * Copyright (C) 2003-2015 eXo Platform SAS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see http://www.gnu.org/licenses/ . */ package org.exoplatform.addons.es.rest; import io.swagger.annotations.*; import org.apache.commons.lang.StringUtils; import org.exoplatform.addons.es.domain.IndexingOperation; import org.exoplatform.addons.es.index.IndexingOperationProcessor; import org.exoplatform.addons.es.index.IndexingService; import org.exoplatform.addons.es.index.IndexingServiceConnector; import org.exoplatform.addons.es.index.impl.QueueIndexingService; import org.exoplatform.addons.es.rest.resource.CollectionResource; import org.exoplatform.addons.es.rest.resource.CollectionSizeResource; import org.exoplatform.addons.es.rest.resource.ConnectorResource; import org.exoplatform.addons.es.rest.resource.OperationResource; import org.exoplatform.common.http.HTTPStatus; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.rest.resource.ResourceContainer; import org.exoplatform.ws.frameworks.json.impl.JsonException; import org.exoplatform.ws.frameworks.json.impl.JsonGeneratorImpl; import org.exoplatform.ws.frameworks.json.value.JsonValue; import javax.annotation.security.RolesAllowed; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.Serializable; import java.util.ArrayList; import java.util.Calendar; import java.util.List; /** * Created by The eXo Platform SAS * Author : Thibault Clement * tclement@exoplatform.com * 10/6/15 */ @Path(IndexingManagementRestServiceV1.BASE_VERSION_URI + IndexingManagementRestServiceV1.INDEXING_MANAGEMENT_URI) @RolesAllowed("administrators") @Api(value = IndexingManagementRestServiceV1.BASE_VERSION_URI + IndexingManagementRestServiceV1.INDEXING_MANAGEMENT_URI, description = "Entry point for Indexing Management resources", basePath = IndexingManagementRestServiceV1.BASE_VERSION_URI + IndexingManagementRestServiceV1.INDEXING_MANAGEMENT_URI) public class IndexingManagementRestServiceV1 implements ResourceContainer { public final static String BASE_VERSION_URI = "/v1"; public final static String INDEXING_MANAGEMENT_URI = "/indexingManagement"; public final static String CONNECTORS_URI = "/connectors"; public final static String OPERATIONS_URI = "/operations"; public final static String ERRORS_URI = "/errors"; private final static Log LOG = ExoLogger.getLogger(IndexingManagementRestServiceV1.class); private QueueIndexingService indexingService; private IndexingOperationProcessor indexingOperationProcessor; public IndexingManagementRestServiceV1(IndexingService indexingService, IndexingOperationProcessor indexingOperationProcessor) { this.indexingService = (QueueIndexingService) indexingService; this.indexingOperationProcessor = indexingOperationProcessor; } // Indexing Service Connectors @GET @Path(IndexingManagementRestServiceV1.CONNECTORS_URI) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed("administrators") @ApiOperation(value = "Return all Indexing Connectors") @ApiResponses(value = { @ApiResponse(code = 200, message = "Successful retrieval of all Indexing Connectors"), @ApiResponse(code = 500, message = "Can't generate JSON file") }) public Response getConnectors( @ApiParam(value = "The name of a JavaScript function to be used as the JSONP callback", required = false) @QueryParam("jsonp") String jsonp, @ApiParam(value = "Tell the service if it must return the size of the collection in the store", required = false) @QueryParam("returnSize") boolean returnSize) { //Get connectors List<IndexingServiceConnector> connectors = new ArrayList<>( indexingOperationProcessor.getConnectors().values()); CollectionResource<IndexingServiceConnector> connectorData; //Manage return size parameter if (returnSize) { int connectorNb = indexingOperationProcessor.getConnectors().size(); connectorData = new CollectionSizeResource<>(connectors, connectorNb); } else { connectorData = new CollectionResource<>(connectors); } Response.ResponseBuilder response; //Manage json-callback parameter if (StringUtils.isNotBlank(jsonp)) { try { response = buildJsonCallBack(connectorData, jsonp); } catch (JsonException e) { LOG.error(e); response = Response.status(HTTPStatus.INTERNAL_ERROR); } } else { response = Response.ok(connectorData, MediaType.APPLICATION_JSON); } return response.build(); } @GET @Path(IndexingManagementRestServiceV1.CONNECTORS_URI + "/{connectorType}") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed("administrators") @ApiOperation(value = "Return the Indexing Connectors with the specified Connector Type") @ApiResponses(value = { @ApiResponse(code = 200, message = "Successful retrieval of the Indexing Connector"), @ApiResponse(code = 404, message = "Indexing Connector with specified type Not Found"), @ApiResponse(code = 500, message = "Can't generate JSON file") }) public Response getConnector( @ApiParam(value = "Type of the Indexing Connector to retrieve", required = true) @PathParam("connectorType") String connectorType, @ApiParam(value = "The name of a JavaScript function to be used as the JSONP callback", required = false) @QueryParam("jsonp") String jsonp) { IndexingServiceConnector connector = indexingOperationProcessor.getConnectors().get(connectorType); if (connector == null) return Response.status(HTTPStatus.NOT_FOUND).build(); Response.ResponseBuilder response; //Manage json-callback parameter if (StringUtils.isNotBlank(jsonp)) { try { response = buildJsonCallBack(connector, jsonp); } catch (JsonException e) { LOG.error(e); response = Response.status(HTTPStatus.INTERNAL_ERROR); } } else { response = Response.ok(connector, MediaType.APPLICATION_JSON); } return response.build(); } @PUT @Path(IndexingManagementRestServiceV1.CONNECTORS_URI + "/{connectorType}") @Consumes(MediaType.APPLICATION_JSON) @RolesAllowed("administrators") @ApiOperation(value = "Update an Indexing Connector to enable / disable it") @ApiResponses(value = { @ApiResponse(code = 200, message = "Successful update of the Indexing Connector"), @ApiResponse(code = 404, message = "Indexing Connector with specified type Not Found") }) public Response updateConnector( @ApiParam(value = "Type of the Indexing Connector to update", required = true) @PathParam("connectorType") String connectorType, @ApiParam(value = "An Indexing Connector Resource", required = true) ConnectorResource connectorResource) { if (indexingOperationProcessor.getConnectors().get(connectorType) == null) { return Response.status(HTTPStatus.NOT_FOUND).build(); } indexingOperationProcessor.getConnectors().get(connectorType).setEnable(connectorResource.isEnable()); return Response.ok().build(); } // Indexing Operations @GET @Path(IndexingManagementRestServiceV1.OPERATIONS_URI) @Produces(MediaType.APPLICATION_JSON) @RolesAllowed("administrators") @ApiOperation(value = "Return all Indexing Operations") @ApiResponses(value = { @ApiResponse(code = 200, message = "Successful retrieval of all Indexing Operations"), @ApiResponse(code = 500, message = "Can't generate JSON file") }) public Response getOperations( @ApiParam(value = "The name of a JavaScript function to be used as the JSONP callback", required = false) @QueryParam("jsonp") String jsonp, @ApiParam(value = "The starting point when paging through a list of entities", required = false) @QueryParam("offset") int offset, @ApiParam(value = "The maximum number of results when paging through a list of entities. " + "If not specified or exceed the *query_limit* configuration of Indexing Management rest service, " + "it will use the *query_limit*", required = false) @QueryParam("limit") int limit, @ApiParam(value = "Tell the service if it must return the size of the collection in the store", required = false) @QueryParam("returnSize") boolean returnSize) { offset = parseOffset(offset); limit = parseLimit(limit); //Get operations List<IndexingOperation> operations = new ArrayList<>(indexingService.getOperations(offset, limit)); CollectionResource<IndexingOperation> operationData; //Manage return size parameter if (returnSize) { int operationNb = indexingService.getNumberOperations().intValue(); operationData = new CollectionSizeResource<>(operations, operationNb); } else { operationData = new CollectionResource<>(operations); } operationData.setLimit(limit); operationData.setOffset(offset); Response.ResponseBuilder response; //Manage json-callback parameter if (StringUtils.isNotBlank(jsonp)) { try { response = buildJsonCallBack(operationData, jsonp); } catch (JsonException e) { LOG.error(e); response = Response.status(HTTPStatus.INTERNAL_ERROR); } } else { response = Response.ok(operationData, MediaType.APPLICATION_JSON); } return response.build(); } @POST @Path(IndexingManagementRestServiceV1.OPERATIONS_URI) @Consumes(MediaType.APPLICATION_JSON) @RolesAllowed("administrators") @ApiOperation(value = "Add an Indexing Operation to the queue") @ApiResponses(value = { @ApiResponse(code = 201, message = "Indexing Operation successfully added"), @ApiResponse(code = 400, message = "The specified Indexing Operation is unknown") }) public Response addOperation( @ApiParam(value = "An Indexing Operation Resource", required = true) OperationResource operationResource) { switch (operationResource.getOperation()) { case "init": indexingService.init(operationResource.getEntityType()); break; case "index": indexingService.index(operationResource.getEntityType(), operationResource.getEntityId()); break; case "reindex": indexingService.reindex(operationResource.getEntityType(), operationResource.getEntityId()); break; case "unindex": indexingService.unindex(operationResource.getEntityType(), operationResource.getEntityId()); break; case "reindexAll": indexingService.reindexAll(operationResource.getEntityType()); break; case "unindexAll": indexingService.unindexAll(operationResource.getEntityType()); break; default: return getBadRequestResponse().build(); } return Response.status(HTTPStatus.CREATED).build(); } @DELETE @Path(IndexingManagementRestServiceV1.OPERATIONS_URI) @RolesAllowed("administrators") @ApiOperation(value = "Delete all Indexing Operation") @ApiResponses(value = { @ApiResponse(code = 200, message = "Successful deletion of all Indexing Operations") }) public Response deleteOperations() { indexingService.deleteAllOperations(); return Response.ok().build(); } @GET @Path(IndexingManagementRestServiceV1.OPERATIONS_URI + "/{operationId}") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed("administrators") @ApiOperation(value = "Return the Indexing Operation with the specified Opertion Id") @ApiResponses(value = { @ApiResponse(code = 200, message = "Successful retrieval of the Indexing Operation"), @ApiResponse(code = 404, message = "Indexing Operation with specified Id Not Found"), @ApiResponse(code = 500, message = "Can't generate JSON file") }) public Response getOperation( @ApiParam(value = "Id of the Indexing Operation to retrieve", required = true) @PathParam("operationId") String operationId, @ApiParam(value = "The name of a JavaScript function to be used as the JSONP callback", required = false) @QueryParam("jsonp") String jsonp) { IndexingOperation operation = indexingService.getOperation(operationId); if (operation == null) return Response.status(HTTPStatus.NOT_FOUND).build(); Response.ResponseBuilder response; //Manage json-callback parameter if (StringUtils.isNotBlank(jsonp)) { try { response = buildJsonCallBack(operation, jsonp); } catch (JsonException e) { LOG.error(e); response = Response.status(HTTPStatus.INTERNAL_ERROR); } } else { response = Response.ok(operation, MediaType.APPLICATION_JSON); } return response.build(); } @DELETE @Path(IndexingManagementRestServiceV1.OPERATIONS_URI + "/{operationId}") @RolesAllowed("administrators") @ApiOperation(value = "Delete a specified Indexing Operation") @ApiResponses(value = { @ApiResponse(code = 200, message = "Successful deletion of the Indexing Operations"), @ApiResponse(code = 404, message = "Indexing Operation with specified Id Not Found") }) public Response DeleteOperation( @ApiParam(value = "Id of the Indexing Operation to delete", required = true) @PathParam("operationId") String operationId) { IndexingOperation operation = indexingService.getOperation(operationId); if (operation == null) return Response.status(HTTPStatus.NOT_FOUND).build(); indexingService.deleteOperation(operation); return Response.ok().build(); } //TODO manage Bulk Operation // Indexing Errors //TODO implement Error REST Service // Utils method private Response.ResponseBuilder buildJsonCallBack(Serializable resource, String jsonp) throws JsonException { JsonValue value = new JsonGeneratorImpl().createJsonObject(resource); StringBuilder sb = new StringBuilder(jsonp); sb.append("(").append(value).append(");"); return Response.ok(sb.toString(), new MediaType("text", "javascript")); } /** * Doesn't allow limit parameter to exceed the default query_limit */ private int parseLimit(int limit) { return (limit <= 0 || limit > CollectionResource.QUERY_LIMIT) ? CollectionResource.QUERY_LIMIT : limit; } /** * Default offset is 0 */ private int parseOffset(int offset) { return (offset <= 0) ? 0 : offset; } private Response.ResponseBuilder getBadRequestResponse() { Calendar today = Calendar.getInstance(); if (today.get(Calendar.DAY_OF_MONTH) == 1 && today.get(Calendar.MONTH) == Calendar.APRIL) { return Response.status(418); } return Response.status(HTTPStatus.BAD_REQUEST); } }