package eu.dnetlib.dhp.oa.zenodoapi; import java.io.*; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; import org.apache.http.HttpHeaders; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.ContentType; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; // import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.jetbrains.annotations.NotNull; import com.google.gson.Gson; import eu.dnetlib.dhp.oa.zenodoapi.model.ZenodoModel; import eu.dnetlib.dhp.oa.zenodoapi.model.ZenodoModelList; import okhttp3.*; public class ZenodoAPIClient implements Serializable { String urlString; String bucket; String deposition_id; String access_token; public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8"); private static final MediaType MEDIA_TYPE_ZIP = MediaType.parse("application/zip"); public String getUrlString() { return urlString; } public void setUrlString(String urlString) { this.urlString = urlString; } public String getBucket() { return bucket; } public void setBucket(String bucket) { this.bucket = bucket; } public void setDeposition_id(String deposition_id) { this.deposition_id = deposition_id; } public ZenodoAPIClient(String urlString, String access_token) { this.urlString = urlString; this.access_token = access_token; } /** * Brand new deposition in Zenodo. It sets the deposition_id and the bucket where to store the files to upload * * @return response code * @throws IOException */ // public int newDeposition() throws IOException { // String json = "{}"; // // URL url = new URL(urlString); // HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); // conn.setRequestProperty(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); // conn.setRequestMethod("POST"); // conn.setDoOutput(true); // try (OutputStream os = conn.getOutputStream()) { // byte[] input = json.getBytes("utf-8"); // os.write(input, 0, input.length); // } // // String body = getBody(conn); // // int responseCode = conn.getResponseCode(); // conn.disconnect(); // // if (!checkOKStatus(responseCode)) // throw new IOException("Unexpected code " + responseCode + body); // // ZenodoModel newSubmission = new Gson().fromJson(body, ZenodoModel.class); // this.bucket = newSubmission.getLinks().getBucket(); // this.deposition_id = newSubmission.getId(); // // return responseCode; // } public int newDeposition() throws IOException { String json = "{}"; OkHttpClient httpClient = new OkHttpClient.Builder().connectTimeout(600, TimeUnit.SECONDS).build(); RequestBody body = RequestBody.create(json, MEDIA_TYPE_JSON); Request request = new Request.Builder() .url(urlString) .addHeader("Content-Type", "application/json") // add request headers .addHeader("Authorization", "Bearer " + access_token) .post(body) .build(); try (Response response = httpClient.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response + response.body().string()); // Get response body json = response.body().string(); eu.dnetlib.dhp.common.api.zenodo.ZenodoModel newSubmission = new Gson() .fromJson(json, eu.dnetlib.dhp.common.api.zenodo.ZenodoModel.class); this.bucket = newSubmission.getLinks().getBucket(); this.deposition_id = newSubmission.getId(); return response.code(); } } // public int uploadIS2(InputStream is, String fileName) throws IOException { // // final String crlf = "\r\n"; // final String twoHyphens = "--"; // final String boundary = "*****"; // // HttpPut put = new HttpPut(bucket + "/" + fileName); // // put.addHeader(HttpHeaders.CONTENT_TYPE, "application/zip"); // put.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); // // put.setEntity(new InputStreamEntity(is)); // // int statusCode; // try (CloseableHttpClient client = HttpClients.createDefault()) { // CloseableHttpResponse response = client.execute(put); // statusCode = response.getStatusLine().getStatusCode(); // // } // // if (!checkOKStatus(statusCode)) { // throw new IOException("Unexpected code " + statusCode); // } // // return statusCode; // } // public int publish() throws IOException { // String json = "{}"; // HttpPost post = new HttpPost(urlString + "/" + deposition_id + "/actions/publish"); // post.addHeader(HttpHeaders.CONTENT_TYPE, "application/json"); // post.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); // post.setEntity(new StringEntity(json)); // int statusCode; // try (CloseableHttpClient client = HttpClients.createDefault()) { // CloseableHttpResponse response = client.execute(post); // statusCode = response.getStatusLine().getStatusCode(); // } // if (!checkOKStatus(statusCode)) { // throw new IOException("Unexpected code " + statusCode); // } // return statusCode; // } /** * Upload files in Zenodo. * * @param is the inputStream for the file to upload * @param file_name the name of the file as it will appear on Zenodo * @return the response code */ public int uploadIS(InputStream is, String file_name) throws IOException { URL url = new URL(bucket + "/" + file_name); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, "application/zip"); conn.setRequestProperty(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); conn.setDoOutput(true); conn.setRequestMethod("PUT"); byte[] buf = new byte[8192]; int length; try (OutputStream os = conn.getOutputStream()) { while ((length = is.read(buf)) != -1) { os.write(buf, 0, length); os.flush(); } } int responseCode = conn.getResponseCode(); if (!checkOKStatus(responseCode)) { throw new IOException("Unexpected code " + responseCode + getBody(conn)); } return responseCode; } @NotNull private String getBody(HttpURLConnection conn) throws IOException { String body = "{}"; try (BufferedReader br = new BufferedReader( new InputStreamReader(conn.getInputStream(), "utf-8"))) { StringBuilder response = new StringBuilder(); String responseLine = null; while ((responseLine = br.readLine()) != null) { response.append(responseLine.trim()); } body = response.toString(); } return body; } public int uploadIS3(InputStream is, String file_name, long len) throws IOException { OkHttpClient httpClient = new OkHttpClient.Builder() .writeTimeout(600, TimeUnit.SECONDS) .readTimeout(600, TimeUnit.SECONDS) .connectTimeout(600, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url(bucket + "/" + file_name) .addHeader(HttpHeaders.CONTENT_TYPE, "application/zip") // add request headers .addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + access_token) .put(InputStreamRequestBody.create(MEDIA_TYPE_ZIP, is, len)) .build(); try (Response response = httpClient.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response + response.body().string()); return response.code(); } } /** * Associates metadata information to the current deposition * * @param metadata the metadata * @return response code * @throws IOException */ public int sendMretadata(String metadata) throws IOException { URL url = new URL(urlString + "/" + deposition_id); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); conn.setRequestProperty(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); conn.setDoOutput(true); conn.setRequestMethod("PUT"); try (OutputStream os = conn.getOutputStream()) { byte[] input = metadata.getBytes("utf-8"); os.write(input, 0, input.length); } final int responseCode = conn.getResponseCode(); conn.disconnect(); if (!checkOKStatus(responseCode)) throw new IOException("Unexpected code " + responseCode + getBody(conn)); return responseCode; } private boolean checkOKStatus(int responseCode) { if (HttpURLConnection.HTTP_OK == responseCode || HttpURLConnection.HTTP_CREATED == responseCode) return true; return false; } /** * To create a new version of an already published deposition. It sets the deposition_id and the bucket to be used * for the new version. * * @param concept_rec_id the concept record id of the deposition for which to create a new version. It is the last * part of the url for the DOI Zenodo suggests to use to cite all versions: DOI: 10.xxx/zenodo.656930 * concept_rec_id = 656930 * @return response code * @throws IOException * @throws MissingConceptDoiException */ // public int newVersion(String concept_rec_id) throws Exception, MissingConceptDoiException { // setDepositionId(concept_rec_id, 1); // String json = "{}"; // // URL url = new URL(urlString + "/" + deposition_id + "/actions/newversion"); // HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // // conn.setRequestProperty(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); // conn.setDoOutput(true); // conn.setRequestMethod("POST"); // // try (OutputStream os = conn.getOutputStream()) { // byte[] input = json.getBytes("utf-8"); // os.write(input, 0, input.length); // // } // // String body = getBody(conn); // // int responseCode = conn.getResponseCode(); // // conn.disconnect(); // if (!checkOKStatus(responseCode)) // throw new IOException("Unexpected code " + responseCode + body); // // ZenodoModel zenodoModel = new Gson().fromJson(body, ZenodoModel.class); // String latest_draft = zenodoModel.getLinks().getLatest_draft(); // deposition_id = latest_draft.substring(latest_draft.lastIndexOf("/") + 1); // bucket = getBucket(latest_draft); // // return responseCode; // // } public int newVersion(String concept_rec_id) throws Exception, MissingConceptDoiException { setDepositionId(concept_rec_id, 1); String json = "{}"; OkHttpClient httpClient = new OkHttpClient.Builder().connectTimeout(600, TimeUnit.SECONDS).build(); RequestBody body = RequestBody.create(json, MEDIA_TYPE_JSON); Request request = new Request.Builder() .url(urlString + "/" + deposition_id + "/actions/newversion") .addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + access_token) .post(body) .build(); try (Response response = httpClient.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response + response.body().string()); ZenodoModel zenodoModel = new Gson().fromJson(response.body().string(), ZenodoModel.class); String latest_draft = zenodoModel.getLinks().getLatest_draft(); deposition_id = latest_draft.substring(latest_draft.lastIndexOf("/") + 1); bucket = getBucket(latest_draft); return response.code(); } } /** * To finish uploading a version or new deposition not published * It sets the deposition_id and the bucket to be used * * * @param deposition_id the deposition id of the not yet published upload * concept_rec_id = 656930 * @return response code * @throws IOException * @throws MissingConceptDoiException */ public int uploadOpenDeposition(String deposition_id) throws IOException, MissingConceptDoiException { this.deposition_id = deposition_id; String json = "{}"; URL url = new URL(urlString + "/" + deposition_id); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestProperty(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); conn.setRequestMethod("POST"); conn.setDoOutput(true); try (OutputStream os = conn.getOutputStream()) { byte[] input = json.getBytes("utf-8"); os.write(input, 0, input.length); } String body = getBody(conn); int responseCode = conn.getResponseCode(); conn.disconnect(); if (!checkOKStatus(responseCode)) throw new IOException("Unexpected code " + responseCode + body); ZenodoModel zenodoModel = new Gson().fromJson(body, ZenodoModel.class); bucket = zenodoModel.getLinks().getBucket(); return responseCode; } private void setDepositionId(String concept_rec_id, Integer page) throws Exception, MissingConceptDoiException { ZenodoModelList zenodoModelList = new Gson() .fromJson(getPrevDepositions(String.valueOf(page)), ZenodoModelList.class); for (ZenodoModel zm : zenodoModelList) { if (zm.getConceptrecid().equals(concept_rec_id)) { deposition_id = zm.getId(); return; } } if (zenodoModelList.size() == 0) throw new MissingConceptDoiException( "The concept record id specified was missing in the list of depositions"); setDepositionId(concept_rec_id, page + 1); } // private String getPrevDepositions(String page) throws Exception { // // HttpGet get = new HttpGet(urlString); // URI uri = new URIBuilder(get.getURI()).addParameter("page", page).build(); // // get.setURI(uri); // // get.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); // get.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); // try (CloseableHttpClient client = HttpClients.createDefault()) { // CloseableHttpResponse response = client.execute(get); // final String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); // return body; // } // } private String getPrevDepositions(String page) throws IOException { OkHttpClient httpClient = new OkHttpClient.Builder().connectTimeout(600, TimeUnit.SECONDS).build(); HttpUrl.Builder urlBuilder = HttpUrl.parse(urlString).newBuilder(); urlBuilder.addQueryParameter("page", page); String url = urlBuilder.build().toString(); Request request = new Request.Builder() .url(url) .addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()) // add request headers .addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + access_token) .get() .build(); try (Response response = httpClient.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response + response.body().string()); return response.body().string(); } } private String getBucket(String inputUurl) throws IOException { URL url = new URL(inputUurl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); conn.setRequestProperty(HttpHeaders.AUTHORIZATION, "Bearer " + access_token); conn.setDoOutput(true); conn.setRequestMethod("GET"); String body = getBody(conn); int responseCode = conn.getResponseCode(); conn.disconnect(); if (!checkOKStatus(responseCode)) throw new IOException("Unexpected code " + responseCode + body); ZenodoModel zenodoModel = new Gson().fromJson(body, ZenodoModel.class); return zenodoModel.getLinks().getBucket(); } }