MetadataApi { @ApiOperation( value = "Get a metadata record as ZIP", notes = "Metadata Exchange Format (MEF) is returned. MEF is a ZIP file containing " + "the metadata as XML and some others files depending on the version requested. " + "See http: nickname = "getRecordAsZip") @RequestMapping(value = "/{metadataUuid}/formatters/zip", method = RequestMethod.GET, consumes = { MediaType.ALL_VALUE }, produces = { "application/zip", MEF_V1_ACCEPT_TYPE, MEF_V2_ACCEPT_TYPE }) @ApiResponses(value = { @ApiResponse(code = 200, message = "Return the record."), @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW) }) public @ResponseBody void getRecordAsZip( @ApiParam( value = API_PARAM_RECORD_UUID, required = true) @PathVariable String metadataUuid, @ApiParam( value = "MEF file format.", required = false) @RequestParam( required = false, defaultValue = "FULL") MEFLib.Format format, @ApiParam( value = "With related records (parent and service).", required = false) @RequestParam( required = false, defaultValue = "true") boolean withRelated, @ApiParam( value = "Resolve XLinks in the records.", required = false) @RequestParam( required = false, defaultValue = "true") boolean withXLinksResolved, @ApiParam( value = "Preserve XLink URLs in the records.", required = false) @RequestParam( required = false, defaultValue = "false") boolean withXLinkAttribute, @RequestParam( required = false, defaultValue = "true") boolean addSchemaLocation, @ApiParam(value = "Download the approved version", required = false) @RequestParam(required = false, defaultValue = "true") boolean approved, @RequestHeader( value = HttpHeaders.ACCEPT, defaultValue = "application/x-gn-mef-2-zip" ) String acceptHeader, HttpServletResponse response, HttpServletRequest request ) throws Exception { AbstractMetadata metadata; try { metadata = ApiUtils.canViewRecord(metadataUuid, request); } catch (SecurityException e) { Log.debug(API.LOG_MODULE_NAME, e.getMessage(), e); throw new NotAllowedException(ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW); } Path stylePath = dataDirectory.getWebappDir().resolve(Geonet.Path.SCHEMAS); Path file = null; ServiceContext context = ApiUtils.createServiceContext(request); MEFLib.Version version = MEFLib.Version.find(acceptHeader); if (version == MEFLib.Version.V1) { boolean skipUUID = false; Integer id = -1; if (approved) { id = metadataRepository.findOneByUuid(metadataUuid).getId(); } else { id = metadataUtils.findOneByUuid(metadataUuid).getId(); } file = MEFLib.doExport( context, id, format.toString(), skipUUID, withXLinksResolved, withXLinkAttribute, addSchemaLocation ); response.setContentType(MEFLib.Version.Constants.MEF_V1_ACCEPT_TYPE); } else { Set<String> tmpUuid = new HashSet<String>(); tmpUuid.add(metadataUuid); if (withRelated) { Element childRequest = new Element("request"); childRequest.addContent(new Element("parentUuid").setText(metadataUuid)); childRequest.addContent(new Element("to").setText("1000")); Set<String> childs = MetadataUtils.getUuidsToExport( metadataUuid, request, childRequest); if (childs.size() != 0) { tmpUuid.addAll(childs); } Element servicesRequest = new Element(Jeeves.Elem.REQUEST); servicesRequest.addContent(new Element( org.fao.geonet.constants.Params.OPERATES_ON) .setText(metadataUuid)); servicesRequest.addContent(new Element( org.fao.geonet.constants.Params.TYPE) .setText("service")); Set<String> services = MetadataUtils.getUuidsToExport( metadataUuid, request, servicesRequest); if (services.size() != 0) { tmpUuid.addAll(services); } } Log.info(Geonet.MEF, "Building MEF2 file with " + tmpUuid.size() + " records."); file = MEFLib.doMEF2Export(context, tmpUuid, format.toString(), false, stylePath, withXLinksResolved, withXLinkAttribute, false, addSchemaLocation, approved); response.setContentType(MEFLib.Version.Constants.MEF_V2_ACCEPT_TYPE); } response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format( "inline; filename=\"%s.zip\"", metadata.getUuid() )); response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(Files.size(file))); FileUtils.copyFile(file.toFile(), response.getOutputStream()); }  synchronized void setApplicationContext(ApplicationContext context); @ApiOperation(value = "Get a metadata record", notes = "Depending on the accept header the appropriate formatter is used. " + "When requesting a ZIP, a MEF version 2 file is returned. " + "When requesting HTML, the default formatter is used.", nickname = "getRecord") @RequestMapping(value = "/{metadataUuid:.+}", method = RequestMethod.GET, consumes = { MediaType.ALL_VALUE }, produces = { MediaType.TEXT_HTML_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_XHTML_XML_VALUE, MediaType.APPLICATION_JSON_VALUE, "application/pdf", "application/zip", MEF_V1_ACCEPT_TYPE, MEF_V2_ACCEPT_TYPE, MediaType.ALL_VALUE }) @ApiResponses(value = { @ApiResponse(code = 200, message = "Return the record."), @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW), @ApiResponse(code = 404, message = ApiParams.API_RESPONSE_RESOURCE_NOT_FOUND) }) String getRecord(
        @ApiParam(value = API_PARAM_RECORD_UUID,
            required = true)
        @PathVariable
            String metadataUuid,
        @ApiParam(value = "Accept header should indicate which is the appropriate format " +
            "to return. It could be text/html, application/xml, application/zip, ..." +
            "If no appropriate Accept header found, the XML format is returned.",
            required = true)
        @RequestHeader(
            value = HttpHeaders.ACCEPT,
            defaultValue = MediaType.APPLICATION_XML_VALUE,
            required = false
        )
            String acceptHeader,
        HttpServletResponse response,
        HttpServletRequest request
    ); @ApiOperation(value = "Get a metadata record as XML or JSON", notes = "", nickname = "getRecordAsXmlOrJSON") @RequestMapping(value = { "/{metadataUuid}/formatters/xml", "/{metadataUuid}/formatters/json" }, method = RequestMethod.GET, produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE + "; charset=utf-8" }) @ApiResponses(value = { @ApiResponse(code = 200, message = "Return the record."), @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW) }) @ResponseBody Object getRecordAsXML(
        @ApiParam(
            value = API_PARAM_RECORD_UUID,
            required = true)
        @PathVariable
            String metadataUuid,
        @ApiParam(value = "Add XSD schema location based on standard configuration " +
            "(see schema-ident.xml).",
            required = false)
        @RequestParam(required = false, defaultValue = "true")
            boolean addSchemaLocation,
        @ApiParam(value = "Increase record popularity",
            required = false)
        @RequestParam(required = false, defaultValue = "true")
            boolean increasePopularity,
        @ApiParam(value = "Add geonet:info details",
            required = false)
        @RequestParam(required = false, defaultValue = "false")
            boolean withInfo,
        @ApiParam(value = "Download as a file",
            required = false)
        @RequestParam(required = false, defaultValue = "false")
            boolean attachment,
        @ApiParam(value = "Download the approved version",
            required = false, defaultValue = "true")
        @RequestParam(required = false, defaultValue = "true")
            boolean approved,
        @RequestHeader(
            value = HttpHeaders.ACCEPT,
            defaultValue = MediaType.APPLICATION_XML_VALUE
        )
            String acceptHeader,
        HttpServletResponse response,
        HttpServletRequest request
    ); @ApiOperation( value = "Get a metadata record as ZIP", notes = "Metadata Exchange Format (MEF) is returned. MEF is a ZIP file containing " + "the metadata as XML and some others files depending on the version requested. " + "See http://geonetwork-opensource.org/manuals/trunk/eng/users/annexes/mef-format.html.", nickname = "getRecordAsZip") @RequestMapping(value = "/{metadataUuid}/formatters/zip", method = RequestMethod.GET, consumes = { MediaType.ALL_VALUE }, produces = { "application/zip", MEF_V1_ACCEPT_TYPE, MEF_V2_ACCEPT_TYPE }) @ApiResponses(value = { @ApiResponse(code = 200, message = "Return the record."), @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW) }) @ResponseBody void getRecordAsZip(
        @ApiParam(
            value = API_PARAM_RECORD_UUID,
            required = true)
        @PathVariable
            String metadataUuid,
        @ApiParam(
            value = "MEF file format.",
            required = false)
        @RequestParam(
            required = false,
            defaultValue = "FULL")
            MEFLib.Format format,
        @ApiParam(
            value = "With related records (parent and service).",
            required = false)
        @RequestParam(
            required = false,
            defaultValue = "true")
            boolean withRelated,
        @ApiParam(
            value = "Resolve XLinks in the records.",
            required = false)
        @RequestParam(
            required = false,
            defaultValue = "true")
            boolean withXLinksResolved,
        @ApiParam(
            value = "Preserve XLink URLs in the records.",
            required = false)
        @RequestParam(
            required = false,
            defaultValue = "false")
            boolean withXLinkAttribute,
        @RequestParam(
            required = false,
            defaultValue = "true")
            boolean addSchemaLocation,
        @ApiParam(value = "Download the approved version",
            required = false)
        @RequestParam(required = false, defaultValue = "true")
            boolean approved,
        @RequestHeader(
            value = HttpHeaders.ACCEPT,
            defaultValue = "application/x-gn-mef-2-zip"
        )
            String acceptHeader,
        HttpServletResponse response,
        HttpServletRequest request
    ); @ApiOperation(value = "Increase record popularity", notes = "Used when a view is based on the search results content and does not really access the record. Record is then added to the indexing queue and popularity will be updated soon.", nickname = "increaseRecordPopularity") @RequestMapping(value = "/{metadataUuid:.+}/popularity", method = RequestMethod.POST, consumes = { MediaType.ALL_VALUE }) @ApiResponses(value = { @ApiResponse(code = 201, message = "Popularity updated."), @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW), @ApiResponse(code = 404, message = ApiParams.API_RESPONSE_RESOURCE_NOT_FOUND) }) @ResponseStatus(HttpStatus.CREATED) void getRecord(
        @ApiParam(value = API_PARAM_RECORD_UUID,
            required = true)
        @PathVariable
            String metadataUuid,
        HttpServletRequest request
    ); @ApiOperation( value = "Get record related resources", nickname = "getAssociated", notes = "Retrieve related services, datasets, onlines, thumbnails, sources, ... " + "to this records.<br/>" + "<a href='http://geonetwork-opensource.org/manuals/trunk/eng/users/user-guide/associating-resources/index.html'>More info</a>") @RequestMapping(value = "/{metadataUuid:.+}/related", method = RequestMethod.GET, produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }) @ResponseStatus(HttpStatus.OK) @ApiResponses(value = { @ApiResponse(code = 200, message = "Return the associated resources."), @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW) }) @ResponseBody RelatedResponse getRelated(
        @ApiParam(
            value = API_PARAM_RECORD_UUID,
            required = true)
        @PathVariable
            String metadataUuid,
        @ApiParam(value = "Type of related resource. If none, all resources are returned.",
            required = false
        )
        @RequestParam(defaultValue = "")
            RelatedItemType[] type,
        @ApiParam(value = "Start offset for paging. Default 1. Only applies to related metadata records (ie. not for thumbnails).",
            required = false
        )
        @RequestParam(defaultValue = "1")
            int start,
        @ApiParam(value = "Number of rows returned. Default 100.")
        @RequestParam(defaultValue = "100")
            int rows,
        HttpServletRequest request); @ApiOperation( value = "Returns a map to decode attributes in a dataset (from the associated feature catalog)", nickname = "getFeatureCatalog", notes = "Retrieve related services, datasets, onlines, thumbnails, sources, ... " + "to this records.<br/>" + "<a href='http://geonetwork-opensource.org/manuals/trunk/eng/users/user-guide/associating-resources/index.html'>More info</a>") @RequestMapping(value = "/{metadataUuid}/featureCatalog", method = RequestMethod.GET, produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }) @ResponseStatus(HttpStatus.OK) @ApiResponses(value = { @ApiResponse(code = 200, message = "Return the associated resources."), @ApiResponse(code = 403, message = ApiParams.API_RESPONSE_NOT_ALLOWED_CAN_VIEW) }) @ResponseBody FeatureResponse getFeatureCatalog(
        @ApiParam(
            value = API_PARAM_RECORD_UUID,
            required = true)
        @PathVariable
            String metadataUuid,
        HttpServletRequest request);  }
