<commit_before>package uk.bl.odin.orcid.client;

import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.logging.Logger;

import javax.inject.Inject;
import javax.inject.Named;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import org.restlet.Context;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Parameter;
import org.restlet.data.Reference;
import org.restlet.engine.header.Header;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
import org.restlet.util.Series;

import uk.bl.odin.orcid.client.constants.OrcidAuthScope;
import uk.bl.odin.orcid.client.constants.OrcidConstants;
import uk.bl.odin.orcid.client.constants.OrcidExternalIdentifierType;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidActivities;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidBio;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidMessage;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidProfile;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidWork;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidWorks;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;

/**
 * General purpose ORCID client that supports simple OAuth scenarios
 * 
 * @see http://support.orcid.org/knowledgebase/articles/116874-orcid-api-guide
 *      Uses message 1.1
 *      https://raw.github.com/ORCID/ORCID-Source/master/orcid-model
 *      /src/main/resources/orcid-message-1.1.xsd
 */
@SuppressWarnings("restriction")
public class OrcidOAuthClient {

	private static final Logger log = Logger.getLogger(OrcidOAuthClient.class.getName());

	private static final String AUTHZ_ENDPOINT = "/oauth/authorize";
	private static final String TOKEN_ENDPOINT = "/oauth/token";
	private static final String WORK_CREATE_ENDPOINT = "/orcid-works";

	private static final String SANDBOX_LOGIN_URI = "https://sandbox.orcid.org";
	private static final String SANDBOX_API_URI_TOKEN = "https://api.sandbox.orcid.org";
	private static final String SANDBOX_API_URI_V1_1 = "http://api.sandbox.orcid.org/v1.1";
	
	private static final String LIVE_LOGIN_URI = "https://orcid.org";
	private static final String LIVE_API_URI_TOKEN = "https://api.orcid.org";
	private static final String LIVE_API_URI_V1_1 = "http://api.orcid.org/v1.1";

	private final String clientID;
	private final String clientSecret;
	private final String redirectUri;

	private final String loginUri;
	private final String apiUriToken;
	private final String apiUriV11;

	private final JAXBContext orcidMessageContext;

	/**
	 * Suitable for injection or manual construction. Thread safe.
	 * 
	 * @param clientID
	 *            OAuth credential
	 * @param clientSecret
	 *            OAuth credential
	 * @param redirectUri
	 *            OAuth credential
	 * @param sandbox
	 *            if true use sandbox endpoints
	 * @throws JAXBException
	 *             if we can't create a JaxB context
	 */
	@Inject
	public OrcidOAuthClient(@Named("OrcidClientID") String clientID, @Named("OrcidClientSecret") String clientSecret,
			@Named("OrcidReturnURI") String redirectUri, @Named("OrcidSandbox") boolean sandbox) throws JAXBException {
		if (clientID == null || clientSecret == null || redirectUri == null)
			throw new IllegalArgumentException("cannot create OrcidOAuthClient - missing init parameter(s)");
		if (sandbox) {
			this.loginUri = SANDBOX_LOGIN_URI;
			this.apiUriToken = <PASSWORD>OX_API_URI_TOKEN;
			this.apiUriV11 = SANDBOX_API_URI_V1_1;
		} else {
			this.loginUri = LIVE_LOGIN_URI;
			this.apiUriToken = LIVE_API_URI_TOKEN;
			this.apiUriV11 = LIVE_API_URI_V1_1;
		}
		this.clientID = clientID;
		this.clientSecret = clientSecret;
		this.redirectUri = redirectUri;
		orcidMessageContext = JAXBContext.newInstance(OrcidMessage.class);
	}

	/**
	 * Create a URL that can be used to request an accessCode
	 */
	public String getAuthzCodeRequest(String state, OrcidAuthScope scope) {
		return getAuthzCodeRequest(state) + "&scope=" + scope.toString();
	}

	/**
	 * Create a URL that can be used to request an accessCode
	 */
	public String getAuthzCodeRequest(String state, List<OrcidAuthScope> scopes) {
		return getAuthzCodeRequest(state) + "&scope=" + Joiner.on(" ").join(scopes);
	}

	private String getAuthzCodeRequest(String state) {
		String req = loginUri + AUTHZ_ENDPOINT;
		req += "?client_id=" + clientID;
		req += "&response_type=code";
		if (state != null)
			req += "&state=" + state;
		req += "&redirect_uri=" + redirectUri;
		return req;
	}

