package org.gcube.gcat.rest; import java.io.StringWriter; import java.util.List; import java.util.Set; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.InternalServerErrorException; import javax.ws.rs.NotFoundException; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import org.gcube.common.resources.gcore.GenericResource; import org.gcube.common.resources.gcore.Resources; import org.gcube.datacatalogue.metadatadiscovery.reader.MetadataFormatDiscovery; import org.gcube.datacatalogue.metadatadiscovery.reader.QueryForResourceUtil; import org.gcube.gcat.ResourceInitializer; import org.gcube.gcat.profile.MetadataUtility; import org.gcube.gcat.utils.Constants; import org.gcube.informationsystem.publisher.RegistryPublisher; import org.gcube.informationsystem.publisher.RegistryPublisherFactory; import org.gcube.resources.discovery.client.api.DiscoveryClient; import org.gcube.resources.discovery.client.queries.api.Query; import org.gcube.resources.discovery.client.queries.impl.QueryBox; import org.gcube.resources.discovery.icclient.ICFactory; import org.json.JSONObject; import org.json.XML; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; /** * @author Luca Frosini (ISTI - CNR) */ @Path(Profile.PROFILES) public class Profile extends BaseREST implements org.gcube.gcat.api.interfaces.Profile { private static Logger logger = LoggerFactory.getLogger(Profile.class); public static final String PROFILE_NAME_PARAMETER = "PROFILE_NAME"; @Context private UriInfo uriInfo; @GET @Produces(MediaType.APPLICATION_JSON) public String list() { setCalledMethod("GET /" + PROFILES); ObjectMapper mapper = new ObjectMapper(); ArrayNode arrayNode = mapper.createArrayNode(); try { Set names = MetadataUtility.getInstance().getProfilesNames(); for(String name : names) { arrayNode.add(name); } return mapper.writeValueAsString(arrayNode); } catch(Exception e) { throw new InternalServerErrorException(e.getMessage()); } } public static int PRETTY_PRINT_INDENT_FACTOR = 4; @GET @Path("/{" + PROFILE_NAME_PARAMETER + "}") @Produces({MediaType.APPLICATION_XML, ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8}) public String read(@PathParam(PROFILE_NAME_PARAMETER) String name, @DefaultValue(MediaType.APPLICATION_XML) @HeaderParam("Accept") String accept) { setCalledMethod("GET /" + PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}"); try { String profile = MetadataUtility.getInstance().getMetadataFormat(name).getMetadataSource(); if(profile != null) { if(accept.startsWith(MediaType.APPLICATION_XML)) { return profile; } else { JSONObject xmlJSONObj = XML.toJSONObject(profile); String jsonString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR); return jsonString; } } else { throw new NotFoundException("Profile with name " + name + " not found"); } } catch(WebApplicationException e) { throw e; } catch(Exception e) { throw new InternalServerErrorException(e.getMessage()); } } /* public static void appendXmlFragment(org.gcube.common.resources.gcore.GenericResource.Profile profile, String xml) throws Exception { try { DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Element elem = profile.newBody(); Node fragmentNode = docBuilder.parse(new InputSource(new StringReader(xml))).getDocumentElement(); fragmentNode = elem.getOwnerDocument().importNode(fragmentNode, true); elem.appendChild(fragmentNode); } catch (Exception e) { profile.newBody(xml); } } */ /* * TODO Check the Queries because the name in the Profile differs from the name in * * */ protected GenericResource instantiateGenericResource(String name, String xml) throws Exception { GenericResource genericResource = new GenericResource(); org.gcube.common.resources.gcore.GenericResource.Profile profile = genericResource.newProfile(); profile.type(MetadataFormatDiscovery.DATA_CATALOGUE_METADATA_SECONDARY_TYPE); profile.name(name); profile.description("Profile create using " + Constants.CATALOGUE_NAME); // appendXmlFragment(profile, xml); profile.newBody(xml); StringWriter stringWriter = new StringWriter(); Resources.marshal(genericResource, stringWriter); logger.debug("The generated {} is\n{}", GenericResource.class.getSimpleName(), stringWriter.toString()); return genericResource; } protected void createGenericResource(String name, String xml) throws Exception { GenericResource genericResource = instantiateGenericResource(name, xml); RegistryPublisher registryPublisher = RegistryPublisherFactory.create(); genericResource = registryPublisher.create(genericResource); StringWriter stringWriter = new StringWriter(); Resources.marshal(genericResource, stringWriter); logger.trace("The {} with ID {} has been created \n{}", GenericResource.class.getSimpleName(), genericResource.id(), stringWriter.toString()); } protected GenericResource getGenericResource(String name) { String query = QueryForResourceUtil.getGcubeGenericQueryStringForSecondaryTypeAndName(name, MetadataFormatDiscovery.DATA_CATALOGUE_METADATA_SECONDARY_TYPE); Query q = new QueryBox(query); DiscoveryClient client = ICFactory.clientFor(GenericResource.class); List resources = client.submit(q); if(resources == null || resources.size() == 0) { throw new InternalServerErrorException( "No Resources with secondaryType '" + MetadataFormatDiscovery.DATA_CATALOGUE_METADATA_SECONDARY_TYPE + "' and name '" + name + "' exists in the current context"); } else { if(resources.size() == 1) { GenericResource genericResource = resources.get(0); return genericResource; } else { throw new InternalServerErrorException("More than one Resource with secondaryType '" + MetadataFormatDiscovery.DATA_CATALOGUE_METADATA_SECONDARY_TYPE + "' and name '" + name + "' exists in the current context"); } } } protected void updateGenericResource(String name, String xml) { GenericResource genericResource = getGenericResource(name); logger.info("The {} with ID {} is going to be updated", GenericResource.class.getSimpleName(), genericResource.id()); genericResource.profile().newBody(xml); RegistryPublisher registryPublisher = RegistryPublisherFactory.create(); registryPublisher.update(genericResource); StringWriter stringWriter = new StringWriter(); Resources.marshal(genericResource, stringWriter); logger.trace("The {} with ID {} has been updated to \n{}", GenericResource.class.getSimpleName(), genericResource.id(), stringWriter.toString()); } protected void removeGenericResource(String name) { GenericResource genericResource = getGenericResource(name); RegistryPublisher registryPublisher = RegistryPublisherFactory.create(); registryPublisher.remove(genericResource); } @PUT @Path("/{" + PROFILE_NAME_PARAMETER + "}") @Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) public Response createOrUpdate(@PathParam(PROFILE_NAME_PARAMETER) String name, String xml) { setCalledMethod("PUT /" + PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}"); try { MetadataUtility metadataUtility = MetadataUtility.getInstance(); metadataUtility.getDataCalogueMetadataFormatReader().validateProfile(xml); if(metadataUtility.getMetadataFormat(name) == null) { createGenericResource(name, xml); ResponseBuilder responseBuilder = Response.status(Status.CREATED).entity(xml); responseBuilder.header(LOCATION_HEADER, uriInfo.getAbsolutePath()); return responseBuilder.type(MediaType.APPLICATION_XML).build(); } else { updateGenericResource(name, xml); ResponseBuilder responseBuilder = Response.status(Status.OK).entity(xml); return responseBuilder.type(MediaType.APPLICATION_XML).build(); } } catch(WebApplicationException e) { throw e; } catch(Exception e) { throw new InternalServerErrorException(e.getMessage()); }finally { // TOOD Actually Cache has been removed. Remove the following code if it will not be re-introduced // Cleaning the cache MetadataUtility.clearCache(); } } @DELETE @Path("/{" + PROFILE_NAME_PARAMETER + "}") public Response delete(@PathParam(PROFILE_NAME_PARAMETER) String name) { setCalledMethod("DELETE /" + PROFILES + "/{" + PROFILE_NAME_PARAMETER + "}"); try { MetadataUtility metadataUtility = MetadataUtility.getInstance(); if(metadataUtility.getMetadataFormat(name) == null) { throw new NotFoundException("Profile with name " + name + " not found"); } else { removeGenericResource(name); return Response.status(Status.NO_CONTENT).build(); } } catch(WebApplicationException e) { throw e; } catch(Exception e) { throw new InternalServerErrorException(e.getMessage()); } finally { // Cleaning the cache MetadataUtility.clearCache(); } } @Override public Response create(String name, String xml) { return createOrUpdate(name, xml); } @Override public String read(String name) { return read(name, MediaType.APPLICATION_XML); } @Override public String update(String name, String xml) { return createOrUpdate(name, xml).getEntity().toString(); } }