@Test public void getRecordAsZip() throws Exception { final String zipMagicNumber = "PK\u0003\u0004"; MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); MockHttpSession mockHttpSession = loginAsAdmin(); mockMvc.perform(get("/srv/api/records/" + this.uuid + "/formatters/zip") .session(mockHttpSession) .accept("application/zip")) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(MEF_V2_ACCEPT_TYPE)) .andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, equalTo(String.format("inline; filename=\"%s.%s\"", this.uuid, "zip")))) .andExpect(content().string(startsWith(zipMagicNumber))); mockMvc.perform(get("/srv/api/records/" + this.uuid + "/formatters/zip") .session(mockHttpSession) .accept(MEF_V1_ACCEPT_TYPE)) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(MEF_V1_ACCEPT_TYPE)) .andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, equalTo(String.format("inline; filename=\"%s.%s\"", this.uuid, "zip")))) .andExpect(content().string(startsWith(zipMagicNumber))); mockMvc.perform(get("/srv/api/records/" + this.uuid + "/formatters/zip") .session(mockHttpSession) .accept(MEF_V1_ACCEPT_TYPE)) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(MEF_V1_ACCEPT_TYPE)) .andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, equalTo(String.format("inline; filename=\"%s.%s\"", this.uuid, "zip")))) .andExpect(content().string(startsWith(zipMagicNumber))); }