/* * JBoss, Home of Professional Open Source * Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @authors tag. All rights reserved. */ package org.searchisko.api.rest; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.security.RolesAllowed; import javax.ejb.ObjectNotFoundException; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import org.searchisko.api.audit.annotation.Audit; import org.searchisko.api.audit.annotation.AuditId; import org.searchisko.api.audit.annotation.AuditIgnore; import org.searchisko.api.indexer.EsRiverJiraIndexerHandler; import org.searchisko.api.indexer.EsRiverRemoteIndexerHandler; import org.searchisko.api.indexer.IndexerHandler; import org.searchisko.api.rest.exception.BadFieldException; import org.searchisko.api.rest.exception.NotAuthenticatedException; import org.searchisko.api.rest.exception.NotAuthorizedException; import org.searchisko.api.rest.exception.RequiredFieldException; import org.searchisko.api.security.Role; import org.searchisko.api.service.AuthenticationUtilService; import org.searchisko.api.service.ProviderService; import org.searchisko.api.service.ProviderService.ProviderContentTypeInfo; import org.searchisko.api.util.SearchUtils; /** * REST API for Indexer related operations. * * @author Vlastimil Elias (velias at redhat dot com) */ @RequestScoped @Path("/indexer") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ Role.ADMIN, Role.PROVIDER }) @Audit public class IndexerRestService extends RestServiceBase { public static final String INDEXER_TYPE_ES_RIVER_REMOTE = "elasticsearch-river-remote"; public static final String INDEXER_TYPE_ES_RIVER_JIRA = "elasticsearch-river-jira"; @Inject protected ProviderService providerService; @Inject protected AuthenticationUtilService authenticationUtilService; @Inject protected EsRiverRemoteIndexerHandler esRiverRemoteIndexerHandler; @Inject protected EsRiverJiraIndexerHandler esRiverJiraIndexerHandler; @Context protected SecurityContext securityContext; /** * Force reindex for given content type using Searchisko internal indexer. * * @throws ObjectNotFoundException */ @POST @Path("/{type}/_force_reindex") public Response forceReindex(@PathParam("type") @AuditId String type) throws ObjectNotFoundException { Map<String, Object> ic = getIndexerConfigurationWithManagePermissionCheck(type); IndexerHandler ih = getIndexerHandler((String) ic.get(ProviderService.TYPE), type); try { ih.forceReindex(extractIndexerName(ic, type)); return Response.ok("Full reindex forced successfuly").build(); } catch (ObjectNotFoundException e) { throw new ObjectNotFoundException( "Indexer name or type is not configured correctly because indexer instance has not found for content type " + type); } } /** * Stop indexing for all content types using Searchisko internal indexer. * * @throws ObjectNotFoundException */ @POST @Path("/_all/_stop") public Map<String, String> stopAll() throws ObjectNotFoundException { Map<String, String> ret = new HashMap<>(); List<ProviderContentTypeInfo> allI = getAllIndexerConfigurationsWithManagePermissionCheck(); for (ProviderContentTypeInfo typeInfo : allI) { String typeName = typeInfo.getTypeName(); Map<String, Object> ic = ProviderService.extractIndexerConfiguration(typeInfo.getTypeDef(), typeName); IndexerHandler ih = getIndexerHandler((String) ic.get(ProviderService.TYPE), typeName); try { ih.stop(extractIndexerName(ic, typeName)); ret.put(typeName, "Indexer stopped successfuly"); } catch (ObjectNotFoundException e) { ret.put(typeName, "Indexer name or type is not configured correctly because indexer instance has not found"); } } return ret; } /** * Stop indexing for given content type using Searchisko internal indexer. * * @throws ObjectNotFoundException */ @POST @Path("/{type}/_stop") public Response stop(@PathParam("type") @AuditId String type) throws ObjectNotFoundException { Map<String, Object> ic = getIndexerConfigurationWithManagePermissionCheck(type); IndexerHandler ih = getIndexerHandler((String) ic.get(ProviderService.TYPE), type); try { ih.stop(extractIndexerName(ic, type)); return Response.ok("Indexer stopped successfuly").build(); } catch (ObjectNotFoundException e) { throw new ObjectNotFoundException( "Indexer name or type is not configured correctly because indexer instance has not found for content type " + type); } } /** * Restart indexing for all content types using Searchisko internal indexer. * * @throws ObjectNotFoundException */ @POST @Path("/_all/_restart") public Map<String, String> restartAll() throws ObjectNotFoundException { Map<String, String> ret = new HashMap<>(); List<ProviderContentTypeInfo> allI = getAllIndexerConfigurationsWithManagePermissionCheck(); for (ProviderContentTypeInfo typeInfo : allI) { String typeName = typeInfo.getTypeName(); Map<String, Object> ic = ProviderService.extractIndexerConfiguration(typeInfo.getTypeDef(), typeName); IndexerHandler ih = getIndexerHandler((String) ic.get(ProviderService.TYPE), typeName); try { ih.restart(extractIndexerName(ic, typeName)); ret.put(typeName, "Indexer restarted successfuly"); } catch (ObjectNotFoundException e) { ret.put(typeName, "Indexer name or type is not configured correctly because indexer instance has not found"); } } return ret; } /** * Restart indexing for given content type using Searchisko internal indexer. * * @throws ObjectNotFoundException */ @POST @Path("/{type}/_restart") public Response restart(@PathParam("type") @AuditId String type) throws ObjectNotFoundException { Map<String, Object> ic = getIndexerConfigurationWithManagePermissionCheck(type); IndexerHandler ih = getIndexerHandler((String) ic.get(ProviderService.TYPE), type); try { ih.restart(extractIndexerName(ic, type)); return Response.ok("Indexer restarted successfuly").build(); } catch (ObjectNotFoundException e) { throw new ObjectNotFoundException( "Indexer name or type is not configured correctly because indexer instance has not found for content type " + type); } } /** * Get status information for all Searchisko internal indexer you have permission to manage. * * @throws ObjectNotFoundException */ @GET @Path("/_all/_status") @AuditIgnore public Map<String, Object> statusAll() throws ObjectNotFoundException { Map<String, Object> ret = new HashMap<>(); List<ProviderContentTypeInfo> allI = getAllIndexerConfigurationsWithManagePermissionCheck(); for (ProviderContentTypeInfo typeInfo : allI) { String typeName = typeInfo.getTypeName(); Map<String, Object> ic = ProviderService.extractIndexerConfiguration(typeInfo.getTypeDef(), typeName); IndexerHandler ih = getIndexerHandler((String) ic.get(ProviderService.TYPE), typeName); try { ret.put(typeName, ih.getStatus(extractIndexerName(ic, typeName))); } catch (ObjectNotFoundException e) { ret.put(typeName, "Indexer name or type is not configured correctly because indexer instance has not found"); } } return ret; } /** * Get status information of indexer for given content type using Searchisko internal indexer. * * @throws ObjectNotFoundException */ @GET @Path("/{type}/_status") @AuditIgnore public Object getStatus(@PathParam("type") String type) throws ObjectNotFoundException { Map<String, Object> ic = getIndexerConfigurationWithManagePermissionCheck(type); IndexerHandler ih = getIndexerHandler((String) ic.get(ProviderService.TYPE), type); try { return ih.getStatus(extractIndexerName(ic, type)); } catch (ObjectNotFoundException e) { throw new ObjectNotFoundException( "Indexer name or type is not configured correctly because indexer instance has not found for content type " + type); } } /** * @param contentType of content we work for - used for error messages * @param ic indexer configuration to extract from * @return * @throws ObjectNotFoundException */ protected String extractIndexerName(Map<String, Object> ic, String contentType) throws ObjectNotFoundException { String indexerName = SearchUtils.trimToNull((String) ic.get(ProviderService.NAME)); if (indexerName == null) { throw new ObjectNotFoundException("Indexer name is not configured correctly for content type " + contentType); } return indexerName; } /** * Get indexer configuration for given content type with validations and permission check. * * @param contentType to get indexer configuration for. * @return indexer configuration structure, never null. * @throws ObjectNotFoundException if indexer configuration is not found for given content type * @throws NotAuthorizedException if user is not authorized * @throws NotAuthenticatedException if user is not authenticated * @see AuthenticationUtilService#checkProviderManagementPermission(String) */ protected Map<String, Object> getIndexerConfigurationWithManagePermissionCheck(String contentType) throws ObjectNotFoundException { if (contentType == null || SearchUtils.isBlank(contentType)) { throw new RequiredFieldException("type"); } ProviderContentTypeInfo typeInfo = providerService.findContentType(contentType); if (typeInfo == null) { throw new BadFieldException("type", "content type not found"); } authenticationUtilService.checkProviderManagementPermission(typeInfo.getProviderName()); Map<String, Object> ic = ProviderService.extractIndexerConfiguration(typeInfo.getTypeDef(), contentType); if (ic == null) { throw new ObjectNotFoundException("Indexer is not configured for content type " + contentType); } return ic; } /** * Get configuration of all indexers from all content types user has permission to manage (provider permission check). * * @return list of type infos with indexers, never null. * @see AuthenticationUtilService#checkProviderManagementPermission(String) */ protected List<ProviderContentTypeInfo> getAllIndexerConfigurationsWithManagePermissionCheck() { List<ProviderContentTypeInfo> ret = new ArrayList<>(); List<Map<String, Object>> allProviders = providerService.getAll(); if (allProviders != null) { for (Map<String, Object> providerDef : allProviders) { String providerName = (String) providerDef.get(ProviderService.NAME); try { authenticationUtilService.checkProviderManagementPermission(providerName); Map<String, Map<String, Object>> allCt = ProviderService.extractAllContentTypes(providerDef); if (allCt != null) { for (String typeName : allCt.keySet()) { Map<String, Object> typeDef = allCt.get(typeName); Map<String, Object> ic = ProviderService.extractIndexerConfiguration(typeDef, typeName); if (ic != null) { ret.add(new ProviderContentTypeInfo(providerDef, typeName)); } } } } catch (NotAuthorizedException e) { // OK, ignore it } } } return ret; } /** * Get indexer handler based on indexer type. * * @param indexerType to get handler for * @param contentType we handle indexer for - used for error messages only * @return indexer handler, never null. * @throws ObjectNotFoundException if indexer handler for passed in type doesn't exist. */ protected IndexerHandler getIndexerHandler(String indexerType, String contentType) throws ObjectNotFoundException { indexerType = SearchUtils.trimToNull(indexerType); if (indexerType == null) { throw new ObjectNotFoundException("Indexer type is not configured correctly for content type " + contentType); } if (INDEXER_TYPE_ES_RIVER_REMOTE.equals(indexerType)) { return esRiverRemoteIndexerHandler; } else if (INDEXER_TYPE_ES_RIVER_JIRA.equals(indexerType)) { return esRiverJiraIndexerHandler; } else { throw new ObjectNotFoundException("Unsupported indexer type '" + indexerType + "' configured for content type " + contentType); } } }