All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.genesys2.client.oauth.GenesysClient Maven / Gradle / Ivy

There is a newer version: 3.0
Show newest version
/*
 * Copyright 2016 Global Crop Diversity Trust
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.genesys2.client.oauth;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.ExecutionException;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.exceptions.OAuthException;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.model.Response;
import com.github.scribejava.core.model.Verb;
import com.github.scribejava.core.oauth.OAuth20Service;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.genesys2.client.oauth.api.GenesysApi;
import org.genesys2.client.oauth.api.accession.AccessionJson;
import org.genesys2.client.oauth.api.images.RepositoryImage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Genesys API client using Scribe.
 */
public class GenesysClient {

	/** The Constant LOG. */
	private static final Logger LOG = LoggerFactory.getLogger(GenesysClient.class);

	/** The mapper. */
	private static ObjectMapper objectMapper;

	/** The service. */
	private final OAuth20Service service;

	/** GenesysTokens: access- and refreshToken. */
	private GenesysTokens tokens = new GenesysTokens();

	/** Base URL of Genesys */
	private String baseUrl;

	/** UTF8 charset */
	private static Charset CHARSET_UTF8 = Charset.forName("UTF8");

	static {
		objectMapper = new ObjectMapper();
		objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
		objectMapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false);
		objectMapper.setSerializationInclusion(Include.NON_NULL);
		objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
	}

	/**
	 * Instantiates a new genesys client.
	 *
	 * @param baseUrl the base url
	 * @param clientId the client id
	 * @param clientSecret the client secret
	 * @param callbackUrl the callback url
	 * @param scope the scope
	 */
	public GenesysClient(final String baseUrl, final String clientId, final String clientSecret, final String callbackUrl, String scope) {
		this.baseUrl = baseUrl;
		ServiceBuilder serviceBuilder = new ServiceBuilder(clientId).callback(callbackUrl).scope(scope);
		if (StringUtils.isNotBlank(clientSecret)) {
			serviceBuilder.apiSecret(clientSecret);
		}
		service = serviceBuilder.build(new GenesysApi(baseUrl));
	}

	/**
	 * Load client configuration from {@link Properties}.
	 *
	 * @param properties the properties
	 * @return the genesys client
	 */
	public static GenesysClient build(final Properties properties) {

		final String baseUrl = properties.getProperty("base.url");

		GenesysTokens tokens = new GenesysTokens();
		tokens.setAccessToken(properties.getProperty("access.token"));
		tokens.setRefreshToken(properties.getProperty("refresh.token"));

		// Genesys client instance auth service
		return new GenesysClient(baseUrl, properties.getProperty("client.key"), properties.getProperty("client.secret"), properties.getProperty("client.callback"),
				properties.getProperty("client.scope"));
	}

	/**
	 * Gets the authorization url.
	 *
	 * @return the authorization url
	 */
	public String getAuthorizationUrl() {
		return service.getAuthorizationUrl();
	}

	/**
	 * Sets the tokens.
	 *
	 * @param tokens the new tokens
	 */
	public void setTokens(final GenesysTokens tokens) {
		this.tokens = tokens;
	}

	/**
	 * Gets the tokens.
	 *
	 * @return the tokens
	 */
	public GenesysTokens getTokens() {
		return tokens;
	}

	/**
	 * Query.
	 *
	 * @param url the url
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String query(final String url) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.GET, url, null, null);
	}

	/**
	 * Query.
	 *
	 * @param method the HTTP method
	 * @param url the url
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String query(final Verb method, final String url) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(method, url, null, null);
	}

	/**
	 * Query.
	 *
	 * @param method the method
	 * @param url the url
	 * @param queryString the query string
	 * @param postBody the post body
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws HttpRedirectException the http redirect exception
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String query(final Verb method, final String url, final Map queryString, final String postBody)
			throws OAuthAuthenticationException, PleaseRetryException, HttpRedirectException, GenesysApiException {

		if (StringUtils.isBlank(postBody)) {
			return query(method, url, queryString, null, null);
		} else {
			return query(method, url, queryString, HttpConstants.APPLICATION_JSON_UTF8, postBody.getBytes(CHARSET_UTF8));
		}
	}

	/**
	 * Send object as JSON
	 *
	 * @param method
	 * @param url
	 * @param queryString
	 * @param object
	 * @return
	 * @throws GenesysApiException
	 * @throws JsonProcessingException
	 */
	private String query(final Verb method, final String url, final Map queryString, final Serializable object)
			throws GenesysApiException, JsonProcessingException {
		return query(method, url, queryString, HttpConstants.APPLICATION_JSON_UTF8, objectMapper.writeValueAsBytes(object));
	}

	private String query(final Verb method, final String url, final Map queryString, final String contentType, final byte[] postBody) throws GenesysApiException {
		if (!tokens.hasAccessToken()) {
			refreshAccessToken();
		}

		for (int i = 0; i < 2; i++) {
			final OAuthRequest request = new OAuthRequest(method, getApiUrl(url));

			if (queryString != null && queryString.size() > 0) {
				for (final String key : queryString.keySet()) {
					request.addQuerystringParameter(key, queryString.get(key));
				}
			}

			if (LOG.isDebugEnabled()) {
				LOG.debug("{} {}", method, request.getCompleteUrl());
			}

			if (StringUtils.isNotBlank(contentType)) {
				request.addHeader("Content-Type", contentType);
			}

			if (postBody != null) {
				// System.err.println("Adding data: " + data);
				if (LOG.isTraceEnabled()) {
					LOG.trace("Body: {}", new String(postBody));
				}
				request.setPayload(postBody);
			}

			request.setCharset("UTF-8");
			Response response = null;

			try {
				service.signRequest(tokens.accessToken(), request);
				response = service.execute(request);

				final String responseBody = response.getBody();

				LOG.debug("HTTP status code {}", response.getCode());

				if (response.getCode() >= 200 && response.getCode() < 300) {
					LOG.debug("Returning response body");
					return responseBody;
				} else {
					if (response.getCode() == 301 || response.getCode() == 302) {
						LOG.debug("Redirect: {}", response.getHeader(HttpConstants.LOCATION));
						throw new HttpRedirectException(response.getHeader(HttpConstants.LOCATION));
					}
					if (response.getCode() == 401) {
						LOG.warn("Response error: {}", response.getCode());
						System.err.println(responseBody);
						if (i == 0) {
							refreshAccessToken();
						} else {
							throw new OAuthAuthenticationException("Unauthorized");
						}
					} else {
						LOG.error("{} {}", method, request.getCompleteUrl());
						LOG.error(new String(postBody));
						LOG.error("HTTP response code: {}", response.getCode());
						LOG.error("Response: {}", responseBody);
						if (response.getCode() == 504 || responseBody.contains("Deadlock found when trying to get lock; try restarting transaction")
								|| responseBody.contains("nested exception is org.hibernate.exception.LockAcquisitionException: could not execute statement")
								|| responseBody.contains("nested exception is org.hibernate.exception.LockTimeoutException: could not execute statement")) {
							throw new PleaseRetryException(responseBody);
						} else {
							throw new GenesysApiException("Unexpected error: " + responseBody);
						}
					}
				}

			} catch (final Throwable e) {
				e.printStackTrace();
				throw new GenesysApiException(e.getMessage());
			}
		}
		return null;
	}

	/**
	 * Gets the api url.
	 *
	 * @param url the url
	 * @return the api url
	 */
	private String getApiUrl(final String url) {
		return baseUrl.concat("/api/v0").concat(url);
	}

	/**
	 * Refresh accessToken with refreshToken.
	 *
	 * @throws GenesysApiException the Genesys API exception
	 */
	public void refreshAccessToken() throws GenesysApiException {
		if (tokens.hasRefreshToken()) {
			LOG.info("Using Refresh Token to get new access token");
			try {
				OAuth2AccessToken accessToken = service.refreshAccessToken(tokens.getRefreshToken());
				tokens.setAccessToken(accessToken.getAccessToken());
				LOG.info("Got new Access Token!");

			} catch (Throwable e) {
				LOG.info("Refresh token didn't work: {}", e.getMessage());
				throw new OAuthAuthenticationException("Refresh token not valid, please re-authenticate");
			}
		} else {
			authenticate();
		}
	}

	/**
	 * Accession exists.
	 *
	 * @param instCode the inst code
	 * @param acceNumb the acce numb
	 * @param genus the genus
	 * @return the string
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String accessionExists(final String instCode, final String acceNumb, final String genus) throws GenesysApiException {

		try {
			final HashMap queryString = new HashMap();
			queryString.put("acceNumb", acceNumb);

			return query(Verb.GET, new URI(null, null, "/acn/exists/" + instCode + "/" + genus, null).toString(), queryString, null);
		} catch (final URISyntaxException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Make aid3.
	 *
	 * @param instCode the inst code
	 * @param genus the genus
	 * @param acceNumb the acce numb
	 * @return the object node
	 */
	public static ObjectNode makeAid3(final String instCode, final String genus, final String acceNumb) {
		final ObjectNode json = objectMapper.createObjectNode();
		json.put("instCode", instCode);
		json.put("acceNumb", acceNumb);
		json.put("genus", genus);
		return json;
	}

	/**
	 * Update MLS status of accessions.
	 *
	 * @param instCode the inst code
	 * @param accns the accns
	 * @return the string
	 * @throws GenesysApiException the Genesys API exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws JsonProcessingException the json processing exception
	 * @deprecated Please use {@link #updateAccessions(String, Collection)} with only the instCode,
	 *             acceNumb, (genus, ) and mlsStat provided.
	 */
	@Deprecated
	public String updateMLS(final String instCode, final Collection accns) throws GenesysApiException, PleaseRetryException, JsonProcessingException {

		if (accns == null || accns.size() == 0) {
			return null;
		}

		LOG.debug("Sending: {}", accns);
		return query(Verb.PUT, "/acn/" + instCode + "/update", null, objectMapper.writeValueAsString(accns));
	}

	/**
	 * Update accession information with new values provided in the JSON string. In case of
	 * {@link PleaseRetryException}, this method will attempt to re-send the data 5 times before giving
	 * up.
	 *
	 * @param instCode the WIEWS institute code
	 * @param jsonAccessionList the JSON array of accessions
	 * @return "OK"
	 * @throws GenesysApiException when data is not valid
	 * @throws InterruptedException when thread was interrupted during sleep between retries
	 *
	 * @deprecated Will be removed by 1.0.0 release
	 */
	@Deprecated
	public String updateAccessions(final String instCode, final String jsonAccessionList) throws GenesysApiException, InterruptedException {
		for (int retry = 0; retry < 5; retry++) {
			try {
				return query(Verb.PUT, "/acn/" + instCode + "/upsert", null, jsonAccessionList);
			} catch (final PleaseRetryException e) {
				final long sleepTime = (long) (Math.pow(2, retry) * 100 + Math.pow(2, retry) * 2500 * Math.random());
				LOG.warn("Retrying PUT after {} ms.", sleepTime);
				Thread.sleep(sleepTime);
			}
		}
		throw new RuntimeException("All retries failed");
	}

	/**
	 * Update accessions.
	 *
	 * @param instCode the inst code
	 * @param accns the accns
	 * @return the string
	 * @throws GenesysApiException the Genesys API exception
	 * @throws InterruptedException the interrupted exception
	 * @throws JsonProcessingException the json processing exception
	 */
	public String updateAccessions(final String instCode, final Collection accns) throws GenesysApiException, InterruptedException, JsonProcessingException {

		if (accns == null || accns.size() == 0) {
			return null;
		}

		final String data = objectMapper.writeValueAsString(accns);

		for (int retry = 0; retry < 5; retry++) {
			try {
				return query(Verb.PUT, "/acn/" + instCode + "/upsert", null, data);
			} catch (final PleaseRetryException e) {
				final long sleepTime = (long) (Math.pow(2, retry) * 100 + Math.pow(2, retry) * 2500 * Math.random());
				LOG.warn("Retrying PUT after {} ms.", sleepTime);
				Thread.sleep(sleepTime);
			} catch (final GenesysApiException e) {
				LOG.error("Failed to upload data: {}", data);
				throw e;
			}
		}
		throw new RuntimeException("All retries failed");
	}

	/**
	 * Update organization members.
	 *
	 * @param organizationSlug the organization slug
	 * @param institutes the institutes
	 * @return the string
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String updateOrganizationMembers(final String organizationSlug, final ArrayNode institutes) throws GenesysApiException {
		LOG.debug("Sending: {}", institutes);
		try {
			return query(Verb.PUT, "/org/" + organizationSlug + "/set-institutes", null, institutes.toString());
		} catch (final PleaseRetryException e) {
			LOG.warn("Retrying PUT after some time...");
			try {
				Thread.sleep((long) (1000 * Math.random()));
			} catch (final InterruptedException e1) {
				e1.printStackTrace();
			}
			return query(Verb.PUT, "/org/" + organizationSlug + "/set-institutes", null, institutes.toString());
		}
	}

	/**
	 * Update accession names.
	 *
	 * @param instCode the inst code
	 * @param batch the batch
	 * @return the string
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String updateAccessionNames(final String instCode, final Collection batch) throws GenesysApiException {
		LOG.debug("Sending: {}", batch);
		try {
			return query(Verb.PUT, "/acn/" + instCode + "/names", null, batch.toString());
		} catch (final PleaseRetryException e) {
			LOG.warn("Retrying PUT after some time...");
			try {
				Thread.sleep((long) (1000 * Math.random()));
			} catch (final InterruptedException e1) {
				e1.printStackTrace();
			}
			LOG.warn("Retrying PUT");
			return query(Verb.PUT, "/acn/" + instCode + "/names", null, batch.toString());
		}
	}

	/**
	 * Delete accessions.
	 *
	 * @param instCode the inst code
	 * @param array the array
	 * @return the string
	 * @throws GenesysApiException the Genesys API exception
	 *
	 * @deprecated Use {@link #deleteAccessionsByName(String, String)}
	 */
	@Deprecated
	public String deleteAccessions(final String instCode, final ArrayNode array) throws GenesysApiException {
		return deleteAccessionsByName(instCode, array.toString());
	}

	/**
	 * Delete accessions from Genesys by ID-triplet (INSTCODE, ACCENUMB, GENUS).
	 *
	 * @param instCode the inst code
	 * @param jsonAccessionId3List the json accession id3 list
	 * @return the string
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String deleteAccessionsByName(final String instCode, final String jsonAccessionId3List) throws GenesysApiException {
		return query(Verb.POST, "/acn/" + instCode + "/delete-named", null, jsonAccessionId3List);
	}

	/**
	 * Delete accession.
	 *
	 * @param instCode the inst code
	 * @param ids the ids
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 *
	 * @deprecated Use
	 */
	@Deprecated
	public String deleteAccession(final String instCode, final ArrayNode ids) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return deleteAccessionsByGenesysId(instCode, ids.toString());
	}

	/**
	 * Delete accessions from Genesys.
	 *
	 * @param instCode the inst code
	 * @param jsonAccessionIdList the json accession id list
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String deleteAccessionsByGenesysId(final String instCode, final String jsonAccessionIdList)
			throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/acn/" + instCode + "/delete", null, jsonAccessionIdList);
	}

	/**
	 * Authenticate.
	 *
	 * @param uname the uname
	 * @param password the password
	 * @throws OAuthAuthenticationException when authentication fails
	 */
	public void authenticate(String uname, String password) throws OAuthAuthenticationException {
		try {
			OAuth2AccessToken accessToken = service.getAccessTokenPasswordGrant(uname, password);

			LOG.info("ACCESS TOKEN: {} scope={} raw={}", accessToken.getAccessToken(), accessToken.getScope(), accessToken.getRawResponse());

			final String refreshToken = accessToken.getRefreshToken();
			LOG.info("REFRESH TOKEN: {}", refreshToken);

			tokens.setAccessToken(accessToken.getAccessToken());
			tokens.setRefreshToken(refreshToken);

		} catch (IOException | InterruptedException | ExecutionException e) {
			LOG.error("Auth error", e);
			throw new OAuthAuthenticationException(e.getMessage());
		}
	}

	/**
	 * Obtain access and refresh tokens with client id and secret.
	 *
	 * @throws OAuthAuthenticationException when authentication fails
	 */
	public void authenticate() throws OAuthAuthenticationException {
		try {
			OAuth2AccessToken accessToken = service.getAccessTokenClientCredentialsGrant();

			LOG.info("ACCESS TOKEN: {} scope={} raw={}", accessToken.getAccessToken(), accessToken.getScope(), accessToken.getRawResponse());

			final String refreshToken = accessToken.getRefreshToken();
			LOG.info("REFRESH TOKEN: {}", refreshToken);

			tokens.setAccessToken(accessToken.getAccessToken());
			tokens.setRefreshToken(refreshToken);

		} catch (OAuthException | IOException | InterruptedException | ExecutionException e) {
			LOG.error("Auth error", e);
			throw new OAuthAuthenticationException(e.getMessage());
		}
	}

	/**
	 * Obtain access and refresh tokens with verifier code.
	 *
	 * @param verifierCode the verifier code
	 * @throws OAuthAuthenticationException when authentication fails
	 */
	public void authenticate(final String verifierCode) throws OAuthAuthenticationException {
		try {
			OAuth2AccessToken accessToken = service.getAccessToken(verifierCode);

			LOG.info("ACCESS TOKEN: {} scope={} raw={}", accessToken.getAccessToken(), accessToken.getScope(), accessToken.getRawResponse());

			final String refreshToken = accessToken.getRefreshToken();
			LOG.info("REFRESH TOKEN: {}", refreshToken);

			tokens.setAccessToken(accessToken.getAccessToken());
			tokens.setRefreshToken(refreshToken);

		} catch (IOException | InterruptedException | ExecutionException e) {
			LOG.error("Auth error", e);
			throw new OAuthAuthenticationException(e.getMessage());
		}
	}

	/**
	 * Me.
	 *
	 * @return the string
	 * @throws OAuthAuthenticationException when authentication fails
	 * @throws PleaseRetryException exception indicating the call should be attempted again
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String me() throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/me");
	}

	/**
	 * Gets the crop.
	 *
	 * @param shortName the short name
	 * @return the crop
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String getCrop(final String shortName) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		if (!shortName.matches("^\\w+$")) {
			throw new GenesysApiException("Crop shortname can only contain characters");
		}
		return query("/crops/" + shortName);
	}

	/**
	 * List parameters.
	 *
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String listParameters() throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/kpi/parameter/list");
	}

	/**
	 * Put parameter.
	 *
	 * @param node the node
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String putParameter(final ObjectNode node) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/kpi/parameter", null, node.toString());
	}

	/**
	 * Gets the parameter.
	 *
	 * @param name the name
	 * @return the parameter
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String getParameter(final String name) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/kpi/parameter/" + name);
	}

	/**
	 * List dimensions.
	 *
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String listDimensions() throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/kpi/dimension/list");
	}

	/**
	 * Gets the dimension.
	 *
	 * @param id the id
	 * @return the dimension
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String getDimension(final long id) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/kpi/dimension/" + id);
	}

	/**
	 * Put dimension.
	 *
	 * @param node the node
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String putDimension(final ObjectNode node) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/kpi/dimension", null, node.toString());
	}

	/**
	 * List executions.
	 *
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String listExecutions() throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/kpi/execution/list");
	}

	/**
	 * Gets the execution.
	 *
	 * @param name the name
	 * @return the execution
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String getExecution(final String name) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/kpi/execution/" + name);
	}

	/**
	 * Put execution.
	 *
	 * @param node the node
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String putExecution(final ObjectNode node) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/kpi/execution", null, node.toString());
	}

	/**
	 * Kpi execute.
	 *
	 * @param name the name
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String kpiExecute(final String name) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/kpi/execution/" + name + "/execute", null, null);
	}

	/**
	 * Delete dimension.
	 *
	 * @param id the id
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String deleteDimension(final long id) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.DELETE, "/kpi/dimension/" + id, null, null);
	}

	/**
	 * Delete execution.
	 *
	 * @param name the name
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String deleteExecution(final String name) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.DELETE, "/kpi/execution/" + name, null, null);
	}

	/**
	 * Delete parameter.
	 *
	 * @param name the name
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String deleteParameter(final String name) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.DELETE, "/kpi/parameter/" + name, null, null);
	}

	/**
	 * List crops.
	 *
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String listCrops() throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/crops");
	}

	/**
	 * Put crop.
	 *
	 * @param node the node
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String putCrop(final ObjectNode node) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/crops", null, node.toString());
	}

	/**
	 * Delete crop.
	 *
	 * @param shortName the short name
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String deleteCrop(final String shortName) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.DELETE, "/crops/" + shortName, null, null);
	}

	/**
	 * Gets the crop rules.
	 *
	 * @param shortName the short name
	 * @return the crop rules
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String getCropRules(final String shortName) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/crops/" + shortName + "/rules");
	}

	/**
	 * Put crop rules.
	 *
	 * @param shortName the short name
	 * @param currentCropRules the current crop rules
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String putCropRules(final String shortName, final ArrayNode currentCropRules) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.PUT, "/crops/" + shortName + "/rules", null, currentCropRules.toString());
	}

	/**
	 * Rebuild crop taxa.
	 *
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String rebuildCropTaxa() throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/crops/rebuild", null, null);
	}

	/**
	 * Rebuild crop taxa.
	 *
	 * @param shortName the short name
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String rebuildCropTaxa(final String shortName) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/crops/" + shortName + "/rebuild", null, null);
	}

	/**
	 * List organizations.
	 *
	 * @param page the page
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String listOrganizations(final int page) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		final Map qs = new HashMap();
		qs.put("page", String.valueOf(page));
		return query(Verb.GET, "/org", qs, null);
	}

	/**
	 * Gets the organization.
	 *
	 * @param slug the slug
	 * @return the organization
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String getOrganization(final String slug) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/org/" + slug);
	}

	/**
	 * Update organization.
	 *
	 * @param org the org
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String updateOrganization(final ObjectNode org) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.POST, "/org", null, org.toString());
	}

	/**
	 * Delete organization.
	 *
	 * @param slug the slug
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String deleteOrganization(final String slug) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.DELETE, "/org/" + slug, null, null);
	}

	/**
	 * Gets the organization members.
	 *
	 * @param slug the slug
	 * @return the organization members
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String getOrganizationMembers(final String slug) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/org/" + slug + "/institutes");
	}

	/**
	 * Put organization members.
	 *
	 * @param slug the slug
	 * @param currentMembers the current members
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String putOrganizationMembers(final String slug, final ArrayNode currentMembers) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.PUT, "/org/" + slug + "/set-institutes", null, currentMembers.toString());
	}

	/**
	 * Gets the organization blurp.
	 *
	 * @param slug the slug
	 * @param language the language
	 * @return the organization blurp
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String getOrganizationBlurp(final String slug, final String language) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query("/org/" + slug + "/blurp/" + language);
	}

	/**
	 * Update organization blurp.
	 *
	 * @param slug the slug
	 * @param blurp the blurp
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String updateOrganizationBlurp(final String slug, final ObjectNode blurp) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		return query(Verb.PUT, "/org/" + slug + "/blurp", null, blurp.toString());
	}

	/**
	 * List observations.
	 *
	 * @param executionName the execution name
	 * @param dimensionFilter the dimension filter
	 * @param page the page
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String listObservations(final String executionName, final String dimensionFilter, final int page)
			throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		final Map qs = new HashMap();
		qs.put("page", String.valueOf(page));
		return query(Verb.POST, "/kpi/observation/" + executionName + "/", qs, StringUtils.defaultIfBlank(dimensionFilter, ""));
	}

	/**
	 * List accessions.
	 *
	 * @param instCode the inst code
	 * @param page the page
	 * @param query the query
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String listAccessions(final String instCode, final int page, final String query) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		final Map params = new HashMap();
		params.put("page", String.valueOf(page));
		params.put("query", query);
		return query(Verb.GET, "/acn/" + instCode + "/list", params, null);
	}

	/**
	 * List existing image galleries for INSTCODE. The response is paginated, provide page
	 * argument to request a specific page.
	 *
	 * @param instCode institute code (MCPD INSTCODE)
	 * @param page 1 for first page
	 * @return the string
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws HttpRedirectException the http redirect exception
	 * @throws GenesysApiException the Genesys API exception
	 */
	public String listGalleries(final String instCode, final int page) throws OAuthAuthenticationException, PleaseRetryException, HttpRedirectException, GenesysApiException {
		return query(Verb.GET, String.format("/img/%1$s/_galleries", instCode), Collections.singletonMap("page", Integer.toString(page)), null);
	}

	/**
	 * List UUIDs of images in an existing accession gallery.
	 *
	 * @param instCode institute code (MCPD INSTCODE)
	 * @param acceNumb the acce numb
	 * @return the list
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 * @throws JsonParseException the json parse exception
	 * @throws JsonMappingException the json mapping exception
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public List listGalleryImages(final String instCode, final String acceNumb)
			throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException, JsonParseException, JsonMappingException, IOException {

		final String json = query(Verb.GET, String.format("/img/%1$s/acn/%2$s", instCode));
		return objectMapper.readValue(json, new TypeReference>() {
		});
	}

	/**
	 * Add image to accession.
	 *
	 * @param instCode institute code (MCPD INSTCODE)
	 * @param acceNumb accession number (MCPD ACCENUMB)
	 * @param file image to upload
	 * @param contentType the content type
	 * @return the repository image
	 * @throws GenesysApiException the Genesys API exception
	 * @throws IOException if file cannot be read
	 */
	public RepositoryImage uploadImage(final String instCode, final String acceNumb, final File file, final String contentType) throws GenesysApiException, IOException {
		if (StringUtils.isBlank(contentType)) {
			throw new GenesysApiException("Content-Type must be provided for the file " + file.getAbsolutePath());
		}

		LOG.debug("Image content type: {}", contentType);

		// PUT file on server
		final String json = query(Verb.PUT, String.format("/img/%1$s/acn/%2$s/", instCode, acceNumb), Collections.singletonMap("originalFilename", file.getName()), contentType,
				FileUtils.readFileToByteArray(file));

		System.err.println(json);
		// Deserialize JSON
		return objectMapper.readValue(json, RepositoryImage.class);
	}

	/**
	 * Remove image from accession gallery by UUID. URL template:
	 * /img/{instCode}/acn/{acceNumb:.+}/{uuid}/_metadata
	 *
	 * @param instCode institute code (MCPD INSTCODE)
	 * @param acceNumb accession number (MCPD ACCENUMB)
	 * @param uuid Repository image UUID as assigned by Genesys
	 * @throws OAuthAuthenticationException authentication exception
	 * @throws PleaseRetryException exception indicating the call shold be re-attempted
	 * @throws GenesysApiException the Genesys API exception
	 */
	public void deleteImage(final String instCode, final String acceNumb, final UUID uuid) throws OAuthAuthenticationException, PleaseRetryException, GenesysApiException {
		query(Verb.DELETE, String.format("/img/%1$s/acn/%2$s/%3$s", instCode, acceNumb, uuid));
	}

	/**
	 * Get image metadata from Genesys.
	 *
	 * @param instCode institute code (MCPD INSTCODE)
	 * @param acceNumb accession number (MCPD ACCENUMB)
	 * @param uuid Repository image UUID as assigned by Genesys
	 * @return the metadata
	 * @throws GenesysApiException the Genesys API exception
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public RepositoryImage getImageMetadata(final String instCode, final String acceNumb, final UUID uuid) throws GenesysApiException, IOException {
		// PUT file on server
		final String json = query(Verb.GET, String.format("/img/%1$s/acn/%2$s/%3$s/_metadata", instCode, acceNumb, uuid));

		// Deserialize JSON
		return objectMapper.readValue(json, RepositoryImage.class);
	}

	/**
	 * Set image metadata. Endpoint PUT
	 * /img/{instCode}/acn/{acceNumb:.+}/{uuid}/_metadata
	 *
	 * @param instCode institute code (MCPD INSTCODE)
	 * @param acceNumb accession number (MCPD ACCENUMB)
	 * @param uuid Repository image UUID as assigned by Genesys
	 * @param imageData the image data
	 * @return the metadata
	 * @throws GenesysApiException the Genesys API exception
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public RepositoryImage putImageMetadata(final String instCode, final String acceNumb, final UUID uuid, final RepositoryImage imageData)
			throws GenesysApiException, IOException {
		final String json = query(Verb.PUT, String.format("/img/%1$s/acn/%2$s/%3$s/_metadata", instCode, acceNumb, uuid), null, imageData);

		// Deserialize JSON
		return objectMapper.readValue(json, RepositoryImage.class);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy