/******************************************************************************* * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2015-2019) * * contact.vitam@culture.gouv.fr * * This software is a computer program whose purpose is to implement a digital archiving back-office system managing * high volumetry securely and efficiently. * * This software is governed by the CeCILL 2.1 license under French law and abiding by the rules of distribution of free * software. You can use, modify and/ or redistribute the software under the terms of the CeCILL 2.1 license as * circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". * * As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license, * users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the * successive licensors have only limited liability. * * In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or * developing or reproducing the software by the user in light of its specific status of free software, that may mean * that it is complicated to manipulate, and that also therefore means that it is reserved for developers and * experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the * software's suitability as regards their requirements in conditions enabling the security of their systems and/or data * to be ensured and, more generally, to use and operate it in the same conditions as regards security. * * The fact that you are presently reading this means that you have had knowledge of the CeCILL 2.1 license and that you * accept its terms. *******************************************************************************/ package fr.gouv.vitam.functional.administration.rest; import static fr.gouv.vitam.common.database.builder.query.QueryHelper.and; import static fr.gouv.vitam.common.database.builder.query.QueryHelper.eq; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.ws.rs.Consumes; 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.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import com.fasterxml.jackson.databind.JsonNode; import fr.gouv.vitam.common.ParametersChecker; import fr.gouv.vitam.common.database.builder.query.BooleanQuery; import fr.gouv.vitam.common.database.builder.request.exception.InvalidCreateOperationException; import fr.gouv.vitam.common.database.builder.request.single.Select; import fr.gouv.vitam.common.database.server.mongodb.MongoDbAccess; import fr.gouv.vitam.common.exception.InvalidParseOperationException; import fr.gouv.vitam.common.json.JsonHandler; import fr.gouv.vitam.common.logging.VitamLogger; import fr.gouv.vitam.common.logging.VitamLoggerFactory; import fr.gouv.vitam.common.model.RequestResponseOK; import fr.gouv.vitam.common.security.SanityChecker; import fr.gouv.vitam.common.server.application.configuration.DbConfigurationImpl; import fr.gouv.vitam.common.server.application.resources.ApplicationStatusResource; import fr.gouv.vitam.common.server.application.resources.BasicVitamStatusServiceImpl; import fr.gouv.vitam.common.stream.StreamUtils; import fr.gouv.vitam.functional.administration.accession.register.core.ReferentialAccessionRegisterImpl; import fr.gouv.vitam.functional.administration.common.AccessionRegisterDetail; import fr.gouv.vitam.functional.administration.common.AccessionRegisterSummary; import fr.gouv.vitam.functional.administration.common.FileFormat; import fr.gouv.vitam.functional.administration.common.FileRules; import fr.gouv.vitam.functional.administration.common.exception.DatabaseConflictException; import fr.gouv.vitam.functional.administration.common.exception.FileRulesException; import fr.gouv.vitam.functional.administration.common.exception.ReferentialException; import fr.gouv.vitam.functional.administration.common.exception.ReferentialNotFoundException; import fr.gouv.vitam.functional.administration.common.server.AdminManagementConfiguration; import fr.gouv.vitam.functional.administration.common.server.ElasticsearchAccessAdminFactory; import fr.gouv.vitam.functional.administration.common.server.ElasticsearchAccessFunctionalAdmin; import fr.gouv.vitam.functional.administration.common.server.MongoDbAccessAdminFactory; import fr.gouv.vitam.functional.administration.common.server.MongoDbAccessAdminImpl; import fr.gouv.vitam.functional.administration.format.core.ReferentialFormatFileImpl; import fr.gouv.vitam.functional.administration.rules.core.RulesManagerFileImpl; /** * FormatManagementResourceImpl implements AccessResource */ @Path("/adminmanagement/v1") @javax.ws.rs.ApplicationPath("webresources") public class AdminManagementResource extends ApplicationStatusResource { private static final String SELECT_IS_A_MANDATORY_PARAMETER = "select is a mandatory parameter"; private static final VitamLogger LOGGER = VitamLoggerFactory.getInstance(AdminManagementResource.class); private final MongoDbAccessAdminImpl mongoAccess; private final ElasticsearchAccessFunctionalAdmin elasticsearchAccess; /** * Constructor * * @param configuration config for constructing AdminManagement */ public AdminManagementResource(AdminManagementConfiguration configuration) { super(new BasicVitamStatusServiceImpl(), configuration.getTenants()); DbConfigurationImpl adminConfiguration; if (configuration.isDbAuthentication()) { adminConfiguration = new DbConfigurationImpl(configuration.getMongoDbNodes(), configuration.getDbName(), true, configuration.getDbUserName(), configuration.getDbPassword()); } else { adminConfiguration = new DbConfigurationImpl(configuration.getMongoDbNodes(), configuration.getDbName()); } elasticsearchAccess = ElasticsearchAccessAdminFactory.create(configuration); mongoAccess = MongoDbAccessAdminFactory.create(adminConfiguration); LOGGER.debug("init Admin Management Resource server"); } MongoDbAccess getLogbookDbAccess() { return mongoAccess; } /** * @return the elasticsearchAccess */ ElasticsearchAccessFunctionalAdmin getElasticsearchAccess() { return elasticsearchAccess; } /** * check the file format * * @param xmlPronom as InputStream * @return Response response jersey */ @Path("format/check") @POST @Consumes(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_JSON) public Response checkFormat(InputStream xmlPronom) { ParametersChecker.checkParameter("xmlPronom is a mandatory parameter", xmlPronom); try (ReferentialFormatFileImpl formatManagement = new ReferentialFormatFileImpl(mongoAccess)) { formatManagement.checkFile(xmlPronom); return Response.status(Status.OK).build(); } catch (final ReferentialException e) { LOGGER.error(e); return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); } catch (final Exception e) { LOGGER.error(e); return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); } finally { StreamUtils.closeSilently(xmlPronom); } } /** * import the file format * * @param xmlPronom as InputStream * @return Response jersey response */ @Path("format/import") @POST @Consumes(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_JSON) public Response importFormat(InputStream xmlPronom) { ParametersChecker.checkParameter("xmlPronom is a mandatory parameter", xmlPronom); try (ReferentialFormatFileImpl formatManagement = new ReferentialFormatFileImpl(mongoAccess)) { formatManagement.importFile(xmlPronom); return Response.status(Status.CREATED).entity(Status.CREATED.getReasonPhrase()).build(); } catch (final ReferentialException e) { LOGGER.error(e); final Status status = Status.BAD_REQUEST; return Response.status(status) .entity(e.getMessage()) .build(); } catch (final DatabaseConflictException e) { LOGGER.error(e); return Response.status(Status.CONFLICT).entity(e.getMessage()).build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status) .entity(status) .build(); } finally { StreamUtils.closeSilently(xmlPronom); } } /** * Find the file format detail related to a specified Id * * * @param formatId path param as String * @return Response jersey response * @throws InvalidParseOperationException * @throws IOException when error json occurs */ @POST @Path("format/{id_format}") @Produces(MediaType.APPLICATION_JSON) public Response findFileFormatByID(@PathParam("id_format") String formatId) throws InvalidParseOperationException, IOException { ParametersChecker.checkParameter("formatId is a mandatory parameter", formatId); FileFormat fileFormat = null; try (ReferentialFormatFileImpl formatManagement = new ReferentialFormatFileImpl(mongoAccess)) { SanityChecker.checkJsonAll(JsonHandler.toJsonNode(formatId)); fileFormat = formatManagement.findDocumentById(formatId); if (fileFormat == null) { throw new ReferentialException("NO DATA for the specified formatId"); } return Response.status(Status.OK).entity(new RequestResponseOK() .setHits(1, 0, 1) .addResult(JsonHandler.toJsonNode(fileFormat))).build(); } catch (final ReferentialException e) { LOGGER.error(e); final Status status = Status.NOT_FOUND; return Response.status(status).build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status).entity(status).build(); } } /** * retrieve all the file format inserted in the collection fileFormat * * @param select as String * @return Response jersay Response * @throws IOException when error json occurs * @throws InvalidParseOperationException when error json occurs */ @Path("format/document") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response findFormats(JsonNode select) throws InvalidParseOperationException, IOException { ParametersChecker.checkParameter(SELECT_IS_A_MANDATORY_PARAMETER, select); List<FileFormat> fileFormatList = new ArrayList<>(); try (ReferentialFormatFileImpl formatManagement = new ReferentialFormatFileImpl(mongoAccess)) { SanityChecker.checkJsonAll(select); fileFormatList = formatManagement.findDocuments(select); final RequestResponseOK responseEntity = new RequestResponseOK() .setHits(fileFormatList.size(), 0, fileFormatList.size()) .setQuery(select); for (final FileFormat format : fileFormatList) { responseEntity.addResult(JsonHandler.toJsonNode(format)); } return Response.status(Status.OK) .entity(responseEntity).build(); } catch (final InvalidParseOperationException e) { LOGGER.error(e); return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); } catch (final ReferentialException e) { LOGGER.error(e); final Status status = Status.NOT_FOUND; return Response.status(status).build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status).entity(status).build(); } } /** * check the rules file * * * * @param rulesStream as InputStream * @return Response response jersey * @throws IOException * @throws InvalidCreateOperationException * @throws InvalidParseOperationException * @throws ReferentialException */ @Path("rules/check") @POST @Consumes(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_JSON) public Response checkRulesFile(InputStream rulesStream) throws IOException, ReferentialException, InvalidParseOperationException, InvalidCreateOperationException { ParametersChecker.checkParameter("rulesStream is a mandatory parameter", rulesStream); try (RulesManagerFileImpl rulesManagerFileImpl = new RulesManagerFileImpl(mongoAccess)) { rulesManagerFileImpl.checkFile(rulesStream); return Response.status(Status.OK).build(); } catch (final FileRulesException e) { LOGGER.error(e); return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); } catch (final Exception e) { LOGGER.error(e); return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); } finally { StreamUtils.closeSilently(rulesStream); } } /** * import the rules file * * @param rulesStream as InputStream * @return Response jersey response * @throws IOException when error json occurs * @throws InvalidParseOperationException when error json occurs * @throws ReferentialException */ @Path("rules/import") @POST @Consumes(MediaType.APPLICATION_OCTET_STREAM) @Produces(MediaType.APPLICATION_JSON) public Response importRulesFile(InputStream rulesStream) throws InvalidParseOperationException, ReferentialException, IOException { ParametersChecker.checkParameter("rulesStream is a mandatory parameter", rulesStream); try (RulesManagerFileImpl rulesFileManagement = new RulesManagerFileImpl(mongoAccess)) { rulesFileManagement.importFile(rulesStream); return Response.status(Status.CREATED).entity(Status.CREATED.getReasonPhrase()).build(); } catch (final FileRulesException e) { LOGGER.error(e); return Response.status(Status.BAD_REQUEST).entity(e.getMessage()) .build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status).entity(status.getReasonPhrase()).build(); } finally { StreamUtils.closeSilently(rulesStream); } } /** * findRuleByID : find the rules details based on a given Id * * @param ruleId path param as String * @return Response jersey response * @throws InvalidParseOperationException * @throws IOException when error json occurs * @throws ReferentialException * @throws InvalidCreateOperationException */ @POST @Path("rules/{id_rule}") @Produces(MediaType.APPLICATION_JSON) public Response findRuleByID(@PathParam("id_rule") String ruleId) throws InvalidParseOperationException, IOException, ReferentialException, InvalidCreateOperationException { ParametersChecker.checkParameter("ruleId is a mandatory parameter", ruleId); List<FileRules> fileRules = null; JsonNode result = null; try (RulesManagerFileImpl rulesFileManagement = new RulesManagerFileImpl(mongoAccess)) { SanityChecker.checkJsonAll(JsonHandler.toJsonNode(ruleId)); result = findRulesByRuleValueQueryBuilder(ruleId); fileRules = rulesFileManagement.findDocuments(result); if (fileRules == null || fileRules.size() > 1) { throw new FileRulesException("NO DATA for the specified rule Value or More than one records exists"); } return Response.status(Status.OK).entity(new RequestResponseOK() .setHits(1, 0, 1) .addResult(JsonHandler.toJsonNode(fileRules.get(0)))).build(); } catch (final FileRulesException e) { LOGGER.error(e); final Status status = Status.NOT_FOUND; return Response.status(status).build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status).entity(status).build(); } } /** * findRulesByRuleValueQueryBuilder: build a dsl query based on a RuleId and order the result * * @param rulesValue * @return * @throws InvalidCreateOperationException * @throws InvalidParseOperationException */ private JsonNode findRulesByRuleValueQueryBuilder(String rulesId) throws InvalidCreateOperationException, InvalidParseOperationException { JsonNode result; final Select select = new Select(); select.addOrderByDescFilter(rulesId); final BooleanQuery query = and(); query.add(eq("RuleId", rulesId)); select.setQuery(query); result = select.getFinalSelect(); return result; } /** * show all file rules inserted in the collection fileRules * * @param select as String * @return Response jersey Response * @throws IOException when error json occurs * @throws InvalidParseOperationException when error json occurs */ @Path("rules/document") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response findDocumentRules(JsonNode select) throws InvalidParseOperationException, IOException { ParametersChecker.checkParameter(SELECT_IS_A_MANDATORY_PARAMETER, select); List<FileRules> filerulesList = new ArrayList<>(); try (RulesManagerFileImpl rulesFileManagement = new RulesManagerFileImpl(mongoAccess)) { SanityChecker.checkJsonAll(select); filerulesList = rulesFileManagement.findDocuments(select); final RequestResponseOK responseEntity = new RequestResponseOK() .setHits(filerulesList.size(), 0, filerulesList.size()) .setQuery(select); for (final FileRules rule : filerulesList) { responseEntity.addResult(JsonHandler.toJsonNode(rule)); } return Response.status(Status.OK) .entity(responseEntity) .build(); } catch (final InvalidParseOperationException e) { LOGGER.error(e); return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); } catch (final ReferentialException e) { LOGGER.error(e); final Status status = Status.NOT_FOUND; return Response.status(status).build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status).entity(status).build(); } } /** * create or update an accession register * * @param accessionRegister AccessionRegisterDetail object * @return Response jersey response */ @Path("accession-register") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response createAccessionRegister(AccessionRegisterDetail accessionRegister) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("register ID / Originating Agency: " + accessionRegister.getId() + " / " + accessionRegister.getOriginatingAgency()); } ParametersChecker.checkParameter("Accession Register is a mandatory parameter", accessionRegister); try (ReferentialAccessionRegisterImpl accessionRegisterManagement = new ReferentialAccessionRegisterImpl(mongoAccess)) { accessionRegisterManagement.createOrUpdateAccessionRegister(accessionRegister); return Response.status(Status.CREATED).build(); } catch (final ReferentialException e) { LOGGER.error(e); return Response.status(Status.PRECONDITION_FAILED).entity(Status.PRECONDITION_FAILED).build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status).entity(status).build(); } } /** * retrieve all accession summary from accession summary collection * * @param select as String * @return Response jersay Response * @throws IOException when error json occurs * @throws InvalidParseOperationException when error json occurs * @throws ReferentialException */ @Path("accession-register/document") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response findDocumentFundsRegister(JsonNode select) throws InvalidParseOperationException, IOException, ReferentialException { ParametersChecker.checkParameter(SELECT_IS_A_MANDATORY_PARAMETER, select); List<AccessionRegisterSummary> fileFundRegisters = new ArrayList<>(); try (ReferentialAccessionRegisterImpl accessionRegisterManagement = new ReferentialAccessionRegisterImpl(mongoAccess)) { SanityChecker.checkJsonAll(select); fileFundRegisters = accessionRegisterManagement.findDocuments(select); } catch (final InvalidParseOperationException e) { LOGGER.error(e); return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); } catch (final ReferentialNotFoundException e) { LOGGER.error(e); final Status status = Status.NOT_FOUND; return Response.status(status).entity(status).build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status).entity(status).build(); } return Response.status(Status.OK) .entity(new RequestResponseOK() .setHits(fileFundRegisters.size(), 0, fileFundRegisters.size()) .setQuery(select) .addAllResults(fileFundRegisters)) .build(); } /** * retrieve accession register detail based on a given dsl query * * * @param select as String * @return Response jersay Response * @throws IOException when error json occurs * @throws InvalidParseOperationException when error json occurs * @throws ReferentialException */ @Path("accession-register/detail") @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response findDetailAccessionRegister(JsonNode select) throws InvalidParseOperationException, IOException, ReferentialException { ParametersChecker.checkParameter(SELECT_IS_A_MANDATORY_PARAMETER, select); List<AccessionRegisterDetail> fileAccessionRegistersDetail = new ArrayList<>(); try (ReferentialAccessionRegisterImpl accessionRegisterManagement = new ReferentialAccessionRegisterImpl(mongoAccess)) { SanityChecker.checkJsonAll(select); fileAccessionRegistersDetail = accessionRegisterManagement.findDetail(select); } catch (final InvalidParseOperationException e) { LOGGER.error(e); return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build(); } catch (final ReferentialNotFoundException e) { LOGGER.error(e); final Status status = Status.NOT_FOUND; return Response.status(status).entity(status).build(); } catch (final Exception e) { LOGGER.error(e); final Status status = Status.INTERNAL_SERVER_ERROR; return Response.status(status).entity(status).build(); } return Response.status(Status.OK) .entity(new RequestResponseOK() .setHits(fileAccessionRegistersDetail.size(), 0, fileAccessionRegistersDetail.size()) .setQuery(select) .addAllResults(fileAccessionRegistersDetail)) .build(); } }