MetadataApi { @ApiOperation( value = "Get record related resources", nickname = "getAssociated", notes = "Retrieve related services, datasets, onlines, thumbnails, sources, ... " + "to this records.<br/>" + "<a href='http: @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 public 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) throws Exception { AbstractMetadata md; try { md = 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); } String language = languageUtils.getIso3langCode(request.getLocales()); final ServiceContext context = ApiUtils.createServiceContext(request); Element raw = new Element("root").addContent(Arrays.asList( new Element("gui").addContent(Arrays.asList( new Element("language").setText(language), new Element("url").setText(context.getBaseUrl()) )), MetadataUtils.getRelated(context, md.getId(), md.getUuid(), type, start, start + rows, true) )); Path relatedXsl = dataDirectory.getWebappDir().resolve("xslt/services/metadata/relation.xsl"); final Element transform = Xml.transform(raw, relatedXsl); RelatedResponse response = (RelatedResponse) Xml.unmarshall(transform, RelatedResponse.class); return response; }  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 getRelated() throws Exception { MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); MockHttpSession mockHttpSession = loginAsAdmin(); addThumbnails(this.context); final MEFLibIntegrationTest.ImportMetadata importMetadata = new MEFLibIntegrationTest.ImportMetadata(this, context); importMetadata.getMefFilesToLoad().add("/org/fao/geonet/api/records/samples/mef2-related.zip"); importMetadata.invoke(); final String MAIN_UUID = "655bb8a1-0324-470f-8dff-bb64e849291c"; final String DATASET_UUID = "842f9143-fd7d-452c-96b4-425ca1281642"; mockMvc.perform(get("/srv/api/records/" + MAIN_UUID + "/related") .session(mockHttpSession) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType(API_JSON_EXPECTED_ENCODING)); mockMvc.perform(get("/srv/api/records/" + MAIN_UUID + "/related") .session(mockHttpSession) .accept(MediaType.APPLICATION_XML)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_XML)) .andExpect(xpath("/related/onlines").exists()); mockMvc.perform(get("/srv/api/records/" + this.uuid + "/related") .param("type", RelatedItemType.thumbnails.toString()) .session(mockHttpSession) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType(API_JSON_EXPECTED_ENCODING)) .andExpect(jsonPath("$." + RelatedItemType.thumbnails, notNullValue())); for (RelatedItemType type : RelatedItemType.values()) { if (type == RelatedItemType.hassources || type == RelatedItemType.related || type == RelatedItemType.hasfeaturecats || type == RelatedItemType.brothersAndSisters || type == RelatedItemType.thumbnails) { continue; } String uuidToTest = MAIN_UUID; if (type == RelatedItemType.datasets) { uuidToTest = DATASET_UUID; } mockMvc.perform(get("/srv/api/records/" + uuidToTest + "/related") .param("type", type.toString()) .session(mockHttpSession) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType(API_JSON_EXPECTED_ENCODING)) .andExpect(jsonPath("$." + type).isNotEmpty()) .andExpect(jsonPath("$").value(hasKey(type.toString()))); mockMvc.perform(get("/srv/api/records/" + uuidToTest + "/related") .param("type", type.toString()) .session(mockHttpSession) .accept(MediaType.APPLICATION_XML)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_XML)) .andExpect(xpath("/related/" + type.toString() + "/item").exists()); } mockMvc.perform(get("/srv/api/records/" + MAIN_UUID + "/related") .param("type", RelatedItemType.children.toString()) .param("start", "2") .param("rows", "1") .session(mockHttpSession) .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(API_JSON_EXPECTED_ENCODING)) .andExpect(jsonPath("$." + RelatedItemType.children).isArray()) .andExpect(jsonPath("$." + RelatedItemType.children, hasSize(1))); mockMvc.perform(get("/srv/api/records/" + MAIN_UUID + "/related") .param("type", RelatedItemType.children.toString()) .param("start", "2") .param("rows", "1") .session(mockHttpSession) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_XML)) .andExpect(xpath("/related/" + RelatedItemType.children + "/item").exists()) .andExpect(xpath("/related/" + RelatedItemType.children + "/item").nodeCount(1)); }