package eu.dnetlib.openaire.context; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import eu.dnetlib.openaire.common.AbstractExporterController; import eu.dnetlib.openaire.community.CommunityService; import eu.dnetlib.openaire.exporter.exceptions.CommunityException; import eu.dnetlib.openaire.exporter.exceptions.ResourceNotFoundException; import eu.dnetlib.openaire.exporter.model.community.CommunityType; import eu.dnetlib.openaire.exporter.model.community.SubCommunity; import eu.dnetlib.openaire.exporter.model.context.CategorySummary; import eu.dnetlib.openaire.exporter.model.context.ConceptSummary; import eu.dnetlib.openaire.exporter.model.context.ContextSummary; import eu.dnetlib.openaire.exporter.model.context.IISConfigurationEntry; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; @RestController @CrossOrigin(origins = { "*" }) @ConditionalOnProperty(value = "openaire.exporter.enable.community", havingValue = "true") @Tag(name = "OpenAIRE Context API", description = "the OpenAIRE Context API") public class ContextApiController extends AbstractExporterController { @Autowired private CommunityService communityService; private static final Log log = LogFactory.getLog(ContextApiController.class); @RequestMapping(value = "/contexts", produces = { "application/json" }, method = RequestMethod.GET) @Operation(summary = "list brief information about all the context profiles", description = "list brief information about all the context profiles") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "not found"), @ApiResponse(responseCode = "500", description = "unexpected error") }) public List listContexts(@RequestParam(required = false) final Set type) throws CommunityException { try { return communityService.listCommunities() .stream() .filter(c -> type == null || type.contains(c.getType())) .map(c -> { final ContextSummary ctx = new ContextSummary(); ctx.setId(c.getId()); ctx.setLabel(c.getName()); ctx.setStatus(c.getStatus().toString()); ctx.setType(c.getType().toString()); return ctx; }) .collect(Collectors.toList()); } catch (final ResourceNotFoundException e) { throw e; } catch (final Throwable e) { throw new CommunityException(e); } } @RequestMapping(value = "/context/{contextId}", produces = { "application/json" }, method = RequestMethod.GET) @Operation(summary = "list the categories defined within a context", description = "list the categories defined within a context") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "not found"), @ApiResponse(responseCode = "500", description = "unexpected error") }) public List listCategories( @PathVariable final String contextId, @RequestParam(required = false, defaultValue = "false") final boolean all) throws CommunityException { try { return communityService.getSubCommunities(contextId) .stream() .filter(sc -> all || sc.isClaim()) .map(sc -> { final String[] parts = StringUtils.split(sc.getSubCommunityId(), "::"); if (parts.length < 3) { throw new RuntimeException("Invalid conceptId (It should have 3 (or more) parts): " + sc.getSubCommunityId()); } final CategorySummary cat = new CategorySummary(); cat.setId(parts[0] + "::" + parts[1]); cat.setLabel(sc.getCategory()); cat.setHasConcept(true); return cat; }) .distinct() .collect(Collectors.toList()); } catch (final ResourceNotFoundException e) { throw e; } catch (final Throwable e) { throw new CommunityException(e); } } @RequestMapping(value = "/context/iis/conf/{contextId}", produces = { "application/json" }, method = RequestMethod.GET) @Operation(summary = "return a list of entries for IIS", description = "return a list of entries for IIS") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "not found"), @ApiResponse(responseCode = "500", description = "unexpected error") }) public List getIISConfiguration(@PathVariable final String contextId) throws CommunityException { try { return communityService.getIISConfiguration(contextId); } catch (final ResourceNotFoundException e) { throw e; } catch (final Throwable e) { throw new CommunityException(e); } } @RequestMapping(value = "/context/category/{categoryId}", produces = { "application/json" }, method = RequestMethod.GET) @Operation(summary = "list the concepts defined within a category", description = "list the concepts defined within a category") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "not found"), @ApiResponse(responseCode = "500", description = "unexpected error") }) public List listConcepts( @PathVariable final String categoryId, @RequestParam(required = false, defaultValue = "false") final boolean all) throws CommunityException { try { final String[] parts = StringUtils.split(categoryId, "::"); if (parts.length != 2) { log.error("Invalid category id (it should have 2 parts): " + categoryId); throw new CommunityException("Invalid category id (it should have 2 parts): " + categoryId); } final String contextId = parts[0]; final List list = findSubCommunities(categoryId + "::", all, contextId); return processSubCommunities(null, list); } catch (final ResourceNotFoundException e) { throw e; } catch (final Throwable e) { throw new CommunityException(e); } } @RequestMapping(value = "/context/category/concept/{conceptId}", produces = { "application/json" }, method = RequestMethod.GET) @Operation(summary = "list the concepts defined within a category", description = "list the concepts defined within a category") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "not found"), @ApiResponse(responseCode = "500", description = "unexpected error") }) public List listSubConcepts( @PathVariable final String conceptId, @RequestParam(required = false, defaultValue = "false") final boolean all) throws CommunityException { try { final String[] parts = StringUtils.split(conceptId, "::"); if (parts.length < 3) { log.error("Invalid concept id (it should have 3 (or more) parts): " + conceptId); throw new CommunityException("Invalid concept id (it should have 3 (or more) parts): " + conceptId); } final String contextId = parts[0]; final List list = findSubCommunities(conceptId + "::", all, contextId); return processSubCommunities(conceptId, list); } catch (final ResourceNotFoundException e) { throw e; } catch (final Throwable e) { throw new CommunityException(e); } } private List findSubCommunities(final String prefix, final boolean all, final String contextId) throws CommunityException { return communityService.getSubCommunities(contextId) .stream() .filter(sc -> all || sc.isClaim()) .filter(sc -> sc.getSubCommunityId().startsWith(prefix)) .collect(Collectors.toList()); } private List processSubCommunities(final String parent, final List list) { return list.stream() .filter(sc -> Objects.equals(sc.getParent(), parent)) .map(sc -> { final List childs = processSubCommunities(sc.getSubCommunityId(), list); final ConceptSummary concept = new ConceptSummary(); concept.setId(sc.getSubCommunityId()); concept.setLabel(sc.getLabel()); concept.setHasSubConcept(!childs.isEmpty()); concept.setConcept(childs); return concept; }) .collect(Collectors.toList()); } }