	/**
	 * Exchange and authorization code for an auth token from ORCID
	 * 
	 * @see http://support.orcid.org/knowledgebase/articles/120107
	 * @see http 
	 *      ://support.orcid.org/knowledgebase/articles/179969-methods-to-generate
	 *      -an-access-token-for-testing
	 * @param authorizationCode
	 * @return the parsed response
	 * @throws IOException
	 *             if result unparsable or network unreachable.
	 * @throws ResourceException
	 *             if there's a http problem (e.g. 404, 400)
	 */
	public OrcidAccessToken getAccessToken(String authorizationCode) throws IOException {
		Reference ref = new Reference(apiUriToken + TOKEN_ENDPOINT);
		ClientResource client = new ClientResource(ref);
		Form f = new Form();<commit_msg>Fixed NPE when context is empty<commit_after>package uk.bl.odin.orcid.client;

import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.logging.Logger;

import javax.inject.Inject;
import javax.inject.Named;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import org.restlet.Context;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Parameter;
import org.restlet.data.Reference;
import org.restlet.engine.header.Header;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
import org.restlet.util.Series;

import uk.bl.odin.orcid.client.constants.OrcidAuthScope;
import uk.bl.odin.orcid.client.constants.OrcidConstants;
import uk.bl.odin.orcid.client.constants.OrcidExternalIdentifierType;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidActivities;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidBio;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidMessage;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidProfile;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidWork;
import uk.bl.odin.orcid.schema.messages.onepointone.OrcidWorks;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;

/**
 * General purpose ORCID client that supports simple OAuth scenarios
 * 
 * @see http://support.orcid.org/knowledgebase/articles/116874-orcid-api-guide
 *      Uses message 1.1
 *      https://raw.github.com/ORCID/ORCID-Source/master/orcid-model
 *      /src/main/resources/orcid-message-1.1.xsd
 */
@SuppressWarnings("restriction")
public class OrcidOAuthClient {

	private static final Logger log = Logger.getLogger(OrcidOAuthClient.class.getName());

	private static final String AUTHZ_ENDPOINT = "/oauth/authorize";
	private static final String TOKEN_ENDPOINT = "/oauth/token";
	private static final String WORK_CREATE_ENDPOINT = "/orcid-works";

	private static final String SANDBOX_LOGIN_URI = "https://sandbox.orcid.org";
	private static final String SANDBOX_API_URI_TOKEN = "https://api.sandbox.orcid.org";
	private static final String SANDBOX_API_URI_V1_1 = "http://api.sandbox.orcid.org/v1.1";
	
	private static final String LIVE_LOGIN_URI = "https://orcid.org";
	private static final String LIVE_API_URI_TOKEN = "https://api.orcid.org";
	private static final String LIVE_API_URI_V1_1 = "http://api.orcid.org/v1.1";

	private final String clientID;
	private final String clientSecret;
	private final String redirectUri;

	private final String loginUri;
	private final String apiUriToken;
	private final String apiUriV11;

	private final JAXBContext orcidMessageContext;

	/**
	 * Suitable for injection or manual construction. Thread safe.
	 * 
	 * @param clientID
	 *            OAuth credential
	 * @param clientSecret
	 *            OAuth credential
	 * @param redirectUri
	 *            OAuth credential
	 * @param sandbox
	 *            if true use sandbox endpoints
	 * @throws JAXBException
	 *             if we can't create a JaxB context
	 */
	@Inject
	public OrcidOAuthClient(@Named("OrcidClientID") String clientID, @Named("OrcidClientSecret") String clientSecret,
			@Named("OrcidReturnURI") String redirectUri, @Named("OrcidSandbox") boolean sandbox) throws JAXBException {
		if (clientID == null || clientSecret == null || redirectUri == null)
			throw new IllegalArgumentException("cannot create OrcidOAuthClient - missing init parameter(s)");
		if (sandbox) {
			this.loginUri = SANDBOX_LOGIN_URI;
			this.apiUriToken = SANDBOX_API_URI_TOKEN;
			this.apiUriV11 = SANDBOX_API_URI_V1_1;
		} else {
			this.loginUri = LIVE_LOGIN_URI;
			this.apiUriToken = LIVE_API_URI_TOKEN;
			this.apiUriV11 = LIVE_API_URI_V1_1;
		}
		this.clientID = clientID;
		this.clientSecret = clientSecret;
		this.redirectUri = redirectUri;
		orcidMessageContext = JAXBContext.newInstance(OrcidMessage.class);
	}

	/**
	 * Create a URL that can be used to request an accessCode
	 */
	public String getAuthzCodeRequest(String state, OrcidAuthScope scope) {
		return getAuthzCodeRequest(state) + "&scope=" + scope.toString();
	}

	/**
	 * Create a URL that can be used to request an accessCode
	 */
	public String getAuthzCodeRequest(String state, List<OrcidAuthScope> scopes) {
		return getAuthzCodeRequest(state) + "&scope=" + Joiner.on(" ").join(scopes);
	}

	private String getAuthzCodeRequest(String state) {
		String req = loginUri + AUTHZ_ENDPOINT;
		req += "?client_id=" + clientID;
		req += "&response_type=code";
		if (state != null)
			req += "&state=" + state;
		req += "&redirect_uri=" + redirectUri;
		return req;
	}

	/**
	 * Exchange and authorization code for an auth token from ORCID
	 * 
	 * @see http://support.orcid.org/knowledgebase/articles/120107
	 * @see http 
	 *      ://support.orcid.org/knowledgebase/articles/179969-methods-to-generate
	 *      -an-access-token-for-testing
	 * @param authorizationCode
	 * @return the parsed response
	 * @throws IOException
	 *             if result unparsable or network unreachable.
	 * @throws ResourceException
	 *             if there's a http problem (e.g. 404, 400)
	 */
	public OrcidAccessToken getAccessToken(String authorizationCode) throws IOException {
		Reference ref = new Reference(apiUriToken + TOKEN_ENDPOINT);
		if (Context.getCurrent() == null) {
			Context.setCurrent(new Context());
		}
		ClientResource client = new ClientResource(ref);
		Form f = new Form();
{'fraction_non_alphanumeric': 0.10620190131281122, 'fraction_numerical': 0.008329560887279312, 'mean_word_length': 4.359534206695779, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 6, 'https://': 10, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1887755', 'n_tokens_mistral': 3793, 'n_tokens_neox': 3528, 'n_words': 781}