package org.gcube.data.publishing.ckan2zenodo.clients; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.concurrent.Callable; import java.util.concurrent.Future; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.gcube.data.publishing.ckan2zenodo.Fixer; import org.gcube.data.publishing.ckan2zenodo.model.ZenodoCredentials; import org.gcube.data.publishing.ckan2zenodo.model.faults.ZenodoException; import org.gcube.data.publishing.ckan2zenodo.model.zenodo.DepositionMetadata; import org.gcube.data.publishing.ckan2zenodo.model.zenodo.FileDeposition; import org.gcube.data.publishing.ckan2zenodo.model.zenodo.ZenodoDeposition; import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.media.multipart.FormDataMultiPart; import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @RequiredArgsConstructor @Slf4j public class Zenodo { private static final String CONTENT_TYPE="application/json"; private static final String DEPOSITION_BASE_URL="deposit/depositions"; private static final String PUBLISH_URL_PRE="deposit/depositions"; private static final String PUBLISH_URL_POST="actions/publish"; private static final String ACCESS_TOKEN="access_token"; private static ObjectMapper mapper = new ObjectMapper(); static { mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false); mapper.setSerializationInclusion(Include.NON_NULL); // mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); } @NonNull private ZenodoCredentials credentials; Client client; private synchronized Client getWebClient() { if(client==null) { client = ClientBuilder.newClient() .property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true); client.register(MultiPartFeature.class); } return client; } public ZenodoDeposition readDeposition(String id) throws ZenodoException { Response resp= getWebClient().target(credentials.getBaseUrl()). path(DEPOSITION_BASE_URL).path(id). queryParam(ACCESS_TOKEN, credentials.getKey()).request(CONTENT_TYPE) .get(); return check(resp,ZenodoDeposition.class); } private static T check(Response resp, Class clazz) throws ZenodoException{ if(resp.getStatus()<200||resp.getStatus()>=300) { throw new ZenodoException("RESP STATUS IS "+resp.getStatus()+". Message : "+resp.readEntity(String.class)); }else { if(clazz==null) return null; String respString=resp.readEntity(String.class); try { return mapper.readValue(Fixer.fixIncoming(respString), clazz); } catch (IOException e) { throw new ZenodoException("Unable to parse response from Zenodo. Content was : \n "+respString,e); } } } public ZenodoDeposition updateMetadata(ZenodoDeposition dep) throws ZenodoException, JsonProcessingException { return updateMetadata(dep.getId(), dep.getMetadata()); } public FileDeposition uploadFile(ZenodoDeposition dep, String toUploadName,String urlString) throws ZenodoException { Callable call=new Callable() { @Override public Response call() throws Exception { File temp=null; try { log.debug("Downloading "+urlString); //Download locally into temp URL url=new URL(urlString); temp=File.createTempFile("zenodo_", ".tmp"); long size=Files.copy(url.openStream(), temp.toPath(),StandardCopyOption.REPLACE_EXISTING); //upload FormDataMultiPart multi=new FormDataMultiPart(); FileDataBodyPart fileDataBodyPart = new FileDataBodyPart("file", temp,MediaType.APPLICATION_OCTET_STREAM_TYPE); multi.field("name", toUploadName); multi.bodyPart(fileDataBodyPart); log.debug("Starting transfer of "+toUploadName+" ("+urlString+") into "+dep.getId()); Response toReturn=getWebClient().target(credentials.getBaseUrl()). path(DEPOSITION_BASE_URL).path(dep.getId()+"").path("files"). queryParam(ACCESS_TOKEN, credentials.getKey()).request(CONTENT_TYPE) .post(Entity.entity(multi,multi.getMediaType())); log.debug("DONE."); return toReturn; }catch(Throwable e) { throw new ZenodoException("Unable to transfer file "+toUploadName+" url : "+urlString,e); }finally { //finally delete temp if(temp!=null) Files.deleteIfExists(temp.toPath()); } } }; log.debug("Submitting request to upload "+urlString+" to Manager"); Future resp=FileUploaderManager.submit(call); try { return check(resp.get(),FileDeposition.class); }catch(ZenodoException z) { throw z; }catch(Throwable t) { throw new ZenodoException(t.getMessage(),t); } //return } private ZenodoDeposition updateMetadata(Integer depositionId,DepositionMetadata meta) throws ZenodoException, JsonProcessingException { String serialized="{\"metadata\":"+Fixer.fixIncoming(mapper.writeValueAsString(meta))+"}"; try { Response resp = getWebClient().target(credentials.getBaseUrl()). path(DEPOSITION_BASE_URL).path(depositionId+""). queryParam(ACCESS_TOKEN, credentials.getKey()).request(CONTENT_TYPE) .put(Entity.json(serialized)); return check(resp,ZenodoDeposition.class); }catch(Throwable t) { log.debug("Error while tryin to update "+serialized); throw t; } } public void deleteDeposition(Integer depositionId) throws ZenodoException { Response resp = getWebClient().target(credentials.getBaseUrl()). path(DEPOSITION_BASE_URL).path(depositionId+""). queryParam(ACCESS_TOKEN, credentials.getKey()).request(CONTENT_TYPE) .delete(); check(resp,null); } public ZenodoDeposition createNew() throws ZenodoException { Response resp = getWebClient().target(credentials.getBaseUrl()). path(DEPOSITION_BASE_URL). queryParam(ACCESS_TOKEN, credentials.getKey()).request(CONTENT_TYPE) .post(Entity.json("{}")); return check(resp,ZenodoDeposition.class); } public ZenodoDeposition publish(ZenodoDeposition dep) throws ZenodoException{ return publish(dep.getId()); } private ZenodoDeposition publish(Integer depositionId) throws ZenodoException{ Response resp = getWebClient().target(credentials.getBaseUrl()). path(PUBLISH_URL_PRE). path(depositionId+""). path(PUBLISH_URL_POST). queryParam(ACCESS_TOKEN, credentials.getKey()).request(CONTENT_TYPE) .post(Entity.json("{}")); return check(resp,ZenodoDeposition.class); } }