From c92eef3de7b63e4d9f8d4dfda4060d8182401db6 Mon Sep 17 00:00:00 2001 From: duane Date: Fri, 20 Sep 2013 13:53:34 -0400 Subject: [PATCH 01/11] Update README.textile Update the readme to show the fork --- README.textile | 97 +++----------------------------------------------- 1 file changed, 4 insertions(+), 93 deletions(-) diff --git a/README.textile b/README.textile index e1726c94f..efa99cdcb 100644 --- a/README.textile +++ b/README.textile @@ -1,95 +1,6 @@ -h2. Welcome to the home of Scribe, the simple OAuth Java lib! +h2. This is a fork of scribe for java 1.4 -!https://secure.travis-ci.org/fernandezpablo85/scribe-java.png?branch=master(travis-ci-status)! +I have not changed any functionality. I only updated the code to make it compile with a 1.4 compiler. -h2. Before submitting a pull request "please read this":https://github.com/fernandezpablo85/scribe-java/wiki/Scribe-scope-revised - -h1. Why use Scribe? - -h3. Dead Simple - -Who said OAuth was difficult? Configuring scribe is __so easy your grandma can do it__! check it out: - -@OAuthService service = new ServiceBuilder()@ - @.provider(LinkedInApi.class)@ - @.apiKey(YOUR_API_KEY)@ - @.apiSecret(YOUR_API_SECRET)@ - @.build();@ - -That **single line** (added newlines for readability) is the only thing you need to configure scribe with LinkedIn's OAuth API for example. - -h3. Threadsafe - -Hit Scribe as hard and with many threads as you like. - -h3. Supports all major 1.0a and 2.0 OAuth APIs out-of-the-box - -* Google - -* Facebook - -* Yahoo - -* LinkedIn - -* Twitter - -* Foursquare - -* Evernote - -* Vimeo - -* Yammer - -* Windows Live - -* and many more! check the "examples folder":http://github.com/fernandezpablo85/scribe-java/tree/master/src/test/java/org/scribe/examples - -h3. Small and modular - -Scribe's code is small (about 1k LOC) and simple to understand. No smart-ass or "clever" hacks here. - -h3. Android-Ready - -Works out of the box with android(TM) applications. - -h3. Stable & bulletproof - -Good test coverage to keep you safe from harm. - -When something bad actually happens, Scribe's meaningful error messages will tell you exactly what went wrong, when and where. - -h3. Pull it from Maven! (new) - -You can pull scribe from a maven repository, just add this to your __pom.xml__ file: - -@@ - @org.scribe@ - @scribe@ - @1.3.5@ -@@ - -h1. Getting started in less than 2 minutes - -Check the "Getting Started":http://wiki.github.com/fernandezpablo85/scribe-java/getting-started page and start rocking! - -h1. Please Read the "FAQ":http://wiki.github.com/fernandezpablo85/scribe-java/faq before creating an issue :) - -h1. Questions? - -Feel free to drop me an email, but there's already a "StackOverflow":http://stackoverflow.com tag for "scribe":http://stackoverflow.com/questions/tagged/scribe you should use. I'm subscribed to it so I'll pick the question immediately. - -Note that it really helps to run scribe on "debug mode":https://github.com/fernandezpablo85/scribe-java/wiki/debug-mode (since 1.3.0), to get additional info. To do this simply call the @.debug()@ method on the @ServiceBuilder@. - -h1. Forks - -Looking for a scribe variation? check the "Fork List":https://github.com/fernandezpablo85/scribe-java/wiki/Forks - -If you have a useful fork that should be listed there please contact me (see About me). - -h1. About me - -"LinkedIn profile":http://www.linkedin.com/in/fernandezpablo85 - -Follow me: "@fernandezpablo":http://twitter.com/fernandezpablo +Please see the original product for more information. If you find an issue in my translation of the project, +please let me know. thanks! From e9d575d98cf34cf2a5611b16f80e89739e1406aa Mon Sep 17 00:00:00 2001 From: Duane Musser Date: Mon, 23 Sep 2013 11:36:33 -0400 Subject: [PATCH 02/11] change to 1.4 compatability --- .gitignore | 3 +- build.xml | 58 ++ .../org/scribe/builder/ServiceBuilder.java | 294 ++++---- .../org/scribe/builder/api/AWeberApi.java | 37 +- .../builder/api/ConstantContactApi.java | 31 +- .../builder/api/ConstantContactApi2.java | 99 ++- .../java/org/scribe/builder/api/DiggApi.java | 33 +- .../org/scribe/builder/api/DropBoxApi.java | 6 +- .../org/scribe/builder/api/EvernoteApi.java | 74 +- .../org/scribe/builder/api/FacebookApi.java | 44 +- .../org/scribe/builder/api/FlickrApi.java | 6 +- .../scribe/builder/api/Foursquare2Api.java | 41 +- .../org/scribe/builder/api/FoursquareApi.java | 33 +- .../org/scribe/builder/api/FreelancerApi.java | 89 +-- .../org/scribe/builder/api/GetGlueApi.java | 33 +- .../org/scribe/builder/api/GoogleApi.java | 52 +- .../java/org/scribe/builder/api/ImgUrApi.java | 30 +- .../org/scribe/builder/api/KaixinApi.java | 52 +- .../org/scribe/builder/api/KaixinApi20.java | 50 +- .../org/scribe/builder/api/LinkedInApi.java | 102 ++- .../java/org/scribe/builder/api/LiveApi.java | 54 +- .../org/scribe/builder/api/LoveFilmApi.java | 33 +- .../org/scribe/builder/api/MeetupApi.java | 29 +- .../org/scribe/builder/api/MendeleyApi.java | 60 +- .../java/org/scribe/builder/api/MisoApi.java | 33 +- .../org/scribe/builder/api/NetProspexApi.java | 33 +- .../scribe/builder/api/NeteaseWeibooApi.java | 70 +- .../java/org/scribe/builder/api/PlurkApi.java | 46 +- .../java/org/scribe/builder/api/Px500Api.java | 35 +- .../org/scribe/builder/api/QWeiboApi.java | 35 +- .../org/scribe/builder/api/RenrenApi.java | 50 +- .../java/org/scribe/builder/api/SapoApi.java | 52 +- .../org/scribe/builder/api/SimpleGeoApi.java | 6 +- .../org/scribe/builder/api/SinaWeiboApi.java | 35 +- .../scribe/builder/api/SinaWeiboApi20.java | 59 +- .../org/scribe/builder/api/SkyrockApi.java | 41 +- .../org/scribe/builder/api/SohuWeiboApi.java | 35 +- .../org/scribe/builder/api/TrelloApi.java | 35 +- .../org/scribe/builder/api/TumblrApi.java | 33 +- .../org/scribe/builder/api/TwitterApi.java | 91 +-- .../org/scribe/builder/api/UbuntuOneApi.java | 50 +- .../org/scribe/builder/api/ViadeoApi.java | 50 +- .../java/org/scribe/builder/api/VimeoApi.java | 33 +- .../org/scribe/builder/api/VkontakteApi.java | 53 +- .../java/org/scribe/builder/api/XingApi.java | 35 +- .../java/org/scribe/builder/api/YahooApi.java | 33 +- .../org/scribe/builder/api/YammerApi.java | 42 +- .../exceptions/OAuthConnectionException.java | 20 +- .../OAuthParametersMissingException.java | 27 +- .../exceptions/OAuthSignatureException.java | 28 +- .../extractors/BaseStringExtractorImpl.java | 67 +- .../scribe/extractors/HeaderExtractor.java | 2 +- .../extractors/HeaderExtractorImpl.java | 72 +- .../java/org/scribe/model/OAuthRequest.java | 96 ++- src/main/java/org/scribe/model/Parameter.java | 84 ++- .../java/org/scribe/model/ParameterList.java | 178 +++-- src/main/java/org/scribe/model/Request.java | 684 +++++++++--------- src/main/java/org/scribe/model/Response.java | 195 +++-- .../java/org/scribe/model/SignatureType.java | 59 +- src/main/java/org/scribe/model/Token.java | 167 ++--- src/main/java/org/scribe/model/Verb.java | 69 +- src/main/java/org/scribe/model/Verifier.java | 2 +- .../org/scribe/oauth/OAuth10aServiceImpl.java | 366 +++++----- .../org/scribe/oauth/OAuth20ServiceImpl.java | 142 ++-- .../java/org/scribe/oauth/OAuthService.java | 87 ++- .../org/scribe/services/CommonsEncoder.java | 4 +- .../services/DatatypeConverterEncoder.java | 4 +- .../org/scribe/services/TimestampService.java | 2 +- .../scribe/services/TimestampServiceImpl.java | 94 ++- src/main/java/org/scribe/utils/MapUtils.java | 34 +- .../java/org/scribe/utils/OAuthEncoder.java | 97 ++- 71 files changed, 2367 insertions(+), 2541 deletions(-) create mode 100644 build.xml diff --git a/.gitignore b/.gitignore index a9a50de0e..2c3c951ae 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ scribe.iml # Binaries -target \ No newline at end of file +target +build \ No newline at end of file diff --git a/build.xml b/build.xml new file mode 100644 index 000000000..4dac9f523 --- /dev/null +++ b/build.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/scribe/builder/ServiceBuilder.java b/src/main/java/org/scribe/builder/ServiceBuilder.java index 27f3c8f63..01cbf1482 100644 --- a/src/main/java/org/scribe/builder/ServiceBuilder.java +++ b/src/main/java/org/scribe/builder/ServiceBuilder.java @@ -1,11 +1,14 @@ package org.scribe.builder; -import java.io.*; -import org.scribe.builder.api.*; -import org.scribe.exceptions.*; -import org.scribe.model.*; -import org.scribe.oauth.*; -import org.scribe.utils.*; +import java.io.OutputStream; + +import org.scribe.builder.api.Api; +import org.scribe.exceptions.OAuthException; +import org.scribe.model.OAuthConfig; +import org.scribe.model.OAuthConstants; +import org.scribe.model.SignatureType; +import org.scribe.oauth.OAuthService; +import org.scribe.utils.Preconditions; /** * Implementation of the Builder pattern, with a fluent interface that creates a @@ -14,156 +17,147 @@ * @author Pablo Fernandez * */ -public class ServiceBuilder -{ - private String apiKey; - private String apiSecret; - private String callback; - private Api api; - private String scope; - private SignatureType signatureType; - private OutputStream debugStream; - - /** - * Default constructor - */ - public ServiceBuilder() - { - this.callback = OAuthConstants.OUT_OF_BAND; - this.signatureType = SignatureType.Header; - this.debugStream = null; - } - - /** - * Configures the {@link Api} - * - * @param apiClass the class of one of the existent {@link Api}s on org.scribe.api package - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder provider(Class apiClass) - { - this.api = createApi(apiClass); - return this; - } +public class ServiceBuilder { + private String apiKey; + private String apiSecret; + private String callback; + private Api api; + private String scope; + private SignatureType signatureType; + private OutputStream debugStream; - private Api createApi(Class apiClass) - { - Preconditions.checkNotNull(apiClass, "Api class cannot be null"); - Api api; - try - { - api = apiClass.newInstance(); + /** + * Default constructor + */ + public ServiceBuilder() { + callback = OAuthConstants.OUT_OF_BAND; + signatureType = SignatureType.Header; + debugStream = null; } - catch(Exception e) - { - throw new OAuthException("Error while creating the Api object", e); + + /** + * Configures the {@link Api} + * + * @param apiClass the class of one of the existent {@link Api}s on org.scribe.api package + * @return the {@link ServiceBuilder} instance for method chaining + */ + public ServiceBuilder provider(final Class/**/apiClass) { + api = createApi(apiClass); + return this; } - return api; - } - /** - * Configures the {@link Api} - * - * Overloaded version. Let's you use an instance instead of a class. - * - * @param api instance of {@link Api}s - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder provider(Api api) - { - Preconditions.checkNotNull(api, "Api cannot be null"); - this.api = api; - return this; - } + private Api createApi(final Class/**/apiClass) { + Preconditions.checkNotNull(apiClass, "Api class cannot be null"); + final Api api; + try { + final Object o = apiClass.newInstance(); + if (o instanceof Api) { + api = (Api) o; + } else { + throw new IllegalArgumentException(String.valueOf(apiClass) + " is not an API"); + } + } catch (final Exception e) { + throw new OAuthException("Error while creating the Api object", e); + } + return api; + } - /** - * Adds an OAuth callback url - * - * @param callback callback url. Must be a valid url or 'oob' for out of band OAuth - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder callback(String callback) - { - Preconditions.checkNotNull(callback, "Callback can't be null"); - this.callback = callback; - return this; - } - - /** - * Configures the api key - * - * @param apiKey The api key for your application - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder apiKey(String apiKey) - { - Preconditions.checkEmptyString(apiKey, "Invalid Api key"); - this.apiKey = apiKey; - return this; - } - - /** - * Configures the api secret - * - * @param apiSecret The api secret for your application - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder apiSecret(String apiSecret) - { - Preconditions.checkEmptyString(apiSecret, "Invalid Api secret"); - this.apiSecret = apiSecret; - return this; - } - - /** - * Configures the OAuth scope. This is only necessary in some APIs (like Google's). - * - * @param scope The OAuth scope - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder scope(String scope) - { - Preconditions.checkEmptyString(scope, "Invalid OAuth scope"); - this.scope = scope; - return this; - } + /** + * Configures the {@link Api} + * + * Overloaded version. Let's you use an instance instead of a class. + * + * @param api instance of {@link Api}s + * @return the {@link ServiceBuilder} instance for method chaining + */ + public ServiceBuilder provider(final Api api) { + Preconditions.checkNotNull(api, "Api cannot be null"); + this.api = api; + return this; + } - /** - * Configures the signature type, choose between header, querystring, etc. Defaults to Header - * - * @param scope The OAuth scope - * @return the {@link ServiceBuilder} instance for method chaining - */ - public ServiceBuilder signatureType(SignatureType type) - { - Preconditions.checkNotNull(type, "Signature type can't be null"); - this.signatureType = type; - return this; - } + /** + * Adds an OAuth callback url + * + * @param callback callback url. Must be a valid url or 'oob' for out of band OAuth + * @return the {@link ServiceBuilder} instance for method chaining + */ + public ServiceBuilder callback(final String callback) { + Preconditions.checkNotNull(callback, "Callback can't be null"); + this.callback = callback; + return this; + } - public ServiceBuilder debugStream(OutputStream stream) - { - Preconditions.checkNotNull(stream, "debug stream can't be null"); - this.debugStream = stream; - return this; - } + /** + * Configures the api key + * + * @param apiKey The api key for your application + * @return the {@link ServiceBuilder} instance for method chaining + */ + public ServiceBuilder apiKey(final String apiKey) { + Preconditions.checkEmptyString(apiKey, "Invalid Api key"); + this.apiKey = apiKey; + return this; + } + + /** + * Configures the api secret + * + * @param apiSecret The api secret for your application + * @return the {@link ServiceBuilder} instance for method chaining + */ + public ServiceBuilder apiSecret(final String apiSecret) { + Preconditions.checkEmptyString(apiSecret, "Invalid Api secret"); + this.apiSecret = apiSecret; + return this; + } - public ServiceBuilder debug() - { - this.debugStream(System.out); - return this; - } - - /** - * Returns the fully configured {@link OAuthService} - * - * @return fully configured {@link OAuthService} - */ - public OAuthService build() - { - Preconditions.checkNotNull(api, "You must specify a valid api through the provider() method"); - Preconditions.checkEmptyString(apiKey, "You must provide an api key"); - Preconditions.checkEmptyString(apiSecret, "You must provide an api secret"); - return api.createService(new OAuthConfig(apiKey, apiSecret, callback, signatureType, scope, debugStream)); - } + /** + * Configures the OAuth scope. This is only necessary in some APIs (like Google's). + * + * @param scope The OAuth scope + * @return the {@link ServiceBuilder} instance for method chaining + */ + public ServiceBuilder scope(final String scope) { + Preconditions.checkEmptyString(scope, "Invalid OAuth scope"); + this.scope = scope; + return this; + } + + /** + * Configures the signature type, choose between header, querystring, etc. Defaults to Header + * + * @param scope The OAuth scope + * @return the {@link ServiceBuilder} instance for method chaining + */ + public ServiceBuilder signatureType(final SignatureType type) { + Preconditions.checkNotNull(type, "Signature type can't be null"); + signatureType = type; + return this; + } + + public ServiceBuilder debugStream(final OutputStream stream) { + Preconditions.checkNotNull(stream, "debug stream can't be null"); + debugStream = stream; + return this; + } + + public ServiceBuilder debug() { + this.debugStream(System.out); + return this; + } + + /** + * Returns the fully configured {@link OAuthService} + * + * @return fully configured {@link OAuthService} + */ + public OAuthService build() { + Preconditions.checkNotNull(api, + "You must specify a valid api through the provider() method"); + Preconditions.checkEmptyString(apiKey, "You must provide an api key"); + Preconditions.checkEmptyString(apiSecret, "You must provide an api secret"); + return api.createService(new OAuthConfig(apiKey, apiSecret, callback, signatureType, scope, + debugStream)); + } } diff --git a/src/main/java/org/scribe/builder/api/AWeberApi.java b/src/main/java/org/scribe/builder/api/AWeberApi.java index 53ae1fc7f..28c4c093c 100644 --- a/src/main/java/org/scribe/builder/api/AWeberApi.java +++ b/src/main/java/org/scribe/builder/api/AWeberApi.java @@ -2,27 +2,20 @@ import org.scribe.model.Token; -public class AWeberApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://auth.aweber.com/1.0/oauth/authorize?oauth_token=%s"; - private static final String REQUEST_TOKEN_ENDPOINT = "https://auth.aweber.com/1.0/oauth/request_token"; - private static final String ACCESS_TOKEN_ENDPOINT = "https://auth.aweber.com/1.0/oauth/access_token"; - - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_ENDPOINT; - } +public class AWeberApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://auth.aweber.com/1.0/oauth/authorize?oauth_token="; + private static final String REQUEST_TOKEN_ENDPOINT = "https://auth.aweber.com/1.0/oauth/request_token"; + private static final String ACCESS_TOKEN_ENDPOINT = "https://auth.aweber.com/1.0/oauth/access_token"; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_ENDPOINT; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_ENDPOINT; + } + + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_ENDPOINT; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/ConstantContactApi.java b/src/main/java/org/scribe/builder/api/ConstantContactApi.java index 0588bc40c..2bad4f2ff 100644 --- a/src/main/java/org/scribe/builder/api/ConstantContactApi.java +++ b/src/main/java/org/scribe/builder/api/ConstantContactApi.java @@ -1,26 +1,19 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class ConstantContactApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://oauth.constantcontact.com/ws/oauth/confirm_access?oauth_token=%s"; +public class ConstantContactApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://oauth.constantcontact.com/ws/oauth/confirm_access?oauth_token="; - @Override - public String getAccessTokenEndpoint() - { - return "https://oauth.constantcontact.com/ws/oauth/access_token"; - } + public String getAccessTokenEndpoint() { + return "https://oauth.constantcontact.com/ws/oauth/access_token"; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } - @Override - public String getRequestTokenEndpoint() - { - return "https://oauth.constantcontact.com/ws/oauth/request_token"; - } + public String getRequestTokenEndpoint() { + return "https://oauth.constantcontact.com/ws/oauth/request_token"; + } } diff --git a/src/main/java/org/scribe/builder/api/ConstantContactApi2.java b/src/main/java/org/scribe/builder/api/ConstantContactApi2.java index b5e4cac27..870c5d21d 100644 --- a/src/main/java/org/scribe/builder/api/ConstantContactApi2.java +++ b/src/main/java/org/scribe/builder/api/ConstantContactApi2.java @@ -1,55 +1,50 @@ package org.scribe.builder.api; -import java.util.regex.*; -import org.scribe.exceptions.*; -import org.scribe.extractors.*; -import org.scribe.model.*; -import org.scribe.utils.*; - -public class ConstantContactApi2 extends DefaultApi20 -{ - private static final String AUTHORIZE_URL = "https://oauth2.constantcontact.com/oauth2/oauth/siteowner/authorize?client_id=%s&response_type=code&redirect_uri=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "https://oauth2.constantcontact.com/oauth2/oauth/token?grant_type=authorization_code"; - } - - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); - } - - @Override - public Verb getAccessTokenVerb() - { - return Verb.POST; - } - - @Override - public AccessTokenExtractor getAccessTokenExtractor() - { - return new AccessTokenExtractor() - { - - public Token extract(String response) - { - Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string"); - - String regex = "\"access_token\"\\s*:\\s*\"([^&\"]+)\""; - Matcher matcher = Pattern.compile(regex).matcher(response); - if (matcher.find()) - { - String token = OAuthEncoder.decode(matcher.group(1)); - return new Token(token, "", response); - } - else - { - throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null); - } - } - }; - } +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.scribe.exceptions.OAuthException; +import org.scribe.extractors.AccessTokenExtractor; +import org.scribe.model.OAuthConfig; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; + +public class ConstantContactApi2 extends DefaultApi20 { + private static final String AUTHORIZE_URL = "https://oauth2.constantcontact.com/oauth2/oauth/siteowner/authorize?client_id=%clienId%&response_type=code&redirect_uri=%redirectUri%"; + + public String getAccessTokenEndpoint() { + return "https://oauth2.constantcontact.com/oauth2/oauth/token?grant_type=authorization_code"; + } + + public String getAuthorizationUrl(final OAuthConfig config) { + return AUTHORIZE_URL.replace("%clientId%", config.getApiKey()).replace("%redirectUri%", + OAuthEncoder.encode(config.getCallback())); + } + + public Verb getAccessTokenVerb() { + return Verb.POST; + } + + public AccessTokenExtractor getAccessTokenExtractor() { + return new AccessTokenExtractor() { + + public Token extract(final String response) { + Preconditions.checkEmptyString(response, + "Response body is incorrect. Can't extract a token from an empty string"); + + final String regex = "\"access_token\"\\s*:\\s*\"([^&\"]+)\""; + final Matcher matcher = Pattern.compile(regex).matcher(response); + if (matcher.find()) { + final String token = OAuthEncoder.decode(matcher.group(1)); + return new Token(token, "", response); + } else { + throw new OAuthException( + "Response body is incorrect. Can't extract a token from this: '" + + response + "'", null); + } + } + }; + } } \ No newline at end of file diff --git a/src/main/java/org/scribe/builder/api/DiggApi.java b/src/main/java/org/scribe/builder/api/DiggApi.java index b69253eb9..03486f5c2 100644 --- a/src/main/java/org/scribe/builder/api/DiggApi.java +++ b/src/main/java/org/scribe/builder/api/DiggApi.java @@ -1,29 +1,22 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class DiggApi extends DefaultApi10a -{ +public class DiggApi extends DefaultApi10a { - private static final String AUTHORIZATION_URL = "http://digg.com/oauth/authorize?oauth_token=%s"; - private static final String BASE_URL = "http://services.digg.com/oauth/"; + private static final String AUTHORIZE_URL = "http://digg.com/oauth/authorize?oauth_token="; + private static final String BASE_URL = "http://services.digg.com/oauth/"; - @Override - public String getRequestTokenEndpoint() - { - return BASE_URL + "request_token"; - } + public String getRequestTokenEndpoint() { + return BASE_URL + "request_token"; + } - @Override - public String getAccessTokenEndpoint() - { - return BASE_URL + "access_token"; - } + public String getAccessTokenEndpoint() { + return BASE_URL + "access_token"; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/DropBoxApi.java b/src/main/java/org/scribe/builder/api/DropBoxApi.java index 86f4a71a1..641278857 100644 --- a/src/main/java/org/scribe/builder/api/DropBoxApi.java +++ b/src/main/java/org/scribe/builder/api/DropBoxApi.java @@ -4,19 +4,19 @@ public class DropBoxApi extends DefaultApi10a { - @Override + public String getAccessTokenEndpoint() { return "https://api.dropbox.com/1/oauth/access_token"; } - @Override + public String getAuthorizationUrl(Token requestToken) { return "https://www.dropbox.com/1/oauth/authorize?oauth_token="+requestToken.getToken(); } - @Override + public String getRequestTokenEndpoint() { return "https://api.dropbox.com/1/oauth/request_token"; diff --git a/src/main/java/org/scribe/builder/api/EvernoteApi.java b/src/main/java/org/scribe/builder/api/EvernoteApi.java index 007f48b1e..3ac9b707b 100644 --- a/src/main/java/org/scribe/builder/api/EvernoteApi.java +++ b/src/main/java/org/scribe/builder/api/EvernoteApi.java @@ -2,48 +2,34 @@ import org.scribe.model.Token; -public class EvernoteApi extends DefaultApi10a -{ - private static final String AUTHORIZATION_URL = "https://www.evernote.com/OAuth.action?oauth_token=%s"; - - @Override - public String getRequestTokenEndpoint() - { - return "https://www.evernote.com/oauth"; - } - - @Override - public String getAccessTokenEndpoint() - { - return "https://www.evernote.com/oauth"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } - - public static class Sandbox extends EvernoteApi - { - private static final String SANDBOX_URL = "https://sandbox.evernote.com"; - - @Override - public String getRequestTokenEndpoint() - { - return SANDBOX_URL + "/oauth"; - } - - @Override - public String getAccessTokenEndpoint() - { - return SANDBOX_URL + "/oauth"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(SANDBOX_URL + "/OAuth.action?oauth_token=%s", requestToken.getToken()); - } - } +public class EvernoteApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://www.evernote.com/OAuth.action?oauth_token="; + + public String getRequestTokenEndpoint() { + return "https://www.evernote.com/oauth"; + } + + public String getAccessTokenEndpoint() { + return "https://www.evernote.com/oauth"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } + + public static class Sandbox extends EvernoteApi { + private static final String SANDBOX_URL = "https://sandbox.evernote.com"; + + public String getRequestTokenEndpoint() { + return SANDBOX_URL + "/oauth"; + } + + public String getAccessTokenEndpoint() { + return SANDBOX_URL + "/oauth"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return SANDBOX_URL + "/OAuth.action?oauth_token=" + requestToken.getToken(); + } + } } diff --git a/src/main/java/org/scribe/builder/api/FacebookApi.java b/src/main/java/org/scribe/builder/api/FacebookApi.java index 996a651e1..61fcb0164 100644 --- a/src/main/java/org/scribe/builder/api/FacebookApi.java +++ b/src/main/java/org/scribe/builder/api/FacebookApi.java @@ -1,33 +1,27 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.OAuthConfig; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; -import org.scribe.utils.*; +public class FacebookApi extends DefaultApi20 { + private static final String AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?client_id=%clientId%&redirect_uri=%redirectUri%"; + private static final String SCOPED_PARAMETER = "&scope="; -public class FacebookApi extends DefaultApi20 -{ - private static final String AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?client_id=%s&redirect_uri=%s"; - private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "https://graph.facebook.com/oauth/access_token"; - } + public String getAccessTokenEndpoint() { + return "https://graph.facebook.com/oauth/access_token"; + } - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Facebook does not support OOB"); + public String getAuthorizationUrl(final OAuthConfig config) { + Preconditions.checkValidUrl(config.getCallback(), + "Must provide a valid url as callback. Facebook does not support OOB"); - // Append scope if present - if(config.hasScope()) - { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope())); - } - else - { - return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); + // Append scope if present + String result = AUTHORIZE_URL.replace("%clientId%", config.getApiKey()).replace( + "redirectUri", OAuthEncoder.encode(config.getCallback())); + if (config.hasScope()) { + result = result + SCOPED_PARAMETER + config.getScope(); + } + return result; } - } } diff --git a/src/main/java/org/scribe/builder/api/FlickrApi.java b/src/main/java/org/scribe/builder/api/FlickrApi.java index a63043610..f606d2fbe 100644 --- a/src/main/java/org/scribe/builder/api/FlickrApi.java +++ b/src/main/java/org/scribe/builder/api/FlickrApi.java @@ -14,7 +14,7 @@ public class FlickrApi extends DefaultApi10a /** * {@inheritDoc} */ - @Override + public String getAccessTokenEndpoint() { return "http://www.flickr.com/services/oauth/access_token"; @@ -23,7 +23,7 @@ public String getAccessTokenEndpoint() /** * {@inheritDoc} */ - @Override + public String getAuthorizationUrl(Token requestToken) { return "http://www.flickr.com/services/oauth/authorize?oauth_token=" + requestToken.getToken(); @@ -32,7 +32,7 @@ public String getAuthorizationUrl(Token requestToken) /** * {@inheritDoc} */ - @Override + public String getRequestTokenEndpoint() { return "http://www.flickr.com/services/oauth/request_token"; diff --git a/src/main/java/org/scribe/builder/api/Foursquare2Api.java b/src/main/java/org/scribe/builder/api/Foursquare2Api.java index d11def9d7..08487dcbb 100644 --- a/src/main/java/org/scribe/builder/api/Foursquare2Api.java +++ b/src/main/java/org/scribe/builder/api/Foursquare2Api.java @@ -1,29 +1,26 @@ package org.scribe.builder.api; -import org.scribe.extractors.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.scribe.extractors.AccessTokenExtractor; +import org.scribe.extractors.JsonTokenExtractor; +import org.scribe.model.OAuthConfig; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; -public class Foursquare2Api extends DefaultApi20 -{ - private static final String AUTHORIZATION_URL = "https://foursquare.com/oauth2/authenticate?client_id=%s&response_type=code&redirect_uri=%s"; +public class Foursquare2Api extends DefaultApi20 { + private static final String AUTHORIZE_URL = "https://foursquare.com/oauth2/authenticate?client_id=%clientId%&response_type=code&redirect_uri=%redirectUri%"; - @Override - public String getAccessTokenEndpoint() - { - return "https://foursquare.com/oauth2/access_token?grant_type=authorization_code"; - } + public String getAccessTokenEndpoint() { + return "https://foursquare.com/oauth2/access_token?grant_type=authorization_code"; + } - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Foursquare2 does not support OOB"); - return String.format(AUTHORIZATION_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); - } + public String getAuthorizationUrl(final OAuthConfig config) { + Preconditions.checkValidUrl(config.getCallback(), + "Must provide a valid url as callback. Foursquare2 does not support OOB"); + return AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace("redirectUri", + OAuthEncoder.encode(config.getCallback())); + } - @Override - public AccessTokenExtractor getAccessTokenExtractor() - { - return new JsonTokenExtractor(); - } + public AccessTokenExtractor getAccessTokenExtractor() { + return new JsonTokenExtractor(); + } } diff --git a/src/main/java/org/scribe/builder/api/FoursquareApi.java b/src/main/java/org/scribe/builder/api/FoursquareApi.java index 060a76b76..c27ffc33b 100644 --- a/src/main/java/org/scribe/builder/api/FoursquareApi.java +++ b/src/main/java/org/scribe/builder/api/FoursquareApi.java @@ -2,25 +2,18 @@ import org.scribe.model.Token; -public class FoursquareApi extends DefaultApi10a -{ - private static final String AUTHORIZATION_URL = "http://foursquare.com/oauth/authorize?oauth_token=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "http://foursquare.com/oauth/access_token"; - } +public class FoursquareApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "http://foursquare.com/oauth/authorize?oauth_token=%s"; - @Override - public String getRequestTokenEndpoint() - { - return "http://foursquare.com/oauth/request_token"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } + public String getAccessTokenEndpoint() { + return "http://foursquare.com/oauth/access_token"; + } + + public String getRequestTokenEndpoint() { + return "http://foursquare.com/oauth/request_token"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/FreelancerApi.java b/src/main/java/org/scribe/builder/api/FreelancerApi.java index 482e66fd1..4c37316d4 100644 --- a/src/main/java/org/scribe/builder/api/FreelancerApi.java +++ b/src/main/java/org/scribe/builder/api/FreelancerApi.java @@ -1,61 +1,44 @@ package org.scribe.builder.api; -import org.scribe.model.*; - -public class FreelancerApi extends DefaultApi10a -{ - private static final String AUTHORIZATION_URL = "http://www.freelancer.com/users/api-token/auth.php?oauth_token=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "http://api.freelancer.com/RequestAccessToken/requestAccessToken.xml?"; - } - - @Override - public String getRequestTokenEndpoint() - { - return "http://api.freelancer.com/RequestRequestToken/requestRequestToken.xml"; - } - - @Override - public Verb getAccessTokenVerb() - { - return Verb.GET; - } - - @Override - public Verb getRequestTokenVerb() - { - return Verb.GET; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } - - public static class Sandbox extends FreelancerApi - { - private static final String SANDBOX_AUTHORIZATION_URL = "http://www.sandbox.freelancer.com/users/api-token/auth.php"; - - @Override - public String getRequestTokenEndpoint() - { - return "http://api.sandbox.freelancer.com/RequestRequestToken/requestRequestToken.xml"; +import org.scribe.model.Token; +import org.scribe.model.Verb; + +public class FreelancerApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "http://www.freelancer.com/users/api-token/auth.php?oauth_token="; + + public String getAccessTokenEndpoint() { + return "http://api.freelancer.com/RequestAccessToken/requestAccessToken.xml?"; + } + + public String getRequestTokenEndpoint() { + return "http://api.freelancer.com/RequestRequestToken/requestRequestToken.xml"; + } + + public Verb getAccessTokenVerb() { + return Verb.GET; } - @Override - public String getAccessTokenEndpoint() - { - return "http://api.sandbox.freelancer.com/RequestAccessToken/requestAccessToken.xml?"; + public Verb getRequestTokenVerb() { + return Verb.GET; } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(SANDBOX_AUTHORIZATION_URL + "?oauth_token=%s", requestToken.getToken()); + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } + + public static class Sandbox extends FreelancerApi { + private static final String SANDBOX_AUTHORIZATION_URL = "http://www.sandbox.freelancer.com/users/api-token/auth.php"; + + public String getRequestTokenEndpoint() { + return "http://api.sandbox.freelancer.com/RequestRequestToken/requestRequestToken.xml"; + } + + public String getAccessTokenEndpoint() { + return "http://api.sandbox.freelancer.com/RequestAccessToken/requestAccessToken.xml?"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return SANDBOX_AUTHORIZATION_URL + "?oauth_token=" + requestToken.getToken(); + } } - } } diff --git a/src/main/java/org/scribe/builder/api/GetGlueApi.java b/src/main/java/org/scribe/builder/api/GetGlueApi.java index 3a7560f0f..07fbb7784 100644 --- a/src/main/java/org/scribe/builder/api/GetGlueApi.java +++ b/src/main/java/org/scribe/builder/api/GetGlueApi.java @@ -2,28 +2,21 @@ import org.scribe.model.Token; -public class GetGlueApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "http://getglue.com/oauth/authorize?oauth_token=%s"; - private static final String REQUEST_TOKEN_RESOURCE = "https://api.getglue.com/oauth/request_token"; - private static final String ACCESS_TOKEN_RESOURCE = "https://api.getglue.com/oauth/access_token"; +public class GetGlueApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "http://getglue.com/oauth/authorize?oauth_token="; + private static final String REQUEST_TOKEN_RESOURCE = "https://api.getglue.com/oauth/request_token"; + private static final String ACCESS_TOKEN_RESOURCE = "https://api.getglue.com/oauth/access_token"; - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_RESOURCE; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_RESOURCE; + } - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_RESOURCE; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_RESOURCE; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/GoogleApi.java b/src/main/java/org/scribe/builder/api/GoogleApi.java index 9c86e5e1a..703d5ae7e 100644 --- a/src/main/java/org/scribe/builder/api/GoogleApi.java +++ b/src/main/java/org/scribe/builder/api/GoogleApi.java @@ -1,38 +1,28 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; +import org.scribe.model.Verb; -public class GoogleApi extends DefaultApi10a -{ - private static final String AUTHORIZATION_URL = "https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "https://www.google.com/accounts/OAuthGetAccessToken"; - } +public class GoogleApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return "https://www.google.com/accounts/OAuthGetRequestToken"; - } + public String getAccessTokenEndpoint() { + return "https://www.google.com/accounts/OAuthGetAccessToken"; + } - @Override - public Verb getAccessTokenVerb() - { - return Verb.GET; - } + public String getRequestTokenEndpoint() { + return "https://www.google.com/accounts/OAuthGetRequestToken"; + } - @Override - public Verb getRequestTokenVerb() - { - return Verb.GET; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } + public Verb getAccessTokenVerb() { + return Verb.GET; + } + + public Verb getRequestTokenVerb() { + return Verb.GET; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/ImgUrApi.java b/src/main/java/org/scribe/builder/api/ImgUrApi.java index 06dd6910d..b039262d2 100644 --- a/src/main/java/org/scribe/builder/api/ImgUrApi.java +++ b/src/main/java/org/scribe/builder/api/ImgUrApi.java @@ -1,6 +1,6 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; /** * OAuth API for ImgUr @@ -8,25 +8,17 @@ * @author David Wursteisen * @see ImgUr API */ -public class ImgUrApi extends DefaultApi10a -{ +public class ImgUrApi extends DefaultApi10a { - @Override - public String getRequestTokenEndpoint() - { - return "https://api.imgur.com/oauth/request_token"; - } + public String getRequestTokenEndpoint() { + return "https://api.imgur.com/oauth/request_token"; + } - @Override - public String getAccessTokenEndpoint() - { - return "https://api.imgur.com/oauth/access_token"; - } + public String getAccessTokenEndpoint() { + return "https://api.imgur.com/oauth/access_token"; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format("https://api.imgur.com/oauth/authorize?oauth_token=%s", requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return "https://api.imgur.com/oauth/authorize?oauth_token=" + requestToken.getToken(); + } } - diff --git a/src/main/java/org/scribe/builder/api/KaixinApi.java b/src/main/java/org/scribe/builder/api/KaixinApi.java index 5b0e0d5dc..2e90af598 100644 --- a/src/main/java/org/scribe/builder/api/KaixinApi.java +++ b/src/main/java/org/scribe/builder/api/KaixinApi.java @@ -1,40 +1,30 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; +import org.scribe.model.Verb; -public class KaixinApi extends DefaultApi10a -{ - private static final String REQUEST_TOKEN_URL = "http://api.kaixin001.com/oauth/request_token"; - private static final String ACCESS_TOKEN_URL = "http://api.kaixin001.com/oauth/access_token"; - private static final String AUTHORIZE_URL = "http://api.kaixin001.com/oauth/authorize?oauth_token=%s"; +public class KaixinApi extends DefaultApi10a { + private static final String REQUEST_TOKEN_URL = "http://api.kaixin001.com/oauth/request_token"; + private static final String ACCESS_TOKEN_URL = "http://api.kaixin001.com/oauth/access_token"; + private static final String AUTHORIZE_URL = "http://api.kaixin001.com/oauth/authorize?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_URL; + } - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_URL; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } - @Override - public Verb getRequestTokenVerb() - { - return Verb.GET; - } + public Verb getRequestTokenVerb() { + return Verb.GET; + } - @Override - public Verb getAccessTokenVerb() - { - return Verb.GET; - } + public Verb getAccessTokenVerb() { + return Verb.GET; + } } diff --git a/src/main/java/org/scribe/builder/api/KaixinApi20.java b/src/main/java/org/scribe/builder/api/KaixinApi20.java index 9e27bcb33..a0b65cb57 100644 --- a/src/main/java/org/scribe/builder/api/KaixinApi20.java +++ b/src/main/java/org/scribe/builder/api/KaixinApi20.java @@ -1,41 +1,33 @@ package org.scribe.builder.api; -import org.scribe.extractors.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.scribe.extractors.AccessTokenExtractor; +import org.scribe.extractors.JsonTokenExtractor; +import org.scribe.model.OAuthConfig; +import org.scribe.utils.OAuthEncoder; /** * Kaixin(http://www.kaixin001.com/) open platform api based on OAuth 2.0. */ -public class KaixinApi20 extends DefaultApi20 -{ +public class KaixinApi20 extends DefaultApi20 { - private static final String AUTHORIZE_URL = "http://api.kaixin001.com/oauth2/authorize?client_id=%s&redirect_uri=%s&response_type=code"; - private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s"; + private static final String AUTHORIZE_URL = "http://api.kaixin001.com/oauth2/authorize?client_id=%clientId%&redirect_uri=%redirectUri%&response_type=code"; + private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope="; - @Override - public AccessTokenExtractor getAccessTokenExtractor() - { - return new JsonTokenExtractor(); - } - - @Override - public String getAccessTokenEndpoint() - { - return "https://api.kaixin001.com/oauth2/access_token?grant_type=authorization_code"; - } + public AccessTokenExtractor getAccessTokenExtractor() { + return new JsonTokenExtractor(); + } - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - // Append scope if present - if (config.hasScope()) - { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope())); + public String getAccessTokenEndpoint() { + return "https://api.kaixin001.com/oauth2/access_token?grant_type=authorization_code"; } - else - { - return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); + + public String getAuthorizationUrl(final OAuthConfig config) { + String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( + "%redirectUri%", OAuthEncoder.encode(config.getCallback())); + // Append scope if present + if (config.hasScope()) { + result = SCOPED_AUTHORIZE_URL + OAuthEncoder.encode(config.getScope()); + } + return result; } - } } diff --git a/src/main/java/org/scribe/builder/api/LinkedInApi.java b/src/main/java/org/scribe/builder/api/LinkedInApi.java index ee6becd85..45255dcb5 100644 --- a/src/main/java/org/scribe/builder/api/LinkedInApi.java +++ b/src/main/java/org/scribe/builder/api/LinkedInApi.java @@ -1,57 +1,53 @@ package org.scribe.builder.api; -import org.scribe.model.*; -import java.util.*; - -public class LinkedInApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://api.linkedin.com/uas/oauth/authenticate?oauth_token=%s"; - private static final String REQUEST_TOKEN_URL = "https://api.linkedin.com/uas/oauth/requestToken"; - - private final Set scopes; - - public LinkedInApi() - { - scopes = Collections.emptySet(); - } - - public LinkedInApi(Set scopes) - { - this.scopes = Collections.unmodifiableSet(scopes); - } - - @Override - public String getAccessTokenEndpoint() - { - return "https://api.linkedin.com/uas/oauth/accessToken"; - } - - @Override - public String getRequestTokenEndpoint() - { - return scopes.isEmpty() ? REQUEST_TOKEN_URL : REQUEST_TOKEN_URL + "?scope=" + scopesAsString(); - } - - private String scopesAsString() - { - StringBuilder builder = new StringBuilder(); - for(String scope : scopes) - { - builder.append("+" + scope); +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.scribe.model.Token; + +public class LinkedInApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://api.linkedin.com/uas/oauth/authenticate?oauth_token="; + private static final String REQUEST_TOKEN_URL = "https://api.linkedin.com/uas/oauth/requestToken"; + + private final Set/**/scopes; + + public LinkedInApi() { + scopes = Collections.emptySet(); } - return builder.substring(1); - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } - - public static LinkedInApi withScopes(String... scopes) - { - Set scopeSet = new HashSet(Arrays.asList(scopes)); - return new LinkedInApi(scopeSet); - } - + + public LinkedInApi(final Set/**/scopes) { + this.scopes = Collections.unmodifiableSet(scopes); + } + + public String getAccessTokenEndpoint() { + return "https://api.linkedin.com/uas/oauth/accessToken"; + } + + public String getRequestTokenEndpoint() { + return scopes.isEmpty() ? REQUEST_TOKEN_URL : REQUEST_TOKEN_URL + "?scope=" + + scopesAsString(); + } + + private String scopesAsString() { + final StringBuilder builder = new StringBuilder(); + final Iterator i = scopes.iterator(); + while (i.hasNext()) { + final String scope = (String) i.next(); + builder.append("+" + scope); + } + return builder.substring(1); + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } + + public static LinkedInApi withScopes(final String[] scopes) { + final Set/**/scopeSet = new HashSet/**/(Arrays.asList(scopes)); + return new LinkedInApi(scopeSet); + } + } diff --git a/src/main/java/org/scribe/builder/api/LiveApi.java b/src/main/java/org/scribe/builder/api/LiveApi.java index 18140f603..bfd199c76 100644 --- a/src/main/java/org/scribe/builder/api/LiveApi.java +++ b/src/main/java/org/scribe/builder/api/LiveApi.java @@ -1,40 +1,30 @@ package org.scribe.builder.api; -import org.scribe.extractors.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.scribe.extractors.AccessTokenExtractor; +import org.scribe.extractors.JsonTokenExtractor; +import org.scribe.model.OAuthConfig; +import org.scribe.utils.OAuthEncoder; -public class LiveApi extends DefaultApi20 -{ +public class LiveApi extends DefaultApi20 { - private static final String AUTHORIZE_URL = "https://oauth.live.com/authorize?client_id=%s&redirect_uri=%s&response_type=code"; - private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s"; + private static final String AUTHORIZE_URL = "https://oauth.live.com/authorize?client_id=%clientId%&redirect_uri=%responseUri%&response_type=code"; + private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope="; - @Override - public String getAccessTokenEndpoint() - { - return "https://oauth.live.com/token?grant_type=authorization_code"; - } + public String getAccessTokenEndpoint() { + return "https://oauth.live.com/token?grant_type=authorization_code"; + } - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Live does not support OOB"); + public String getAuthorizationUrl(final OAuthConfig config) { + String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( + "%redirectUri%", OAuthEncoder.encode(config.getCallback())); + // Append scope if present + if (config.hasScope()) { + result = SCOPED_AUTHORIZE_URL + OAuthEncoder.encode(config.getScope()); + } + return result; + } - // Append scope if present - if (config.hasScope()) - { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope())); - } - else - { - return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); - } - } - - @Override - public AccessTokenExtractor getAccessTokenExtractor() - { - return new JsonTokenExtractor(); - } + public AccessTokenExtractor getAccessTokenExtractor() { + return new JsonTokenExtractor(); + } } \ No newline at end of file diff --git a/src/main/java/org/scribe/builder/api/LoveFilmApi.java b/src/main/java/org/scribe/builder/api/LoveFilmApi.java index 81a5bb874..fa4cb5135 100644 --- a/src/main/java/org/scribe/builder/api/LoveFilmApi.java +++ b/src/main/java/org/scribe/builder/api/LoveFilmApi.java @@ -2,27 +2,20 @@ import org.scribe.model.Token; -public class LoveFilmApi extends DefaultApi10a -{ - private static final String REQUEST_TOKEN_URL = "http://openapi.lovefilm.com/oauth/request_token"; - private static final String ACCESS_TOKEN_URL = "http://openapi.lovefilm.com/oauth/access_token"; - private static final String AUTHORIZE_URL = "https://www.lovefilm.com/activate?oauth_token=%s"; +public class LoveFilmApi extends DefaultApi10a { + private static final String REQUEST_TOKEN_URL = "http://openapi.lovefilm.com/oauth/request_token"; + private static final String ACCESS_TOKEN_URL = "http://openapi.lovefilm.com/oauth/access_token"; + private static final String AUTHORIZE_URL = "https://www.lovefilm.com/activate?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_URL; + } - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_URL; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/MeetupApi.java b/src/main/java/org/scribe/builder/api/MeetupApi.java index 8f63e39e1..c97fa5e0e 100644 --- a/src/main/java/org/scribe/builder/api/MeetupApi.java +++ b/src/main/java/org/scribe/builder/api/MeetupApi.java @@ -6,25 +6,18 @@ * OAuth access to the Meetup.com API. * For more information visit http://www.meetup.com/api */ -public class MeetupApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "http://www.meetup.com/authenticate?oauth_token=%s"; +public class MeetupApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "http://www.meetup.com/authenticate?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return "http://api.meetup.com/oauth/request/"; - } + public String getRequestTokenEndpoint() { + return "http://api.meetup.com/oauth/request/"; + } - @Override - public String getAccessTokenEndpoint() - { - return "http://api.meetup.com/oauth/access/"; - } + public String getAccessTokenEndpoint() { + return "http://api.meetup.com/oauth/access/"; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/MendeleyApi.java b/src/main/java/org/scribe/builder/api/MendeleyApi.java index c6e0eced7..cbcaa4ec7 100644 --- a/src/main/java/org/scribe/builder/api/MendeleyApi.java +++ b/src/main/java/org/scribe/builder/api/MendeleyApi.java @@ -1,43 +1,33 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; +import org.scribe.model.Verb; /** * @author Arieh "Vainolo" Bibliowicz * @see http://apidocs.mendeley.com/home/authentication */ -public class MendeleyApi extends DefaultApi10a -{ - - private static final String AUTHORIZATION_URL = "http://api.mendeley.com/oauth/authorize?oauth_token=%s"; - - @Override - public String getRequestTokenEndpoint() - { - return "http://api.mendeley.com/oauth/request_token/"; - } - - @Override - public String getAccessTokenEndpoint() - { - return "http://api.mendeley.com/oauth/access_token/"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } - - @Override - public Verb getAccessTokenVerb() - { - return Verb.GET; - } - - @Override - public Verb getRequestTokenVerb() - { - return Verb.GET; - } +public class MendeleyApi extends DefaultApi10a { + + private static final String AUTHORIZE_URL = "http://api.mendeley.com/oauth/authorize?oauth_token="; + + public String getRequestTokenEndpoint() { + return "http://api.mendeley.com/oauth/request_token/"; + } + + public String getAccessTokenEndpoint() { + return "http://api.mendeley.com/oauth/access_token/"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } + + public Verb getAccessTokenVerb() { + return Verb.GET; + } + + public Verb getRequestTokenVerb() { + return Verb.GET; + } } diff --git a/src/main/java/org/scribe/builder/api/MisoApi.java b/src/main/java/org/scribe/builder/api/MisoApi.java index a6d88d3df..57d231729 100644 --- a/src/main/java/org/scribe/builder/api/MisoApi.java +++ b/src/main/java/org/scribe/builder/api/MisoApi.java @@ -2,28 +2,21 @@ import org.scribe.model.Token; -public class MisoApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "http://gomiso.com/oauth/authorize?oauth_token=%s"; - private static final String REQUEST_TOKEN_RESOURCE = "http://gomiso.com/oauth/request_token"; - private static final String ACCESS_TOKEN_RESOURCE = "http://gomiso.com/oauth/access_token"; +public class MisoApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "http://gomiso.com/oauth/authorize?oauth_token="; + private static final String REQUEST_TOKEN_RESOURCE = "http://gomiso.com/oauth/request_token"; + private static final String ACCESS_TOKEN_RESOURCE = "http://gomiso.com/oauth/access_token"; - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_RESOURCE; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_RESOURCE; + } - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_RESOURCE; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_RESOURCE; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/NetProspexApi.java b/src/main/java/org/scribe/builder/api/NetProspexApi.java index 8257de751..afd550029 100644 --- a/src/main/java/org/scribe/builder/api/NetProspexApi.java +++ b/src/main/java/org/scribe/builder/api/NetProspexApi.java @@ -2,27 +2,20 @@ import org.scribe.model.Token; -public class NetProspexApi extends DefaultApi10a -{ - private static final String REQUEST_TOKEN_URL = "https://api.netprospex.com/1.0/oauth/request-token"; - private static final String ACCESS_TOKEN_URL = "https://api.netprospex.com/1.0/oauth/access-token"; - private static final String AUTHORIZE_URL = "https://api.netprospex.com/1.0/oauth/authorize?oauth_token=%s"; +public class NetProspexApi extends DefaultApi10a { + private static final String REQUEST_TOKEN_URL = "https://api.netprospex.com/1.0/oauth/request-token"; + private static final String ACCESS_TOKEN_URL = "https://api.netprospex.com/1.0/oauth/access-token"; + private static final String AUTHORIZE_URL = "https://api.netprospex.com/1.0/oauth/authorize?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_URL; + } - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_URL; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/NeteaseWeibooApi.java b/src/main/java/org/scribe/builder/api/NeteaseWeibooApi.java index fae38ac30..4e13977d5 100644 --- a/src/main/java/org/scribe/builder/api/NeteaseWeibooApi.java +++ b/src/main/java/org/scribe/builder/api/NeteaseWeibooApi.java @@ -1,47 +1,39 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class NeteaseWeibooApi extends DefaultApi10a -{ - private static final String REQUEST_TOKEN_URL = "http://api.t.163.com/oauth/request_token"; - private static final String ACCESS_TOKEN_URL = "http://api.t.163.com/oauth/access_token"; - private static final String AUTHORIZE_URL = "http://api.t.163.com/oauth/authorize?oauth_token=%s"; - private static final String AUTHENTICATE_URL = "http://api.t.163.com/oauth/authenticate?oauth_token=%s"; +public class NeteaseWeibooApi extends DefaultApi10a { + private static final String REQUEST_TOKEN_URL = "http://api.t.163.com/oauth/request_token"; + private static final String ACCESS_TOKEN_URL = "http://api.t.163.com/oauth/access_token"; + private static final String AUTHORIZE_URL = "http://api.t.163.com/oauth/authorize?oauth_token="; + private static final String AUTHENTICATE_URL = "http://api.t.163.com/oauth/authenticate?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_URL; + } - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_URL; + } - @Override - /** - * this method will ignore your callback - * if you're creating a desktop client please choose this url - * else your can call getAuthenticateUrl - * - * via http://open.t.163.com/wiki/index.php?title=%E8%AF%B7%E6%B1%82%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83Token(oauth/authorize) - */ - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + /** + * this method will ignore your callback + * if you're creating a desktop client please choose this url + * else your can call getAuthenticateUrl + * + * via http://open.t.163.com/wiki/index.php?title=%E8%AF%B7%E6%B1%82%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83Token(oauth/authorize) + */ + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } - /** - * this method is for web client with callback url - * if you're creating a desktop client please call getAuthorizationUrl - * - * via http://open.t.163.com/wiki/index.php?title=%E8%AF%B7%E6%B1%82%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83Token(oauth/authenticate) - */ - public String getAuthenticateUrl(Token requestToken) - { - return String.format(AUTHENTICATE_URL, requestToken.getToken()); - } + /** + * this method is for web client with callback url + * if you're creating a desktop client please call getAuthorizationUrl + * + * via http://open.t.163.com/wiki/index.php?title=%E8%AF%B7%E6%B1%82%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83Token(oauth/authenticate) + */ + public String getAuthenticateUrl(final Token requestToken) { + return AUTHENTICATE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/PlurkApi.java b/src/main/java/org/scribe/builder/api/PlurkApi.java index 22b1ddb75..4577f34e2 100644 --- a/src/main/java/org/scribe/builder/api/PlurkApi.java +++ b/src/main/java/org/scribe/builder/api/PlurkApi.java @@ -2,38 +2,28 @@ import org.scribe.model.Token; -public class PlurkApi extends DefaultApi10a -{ - private static final String REQUEST_TOKEN_URL = "http://www.plurk.com/OAuth/request_token"; - private static final String AUTHORIZATION_URL = "http://www.plurk.com/OAuth/authorize?oauth_token=%s"; - private static final String ACCESS_TOKEN_URL = "http://www.plurk.com/OAuth/access_token"; +public class PlurkApi extends DefaultApi10a { + private static final String REQUEST_TOKEN_URL = "http://www.plurk.com/OAuth/request_token"; + private static final String AUTHORIZE_URL = "http://www.plurk.com/OAuth/authorize?oauth_token="; + private static final String ACCESS_TOKEN_URL = "http://www.plurk.com/OAuth/access_token"; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_URL; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_URL; + } - public static class Mobile extends PlurkApi - { - private static final String AUTHORIZATION_URL = "http://www.plurk.com/m/authorize?oauth_token=%s"; + public static class Mobile extends PlurkApi { + private static final String AUTHORIZE_URL = "http://www.plurk.com/m/authorize?oauth_token="; - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } - } } diff --git a/src/main/java/org/scribe/builder/api/Px500Api.java b/src/main/java/org/scribe/builder/api/Px500Api.java index f7f3b0e0a..ae605fcd3 100644 --- a/src/main/java/org/scribe/builder/api/Px500Api.java +++ b/src/main/java/org/scribe/builder/api/Px500Api.java @@ -1,26 +1,19 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class Px500Api extends DefaultApi10a -{ - private static final String AUTHORIZATION_URL = "https://api.500px.com/v1/oauth/authorize?oauth_token=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "https://api.500px.com/v1/oauth/access_token"; - } +public class Px500Api extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://api.500px.com/v1/oauth/authorize?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return "https://api.500px.com/v1/oauth/request_token"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } + public String getAccessTokenEndpoint() { + return "https://api.500px.com/v1/oauth/access_token"; + } + + public String getRequestTokenEndpoint() { + return "https://api.500px.com/v1/oauth/request_token"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } \ No newline at end of file diff --git a/src/main/java/org/scribe/builder/api/QWeiboApi.java b/src/main/java/org/scribe/builder/api/QWeiboApi.java index e16f28836..9c556569d 100644 --- a/src/main/java/org/scribe/builder/api/QWeiboApi.java +++ b/src/main/java/org/scribe/builder/api/QWeiboApi.java @@ -1,28 +1,21 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class QWeiboApi extends DefaultApi10a -{ - private static final String REQUEST_TOKEN_URL = "https://open.t.qq.com/cgi-bin/request_token"; - private static final String ACCESS_TOKEN_URL = "https://open.t.qq.com/cgi-bin/access_token"; - private static final String AUTHORIZE_URL = "https://open.t.qq.com/cgi-bin/authorize?oauth_token=%s"; +public class QWeiboApi extends DefaultApi10a { + private static final String REQUEST_TOKEN_URL = "https://open.t.qq.com/cgi-bin/request_token"; + private static final String ACCESS_TOKEN_URL = "https://open.t.qq.com/cgi-bin/access_token"; + private static final String AUTHORIZE_URL = "https://open.t.qq.com/cgi-bin/authorize?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_URL; + } - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_URL; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/RenrenApi.java b/src/main/java/org/scribe/builder/api/RenrenApi.java index b31337ba4..78998cd43 100644 --- a/src/main/java/org/scribe/builder/api/RenrenApi.java +++ b/src/main/java/org/scribe/builder/api/RenrenApi.java @@ -1,40 +1,32 @@ package org.scribe.builder.api; -import org.scribe.extractors.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.scribe.extractors.AccessTokenExtractor; +import org.scribe.extractors.JsonTokenExtractor; +import org.scribe.model.OAuthConfig; +import org.scribe.utils.OAuthEncoder; /** * Renren(http://www.renren.com/) OAuth 2.0 based api. */ -public class RenrenApi extends DefaultApi20 -{ - private static final String AUTHORIZE_URL = "https://graph.renren.com/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code"; - private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s"; +public class RenrenApi extends DefaultApi20 { + private static final String AUTHORIZE_URL = "https://graph.renren.com/oauth/authorize?client_id=%clientId%&redirect_uri=%redirectUri%&response_type=code"; + private static final String SCOPED_PARAMETER = "&scope="; - @Override - public AccessTokenExtractor getAccessTokenExtractor() - { - return new JsonTokenExtractor(); - } - - @Override - public String getAccessTokenEndpoint() - { - return "https://graph.renren.com/oauth/token?grant_type=authorization_code"; - } + public AccessTokenExtractor getAccessTokenExtractor() { + return new JsonTokenExtractor(); + } - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - // Append scope if present - if (config.hasScope()) - { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope())); + public String getAccessTokenEndpoint() { + return "https://graph.renren.com/oauth/token?grant_type=authorization_code"; } - else - { - return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); + + public String getAuthorizationUrl(final OAuthConfig config) { + String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( + "redirectUri", OAuthEncoder.encode(config.getCallback())); + // Append scope if present + if (config.hasScope()) { + result = result + SCOPED_PARAMETER + OAuthEncoder.encode(config.getScope()); + } + return result; } - } } diff --git a/src/main/java/org/scribe/builder/api/SapoApi.java b/src/main/java/org/scribe/builder/api/SapoApi.java index 9771daf4c..b714d824b 100644 --- a/src/main/java/org/scribe/builder/api/SapoApi.java +++ b/src/main/java/org/scribe/builder/api/SapoApi.java @@ -1,40 +1,30 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; +import org.scribe.model.Verb; -public class SapoApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://id.sapo.pt/oauth/authorize?oauth_token=%s"; - private static final String ACCESS_URL = "https://id.sapo.pt/oauth/access_token"; - private static final String REQUEST_URL = "https://id.sapo.pt/oauth/request_token"; +public class SapoApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://id.sapo.pt/oauth/authorize?oauth_token="; + private static final String ACCESS_URL = "https://id.sapo.pt/oauth/access_token"; + private static final String REQUEST_URL = "https://id.sapo.pt/oauth/request_token"; - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_URL; + } - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_URL; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } - @Override - public Verb getRequestTokenVerb() - { - return Verb.GET; - } + public Verb getRequestTokenVerb() { + return Verb.GET; + } - @Override - public Verb getAccessTokenVerb() - { - return Verb.GET; - } + public Verb getAccessTokenVerb() { + return Verb.GET; + } } \ No newline at end of file diff --git a/src/main/java/org/scribe/builder/api/SimpleGeoApi.java b/src/main/java/org/scribe/builder/api/SimpleGeoApi.java index 3e19df70a..b548e056f 100644 --- a/src/main/java/org/scribe/builder/api/SimpleGeoApi.java +++ b/src/main/java/org/scribe/builder/api/SimpleGeoApi.java @@ -9,19 +9,19 @@ public class SimpleGeoApi extends DefaultApi10a { private static final String ENDPOINT = "these are not used since SimpleGeo uses 2 legged OAuth"; - @Override + public String getRequestTokenEndpoint() { return ENDPOINT; } - @Override + public String getAccessTokenEndpoint() { return ENDPOINT; } - @Override + public String getAuthorizationUrl(Token requestToken) { return ENDPOINT; diff --git a/src/main/java/org/scribe/builder/api/SinaWeiboApi.java b/src/main/java/org/scribe/builder/api/SinaWeiboApi.java index 14951d31b..add472709 100644 --- a/src/main/java/org/scribe/builder/api/SinaWeiboApi.java +++ b/src/main/java/org/scribe/builder/api/SinaWeiboApi.java @@ -1,28 +1,21 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class SinaWeiboApi extends DefaultApi10a -{ - private static final String REQUEST_TOKEN_URL = "http://api.t.sina.com.cn/oauth/request_token"; - private static final String ACCESS_TOKEN_URL = "http://api.t.sina.com.cn/oauth/access_token"; - private static final String AUTHORIZE_URL = "http://api.t.sina.com.cn/oauth/authorize?oauth_token=%s"; +public class SinaWeiboApi extends DefaultApi10a { + private static final String REQUEST_TOKEN_URL = "http://api.t.sina.com.cn/oauth/request_token"; + private static final String ACCESS_TOKEN_URL = "http://api.t.sina.com.cn/oauth/access_token"; + private static final String AUTHORIZE_URL = "http://api.t.sina.com.cn/oauth/authorize?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_URL; + } - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_URL; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/SinaWeiboApi20.java b/src/main/java/org/scribe/builder/api/SinaWeiboApi20.java index e0744c432..829b08a65 100644 --- a/src/main/java/org/scribe/builder/api/SinaWeiboApi20.java +++ b/src/main/java/org/scribe/builder/api/SinaWeiboApi20.java @@ -1,46 +1,37 @@ package org.scribe.builder.api; -import org.scribe.extractors.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.scribe.extractors.AccessTokenExtractor; +import org.scribe.extractors.JsonTokenExtractor; +import org.scribe.model.OAuthConfig; +import org.scribe.model.Verb; +import org.scribe.utils.OAuthEncoder; /** * SinaWeibo OAuth 2.0 api. */ -public class SinaWeiboApi20 extends DefaultApi20 -{ - private static final String AUTHORIZE_URL = "https://api.weibo.com/oauth2/authorize?client_id=%s&redirect_uri=%s&response_type=code"; - private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s"; +public class SinaWeiboApi20 extends DefaultApi20 { + private static final String AUTHORIZE_URL = "https://api.weibo.com/oauth2/authorize?client_id=%clientId%&redirect_uri=%redirectUri%&response_type=code"; + private static final String SCOPED_PARAMETER = "&scope="; - @Override - public Verb getAccessTokenVerb() - { - return Verb.POST; - } - - @Override - public AccessTokenExtractor getAccessTokenExtractor() - { - return new JsonTokenExtractor(); - } + public Verb getAccessTokenVerb() { + return Verb.POST; + } - @Override - public String getAccessTokenEndpoint() - { - return "https://api.weibo.com/oauth2/access_token?grant_type=authorization_code"; - } + public AccessTokenExtractor getAccessTokenExtractor() { + return new JsonTokenExtractor(); + } - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - // Append scope if present - if (config.hasScope()) - { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope())); + public String getAccessTokenEndpoint() { + return "https://api.weibo.com/oauth2/access_token?grant_type=authorization_code"; } - else - { - return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); + + public String getAuthorizationUrl(final OAuthConfig config) { + String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( + "redirectUri", OAuthEncoder.encode(config.getCallback())); + // Append scope if present + if (config.hasScope()) { + result = result + SCOPED_PARAMETER + OAuthEncoder.encode(config.getScope()); + } + return result; } - } } diff --git a/src/main/java/org/scribe/builder/api/SkyrockApi.java b/src/main/java/org/scribe/builder/api/SkyrockApi.java index b0e76a303..0e301901c 100644 --- a/src/main/java/org/scribe/builder/api/SkyrockApi.java +++ b/src/main/java/org/scribe/builder/api/SkyrockApi.java @@ -1,6 +1,6 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; /** * OAuth API for Skyrock. @@ -8,28 +8,21 @@ * @author Nicolas Quiénot * @see Skyrock.com API */ -public class SkyrockApi extends DefaultApi10a -{ - private static final String API_ENDPOINT = "https://api.skyrock.com/v2"; - private static final String REQUEST_TOKEN_RESOURCE = "/oauth/initiate"; - private static final String AUTHORIZE_URL = "/oauth/authorize?oauth_token=%s"; - private static final String ACCESS_TOKEN_RESOURCE = "/oauth/token"; - - @Override - public String getAccessTokenEndpoint() - { - return API_ENDPOINT + ACCESS_TOKEN_RESOURCE; - } +public class SkyrockApi extends DefaultApi10a { + private static final String API_ENDPOINT = "https://api.skyrock.com/v2"; + private static final String REQUEST_TOKEN_RESOURCE = "/oauth/initiate"; + private static final String AUTHORIZE_URL = "/oauth/authorize?oauth_token="; + private static final String ACCESS_TOKEN_RESOURCE = "/oauth/token"; - @Override - public String getRequestTokenEndpoint() - { - return API_ENDPOINT + REQUEST_TOKEN_RESOURCE; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(API_ENDPOINT + AUTHORIZE_URL, requestToken.getToken()); - } + public String getAccessTokenEndpoint() { + return API_ENDPOINT + ACCESS_TOKEN_RESOURCE; + } + + public String getRequestTokenEndpoint() { + return API_ENDPOINT + REQUEST_TOKEN_RESOURCE; + } + + public String getAuthorizationUrl(final Token requestToken) { + return API_ENDPOINT + AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/SohuWeiboApi.java b/src/main/java/org/scribe/builder/api/SohuWeiboApi.java index 1f927b7a5..c89912cce 100644 --- a/src/main/java/org/scribe/builder/api/SohuWeiboApi.java +++ b/src/main/java/org/scribe/builder/api/SohuWeiboApi.java @@ -1,28 +1,21 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class SohuWeiboApi extends DefaultApi10a -{ - private static final String REQUEST_TOKEN_URL = "http://api.t.sohu.com/oauth/request_token"; - private static final String ACCESS_TOKEN_URL = "http://api.t.sohu.com/oauth/access_token"; - private static final String AUTHORIZE_URL = "http://api.t.sohu.com/oauth/authorize?oauth_token=%s"; +public class SohuWeiboApi extends DefaultApi10a { + private static final String REQUEST_TOKEN_URL = "http://api.t.sohu.com/oauth/request_token"; + private static final String ACCESS_TOKEN_URL = "http://api.t.sohu.com/oauth/access_token"; + private static final String AUTHORIZE_URL = "http://api.t.sohu.com/oauth/authorize?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_URL; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_URL; + } - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_URL; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_URL; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/TrelloApi.java b/src/main/java/org/scribe/builder/api/TrelloApi.java index 9e46730d4..7cdebf173 100644 --- a/src/main/java/org/scribe/builder/api/TrelloApi.java +++ b/src/main/java/org/scribe/builder/api/TrelloApi.java @@ -1,27 +1,20 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class TrelloApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://trello.com/1/OAuthAuthorizeToken?oauth_token=%s"; +public class TrelloApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://trello.com/1/OAuthAuthorizeToken?oauth_token="; - @Override - public String getAccessTokenEndpoint() - { - return "https://trello.com/1/OAuthGetAccessToken"; - } + public String getAccessTokenEndpoint() { + return "https://trello.com/1/OAuthGetAccessToken"; + } + + public String getRequestTokenEndpoint() { + return "https://trello.com/1/OAuthGetRequestToken"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } - @Override - public String getRequestTokenEndpoint() - { - return "https://trello.com/1/OAuthGetRequestToken"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } - } diff --git a/src/main/java/org/scribe/builder/api/TumblrApi.java b/src/main/java/org/scribe/builder/api/TumblrApi.java index ee680ee8a..58e8d73cb 100644 --- a/src/main/java/org/scribe/builder/api/TumblrApi.java +++ b/src/main/java/org/scribe/builder/api/TumblrApi.java @@ -2,27 +2,20 @@ import org.scribe.model.Token; -public class TumblrApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://www.tumblr.com/oauth/authorize?oauth_token=%s"; - private static final String REQUEST_TOKEN_RESOURCE = "http://www.tumblr.com/oauth/request_token"; - private static final String ACCESS_TOKEN_RESOURCE = "http://www.tumblr.com/oauth/access_token"; +public class TumblrApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://www.tumblr.com/oauth/authorize?oauth_token="; + private static final String REQUEST_TOKEN_RESOURCE = "http://www.tumblr.com/oauth/request_token"; + private static final String ACCESS_TOKEN_RESOURCE = "http://www.tumblr.com/oauth/access_token"; - @Override - public String getAccessTokenEndpoint() - { - return ACCESS_TOKEN_RESOURCE; - } + public String getAccessTokenEndpoint() { + return ACCESS_TOKEN_RESOURCE; + } - @Override - public String getRequestTokenEndpoint() - { - return REQUEST_TOKEN_RESOURCE; - } + public String getRequestTokenEndpoint() { + return REQUEST_TOKEN_RESOURCE; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/TwitterApi.java b/src/main/java/org/scribe/builder/api/TwitterApi.java index a83c28e71..a9000c695 100644 --- a/src/main/java/org/scribe/builder/api/TwitterApi.java +++ b/src/main/java/org/scribe/builder/api/TwitterApi.java @@ -2,65 +2,52 @@ import org.scribe.model.Token; -public class TwitterApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize?oauth_token=%s"; - private static final String REQUEST_TOKEN_RESOURCE = "api.twitter.com/oauth/request_token"; - private static final String ACCESS_TOKEN_RESOURCE = "api.twitter.com/oauth/access_token"; - - @Override - public String getAccessTokenEndpoint() - { - return "http://" + ACCESS_TOKEN_RESOURCE; - } +public class TwitterApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize?oauth_token="; + private static final String REQUEST_TOKEN_RESOURCE = "api.twitter.com/oauth/request_token"; + private static final String ACCESS_TOKEN_RESOURCE = "api.twitter.com/oauth/access_token"; - @Override - public String getRequestTokenEndpoint() - { - return "http://" + REQUEST_TOKEN_RESOURCE; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAccessTokenEndpoint() { + return "http://" + ACCESS_TOKEN_RESOURCE; + } - public static class SSL extends TwitterApi - { - @Override - public String getAccessTokenEndpoint() - { - return "https://" + ACCESS_TOKEN_RESOURCE; + public String getRequestTokenEndpoint() { + return "http://" + REQUEST_TOKEN_RESOURCE; } - @Override - public String getRequestTokenEndpoint() - { - return "https://" + REQUEST_TOKEN_RESOURCE; + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); } - } - /** - * Twitter 'friendlier' authorization endpoint for OAuth. - * - * Uses SSL. - */ - public static class Authenticate extends SSL - { - private static final String AUTHENTICATE_URL = "https://api.twitter.com/oauth/authenticate?oauth_token=%s"; + public static class SSL extends TwitterApi { + + public String getAccessTokenEndpoint() { + return "https://" + ACCESS_TOKEN_RESOURCE; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHENTICATE_URL, requestToken.getToken()); + public String getRequestTokenEndpoint() { + return "https://" + REQUEST_TOKEN_RESOURCE; + } } - } - /** - * Just an alias to the default (SSL) authorization endpoint. - * - * Need to include this for symmetry with 'Authenticate' only. - */ - public static class Authorize extends SSL{} + /** + * Twitter 'friendlier' authorization endpoint for OAuth. + * + * Uses SSL. + */ + public static class Authenticate extends SSL { + private static final String AUTHENTICATE_URL = "https://api.twitter.com/oauth/authenticate?oauth_token="; + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHENTICATE_URL + requestToken.getToken(); + } + } + + /** + * Just an alias to the default (SSL) authorization endpoint. + * + * Need to include this for symmetry with 'Authenticate' only. + */ + public static class Authorize extends SSL { + } } diff --git a/src/main/java/org/scribe/builder/api/UbuntuOneApi.java b/src/main/java/org/scribe/builder/api/UbuntuOneApi.java index 2a72c3afe..95af23d89 100644 --- a/src/main/java/org/scribe/builder/api/UbuntuOneApi.java +++ b/src/main/java/org/scribe/builder/api/UbuntuOneApi.java @@ -1,40 +1,32 @@ package org.scribe.builder.api; import org.scribe.model.Token; -import org.scribe.services.*; +import org.scribe.services.PlaintextSignatureService; +import org.scribe.services.SignatureService; /** * @author Julio Gutierrez * * Sep 6, 2012 */ -public class UbuntuOneApi extends DefaultApi10a -{ - - private static final String AUTHORIZATION_URL = "https://one.ubuntu.com/oauth/authorize/?oauth_token=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "https://one.ubuntu.com/oauth/access/"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } - - @Override - public String getRequestTokenEndpoint() - { - return "https://one.ubuntu.com/oauth/request/"; - } - - @Override - public SignatureService getSignatureService() - { - return new PlaintextSignatureService(); - } +public class UbuntuOneApi extends DefaultApi10a { + + private static final String AUTHORIZE_URL = "https://one.ubuntu.com/oauth/authorize/?oauth_token="; + + public String getAccessTokenEndpoint() { + return "https://one.ubuntu.com/oauth/access/"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } + + public String getRequestTokenEndpoint() { + return "https://one.ubuntu.com/oauth/request/"; + } + + public SignatureService getSignatureService() { + return new PlaintextSignatureService(); + } } diff --git a/src/main/java/org/scribe/builder/api/ViadeoApi.java b/src/main/java/org/scribe/builder/api/ViadeoApi.java index 0f5e77e76..3094f0f26 100644 --- a/src/main/java/org/scribe/builder/api/ViadeoApi.java +++ b/src/main/java/org/scribe/builder/api/ViadeoApi.java @@ -1,42 +1,32 @@ package org.scribe.builder.api; import org.scribe.extractors.AccessTokenExtractor; +import org.scribe.extractors.JsonTokenExtractor; import org.scribe.model.OAuthConfig; import org.scribe.utils.OAuthEncoder; import org.scribe.utils.Preconditions; -import org.scribe.extractors.JsonTokenExtractor; - -public class ViadeoApi extends DefaultApi20 -{ - private static final String AUTHORIZE_URL = "https://secure.viadeo.com/oauth-provider/authorize2?client_id=%s&redirect_uri=%s&response_type=code"; - private static final String SCOPED_AUTHORIZE_URL = AUTHORIZE_URL + "&scope=%s"; +public class ViadeoApi extends DefaultApi20 { + private static final String AUTHORIZE_URL = "https://secure.viadeo.com/oauth-provider/authorize2?client_id=%clientId%&redirect_uri=%redirectUri%&response_type=code"; + private static final String SCOPED_PARAMETER = "&scope="; - @Override - public AccessTokenExtractor getAccessTokenExtractor() - { - return new JsonTokenExtractor(); - } - - @Override - public String getAccessTokenEndpoint() - { - return "https://secure.viadeo.com/oauth-provider/access_token2?grant_type=authorization_code"; - } - - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Viadeo does not support OOB"); + public AccessTokenExtractor getAccessTokenExtractor() { + return new JsonTokenExtractor(); + } - // Append scope if present - if(config.hasScope()) - { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope())); + public String getAccessTokenEndpoint() { + return "https://secure.viadeo.com/oauth-provider/access_token2?grant_type=authorization_code"; } - else - { - return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); + + public String getAuthorizationUrl(final OAuthConfig config) { + Preconditions.checkValidUrl(config.getCallback(), + "Must provide a valid url as callback. Viadeo does not support OOB"); + String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( + "redirectUri", OAuthEncoder.encode(config.getCallback())); + // Append scope if present + if (config.hasScope()) { + result = result + SCOPED_PARAMETER + OAuthEncoder.encode(config.getScope()); + } + return result; } - } } diff --git a/src/main/java/org/scribe/builder/api/VimeoApi.java b/src/main/java/org/scribe/builder/api/VimeoApi.java index 231895dab..6abb059ab 100644 --- a/src/main/java/org/scribe/builder/api/VimeoApi.java +++ b/src/main/java/org/scribe/builder/api/VimeoApi.java @@ -2,25 +2,18 @@ import org.scribe.model.Token; -public class VimeoApi extends DefaultApi10a -{ - private static final String AUTHORIZATION_URL = "http://vimeo.com/oauth/authorize?oauth_token=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "http://vimeo.com/oauth/access_token"; - } +public class VimeoApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "http://vimeo.com/oauth/authorize?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return "http://vimeo.com/oauth/request_token"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } + public String getAccessTokenEndpoint() { + return "http://vimeo.com/oauth/access_token"; + } + + public String getRequestTokenEndpoint() { + return "http://vimeo.com/oauth/request_token"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/VkontakteApi.java b/src/main/java/org/scribe/builder/api/VkontakteApi.java index e12f39559..e39573b90 100644 --- a/src/main/java/org/scribe/builder/api/VkontakteApi.java +++ b/src/main/java/org/scribe/builder/api/VkontakteApi.java @@ -1,41 +1,36 @@ package org.scribe.builder.api; -import org.scribe.extractors.*; -import org.scribe.utils.*; -import org.scribe.model.*; +import org.scribe.extractors.AccessTokenExtractor; +import org.scribe.extractors.JsonTokenExtractor; +import org.scribe.model.OAuthConfig; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; /** * @author Boris G. Tsirkin * @since 20.4.2011 */ -public class VkontakteApi extends DefaultApi20 -{ - private static final String AUTHORIZE_URL = "https://oauth.vk.com/authorize?client_id=%s&redirect_uri=%s&response_type=code"; - private static final String SCOPED_AUTHORIZE_URL = String.format("%s&scope=%%s", AUTHORIZE_URL); +public class VkontakteApi extends DefaultApi20 { + private static final String AUTHORIZE_URL = "https://oauth.vk.com/authorize?client_id=%clientId%&redirect_uri=%redirectUri%&response_type=code"; + private static final String SCOPED_PARAMETER = "&scope="; - @Override - public String getAccessTokenEndpoint() - { - return "https://api.vkontakte.ru/oauth/access_token"; - } - - @Override - public String getAuthorizationUrl(OAuthConfig config) - { - Preconditions.checkValidUrl(config.getCallback(), "Valid url is required for a callback. Vkontakte does not support OOB"); - if(config.hasScope())// Appending scope if present - { - return String.format(SCOPED_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()), OAuthEncoder.encode(config.getScope())); + public String getAccessTokenEndpoint() { + return "https://api.vkontakte.ru/oauth/access_token"; } - else - { - return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback())); + + public String getAuthorizationUrl(final OAuthConfig config) { + Preconditions.checkValidUrl(config.getCallback(), + "Valid url is required for a callback. Vkontakte does not support OOB"); + String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( + "redirectUri", OAuthEncoder.encode(config.getCallback())); + // Append scope if present + if (config.hasScope()) { + result = result + SCOPED_PARAMETER + OAuthEncoder.encode(config.getScope()); + } + return result; } - } - @Override - public AccessTokenExtractor getAccessTokenExtractor() - { - return new JsonTokenExtractor(); - } + public AccessTokenExtractor getAccessTokenExtractor() { + return new JsonTokenExtractor(); + } } diff --git a/src/main/java/org/scribe/builder/api/XingApi.java b/src/main/java/org/scribe/builder/api/XingApi.java index ec8823e67..f4dcfc08e 100755 --- a/src/main/java/org/scribe/builder/api/XingApi.java +++ b/src/main/java/org/scribe/builder/api/XingApi.java @@ -1,27 +1,20 @@ package org.scribe.builder.api; -import org.scribe.model.*; +import org.scribe.model.Token; -public class XingApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://api.xing.com/v1/authorize?oauth_token=%s"; +public class XingApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://api.xing.com/v1/authorize?oauth_token="; - @Override - public String getAccessTokenEndpoint() - { - return "https://api.xing.com/v1/access_token"; - } + public String getAccessTokenEndpoint() { + return "https://api.xing.com/v1/access_token"; + } + + public String getRequestTokenEndpoint() { + return "https://api.xing.com/v1/request_token"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } - @Override - public String getRequestTokenEndpoint() - { - return "https://api.xing.com/v1/request_token"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } - } diff --git a/src/main/java/org/scribe/builder/api/YahooApi.java b/src/main/java/org/scribe/builder/api/YahooApi.java index e8a29a738..dd592b3ea 100644 --- a/src/main/java/org/scribe/builder/api/YahooApi.java +++ b/src/main/java/org/scribe/builder/api/YahooApi.java @@ -2,25 +2,18 @@ import org.scribe.model.Token; -public class YahooApi extends DefaultApi10a -{ - private static final String AUTHORIZE_URL = "https://api.login.yahoo.com/oauth/v2/request_auth?oauth_token=%s"; - - @Override - public String getAccessTokenEndpoint() - { - return "https://api.login.yahoo.com/oauth/v2/get_token"; - } +public class YahooApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://api.login.yahoo.com/oauth/v2/request_auth?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return "https://api.login.yahoo.com/oauth/v2/get_request_token"; - } - - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZE_URL, requestToken.getToken()); - } + public String getAccessTokenEndpoint() { + return "https://api.login.yahoo.com/oauth/v2/get_token"; + } + + public String getRequestTokenEndpoint() { + return "https://api.login.yahoo.com/oauth/v2/get_request_token"; + } + + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } } diff --git a/src/main/java/org/scribe/builder/api/YammerApi.java b/src/main/java/org/scribe/builder/api/YammerApi.java index e06543d97..0e4d6804b 100644 --- a/src/main/java/org/scribe/builder/api/YammerApi.java +++ b/src/main/java/org/scribe/builder/api/YammerApi.java @@ -1,33 +1,25 @@ package org.scribe.builder.api; -import org.scribe.model.*; -import org.scribe.services.*; +import org.scribe.model.Token; +import org.scribe.services.PlaintextSignatureService; +import org.scribe.services.SignatureService; -public class YammerApi extends DefaultApi10a -{ - private static final String AUTHORIZATION_URL = "https://www.yammer.com/oauth/authorize?oauth_token=%s"; +public class YammerApi extends DefaultApi10a { + private static final String AUTHORIZE_URL = "https://www.yammer.com/oauth/authorize?oauth_token="; - @Override - public String getRequestTokenEndpoint() - { - return "https://www.yammer.com/oauth/request_token"; - } + public String getRequestTokenEndpoint() { + return "https://www.yammer.com/oauth/request_token"; + } - @Override - public String getAccessTokenEndpoint() - { - return "https://www.yammer.com/oauth/access_token"; - } + public String getAccessTokenEndpoint() { + return "https://www.yammer.com/oauth/access_token"; + } - @Override - public String getAuthorizationUrl(Token requestToken) - { - return String.format(AUTHORIZATION_URL, requestToken.getToken()); - } + public String getAuthorizationUrl(final Token requestToken) { + return AUTHORIZE_URL + requestToken.getToken(); + } - @Override - public SignatureService getSignatureService() - { - return new PlaintextSignatureService(); - } + public SignatureService getSignatureService() { + return new PlaintextSignatureService(); + } } diff --git a/src/main/java/org/scribe/exceptions/OAuthConnectionException.java b/src/main/java/org/scribe/exceptions/OAuthConnectionException.java index 918de810c..3708715e0 100644 --- a/src/main/java/org/scribe/exceptions/OAuthConnectionException.java +++ b/src/main/java/org/scribe/exceptions/OAuthConnectionException.java @@ -3,12 +3,16 @@ /** * @author: Pablo Fernandez */ -public class OAuthConnectionException extends OAuthException -{ - private static final String MSG = "There was a problem while creating a connection to the remote service."; - - public OAuthConnectionException(Exception e) - { - super(MSG, e); - } +public class OAuthConnectionException extends OAuthException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private static final String MSG = "There was a problem while creating a connection to the remote service."; + + public OAuthConnectionException(final Exception e) { + super(MSG, e); + } } diff --git a/src/main/java/org/scribe/exceptions/OAuthParametersMissingException.java b/src/main/java/org/scribe/exceptions/OAuthParametersMissingException.java index 8407ce493..2a1eb1684 100644 --- a/src/main/java/org/scribe/exceptions/OAuthParametersMissingException.java +++ b/src/main/java/org/scribe/exceptions/OAuthParametersMissingException.java @@ -1,26 +1,23 @@ package org.scribe.exceptions; -import org.scribe.model.*; +import org.scribe.model.OAuthRequest; /** * Specialized exception that represents a missing OAuth parameter. * * @author Pablo Fernandez */ -public class OAuthParametersMissingException extends OAuthException -{ +public class OAuthParametersMissingException extends OAuthException { - private static final long serialVersionUID = 1745308760111976671L; - private static final String MSG = "Could not find oauth parameters in request: %s. " - + "OAuth parameters must be specified with the addOAuthParameter() method"; + private static final long serialVersionUID = 1745308760111976671L; - /** - * Default constructor. - * - * @param request OAuthRequest that caused the error - */ - public OAuthParametersMissingException(OAuthRequest request) - { - super(String.format(MSG, request)); - } + /** + * Default constructor. + * + * @param request OAuthRequest that caused the error + */ + public OAuthParametersMissingException(final OAuthRequest request) { + super("Could not find oauth parameters in request: " + String.valueOf(request) + ". " + + "OAuth parameters must be specified with the addOAuthParameter() method"); + } } diff --git a/src/main/java/org/scribe/exceptions/OAuthSignatureException.java b/src/main/java/org/scribe/exceptions/OAuthSignatureException.java index 94692be5d..aceb37f9c 100644 --- a/src/main/java/org/scribe/exceptions/OAuthSignatureException.java +++ b/src/main/java/org/scribe/exceptions/OAuthSignatureException.java @@ -5,20 +5,18 @@ * * @author Pablo Fernandez */ -public class OAuthSignatureException extends OAuthException -{ - private static final long serialVersionUID = 1L; - private static final String MSG = "Error while signing string: %s"; - - /** - * Default constructor - * - * @param stringToSign plain string that gets signed (HMAC-SHA, etc) - * @param e original exception - */ - public OAuthSignatureException(String stringToSign, Exception e) - { - super(String.format(MSG, stringToSign), e); - } +public class OAuthSignatureException extends OAuthException { + private static final long serialVersionUID = 1L; + private static final String MSG = "Error while signing string: "; + + /** + * Default constructor + * + * @param stringToSign plain string that gets signed (HMAC-SHA, etc) + * @param e original exception + */ + public OAuthSignatureException(final String stringToSign, final Exception e) { + super(MSG + String.valueOf(stringToSign), e); + } } diff --git a/src/main/java/org/scribe/extractors/BaseStringExtractorImpl.java b/src/main/java/org/scribe/extractors/BaseStringExtractorImpl.java index ca21a0d1f..50d7168d9 100644 --- a/src/main/java/org/scribe/extractors/BaseStringExtractorImpl.java +++ b/src/main/java/org/scribe/extractors/BaseStringExtractorImpl.java @@ -1,8 +1,10 @@ package org.scribe.extractors; -import org.scribe.exceptions.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.scribe.exceptions.OAuthParametersMissingException; +import org.scribe.model.OAuthRequest; +import org.scribe.model.ParameterList; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; /** * Default implementation of {@link BaseStringExtractor}. Conforms to OAuth 1.0a @@ -10,39 +12,40 @@ * @author Pablo Fernandez * */ -public class BaseStringExtractorImpl implements BaseStringExtractor -{ +public class BaseStringExtractorImpl implements BaseStringExtractor { - private static final String AMPERSAND_SEPARATED_STRING = "%s&%s&%s"; + private static final String AMPERSAND_SEPARATOR = "&"; - /** - * {@inheritDoc} - */ - public String extract(OAuthRequest request) - { - checkPreconditions(request); - String verb = OAuthEncoder.encode(request.getVerb().name()); - String url = OAuthEncoder.encode(request.getSanitizedUrl()); - String params = getSortedAndEncodedParams(request); - return String.format(AMPERSAND_SEPARATED_STRING, verb, url, params); - } + /** + * {@inheritDoc} + */ + public String extract(final OAuthRequest request) { + checkPreconditions(request); + final String verb = OAuthEncoder.encode(request.getVerb().name()); + final String url = OAuthEncoder.encode(request.getSanitizedUrl()); + final String params = getSortedAndEncodedParams(request); + final StringBuffer buffer = new StringBuffer(); + buffer.append(verb); + buffer.append(AMPERSAND_SEPARATOR); + buffer.append(url); + buffer.append(AMPERSAND_SEPARATOR); + buffer.append(params); + return buffer.toString(); + } - private String getSortedAndEncodedParams(OAuthRequest request) - { - ParameterList params = new ParameterList(); - params.addAll(request.getQueryStringParams()); - params.addAll(request.getBodyParams()); - params.addAll(new ParameterList(request.getOauthParameters())); - return params.sort().asOauthBaseString(); - } + private String getSortedAndEncodedParams(final OAuthRequest request) { + final ParameterList params = new ParameterList(); + params.addAll(request.getQueryStringParams()); + params.addAll(request.getBodyParams()); + params.addAll(new ParameterList(request.getOauthParameters())); + return params.sort().asOauthBaseString(); + } - private void checkPreconditions(OAuthRequest request) - { - Preconditions.checkNotNull(request, "Cannot extract base string from null object"); + private void checkPreconditions(final OAuthRequest request) { + Preconditions.checkNotNull(request, "Cannot extract base string from null object"); - if (request.getOauthParameters() == null || request.getOauthParameters().size() <= 0) - { - throw new OAuthParametersMissingException(request); + if (request.getOauthParameters() == null || request.getOauthParameters().size() <= 0) { + throw new OAuthParametersMissingException(request); + } } - } } diff --git a/src/main/java/org/scribe/extractors/HeaderExtractor.java b/src/main/java/org/scribe/extractors/HeaderExtractor.java index 2bc1f8bd4..e41080eb4 100644 --- a/src/main/java/org/scribe/extractors/HeaderExtractor.java +++ b/src/main/java/org/scribe/extractors/HeaderExtractor.java @@ -13,7 +13,7 @@ public interface HeaderExtractor * Generates an OAuth 'Authorization' Http header to include in requests as the signature. * * @param request the OAuthRequest to inspect and generate the header - * @return the Http header value + * @return the Http header name */ String extract(OAuthRequest request); } diff --git a/src/main/java/org/scribe/extractors/HeaderExtractorImpl.java b/src/main/java/org/scribe/extractors/HeaderExtractorImpl.java index 02094693f..17fa1fbc6 100644 --- a/src/main/java/org/scribe/extractors/HeaderExtractorImpl.java +++ b/src/main/java/org/scribe/extractors/HeaderExtractorImpl.java @@ -1,10 +1,13 @@ package org.scribe.extractors; -import java.util.*; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; -import org.scribe.exceptions.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.scribe.exceptions.OAuthParametersMissingException; +import org.scribe.model.OAuthRequest; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; /** * Default implementation of {@link HeaderExtractor}. Conforms to OAuth 1.0a @@ -12,40 +15,41 @@ * @author Pablo Fernandez * */ -public class HeaderExtractorImpl implements HeaderExtractor -{ - private static final String PARAM_SEPARATOR = ", "; - private static final String PREAMBLE = "OAuth "; - public static final int ESTIMATED_PARAM_LENGTH = 20; +public class HeaderExtractorImpl implements HeaderExtractor { + private static final String PARAM_SEPARATOR = ", "; + private static final String PREAMBLE = "OAuth "; + public static final int ESTIMATED_PARAM_LENGTH = 20; - /** - * {@inheritDoc} - */ - public String extract(OAuthRequest request) - { - checkPreconditions(request); - Map parameters = request.getOauthParameters(); - StringBuilder header = new StringBuilder(parameters.size() * ESTIMATED_PARAM_LENGTH); - header.append(PREAMBLE); - for (Map.Entry entry : parameters.entrySet()) - { - if(header.length() > PREAMBLE.length()) - { - header.append(PARAM_SEPARATOR); - } - header.append(String.format("%s=\"%s\"", entry.getKey(), OAuthEncoder.encode(entry.getValue()))); + /** + * {@inheritDoc} + */ + public String extract(final OAuthRequest request) { + checkPreconditions(request); + final Map/**/parameters = request.getOauthParameters(); + final StringBuilder header = new StringBuilder(parameters.size() * ESTIMATED_PARAM_LENGTH); + header.append(PREAMBLE); + final Iterator i = parameters.entrySet().iterator(); + while (i.hasNext()) { + final Map.Entry/**/entry = (Entry) i.next(); + if (header.length() > PREAMBLE.length()) { + header.append(PARAM_SEPARATOR); + } + final StringBuffer buffer = new StringBuffer(); + buffer.append(entry.getKey()); + buffer.append("\"="); + buffer.append(OAuthEncoder.encode((String) entry.getValue())); + buffer.append("\""); + header.append(buffer.toString()); + } + return header.toString(); } - return header.toString(); - } - private void checkPreconditions(OAuthRequest request) - { - Preconditions.checkNotNull(request, "Cannot extract a header from a null object"); + private void checkPreconditions(final OAuthRequest request) { + Preconditions.checkNotNull(request, "Cannot extract a header from a null object"); - if (request.getOauthParameters() == null || request.getOauthParameters().size() <= 0) - { - throw new OAuthParametersMissingException(request); + if (request.getOauthParameters() == null || request.getOauthParameters().size() <= 0) { + throw new OAuthParametersMissingException(request); + } } - } } diff --git a/src/main/java/org/scribe/model/OAuthRequest.java b/src/main/java/org/scribe/model/OAuthRequest.java index 43892278f..d5ef19620 100644 --- a/src/main/java/org/scribe/model/OAuthRequest.java +++ b/src/main/java/org/scribe/model/OAuthRequest.java @@ -1,6 +1,7 @@ package org.scribe.model; -import java.util.*; +import java.util.HashMap; +import java.util.Map; /** * The representation of an OAuth HttpRequest. @@ -9,61 +10,52 @@ * * @author Pablo Fernandez */ -public class OAuthRequest extends Request -{ - private static final String OAUTH_PREFIX = "oauth_"; - private Map oauthParameters; +public class OAuthRequest extends Request { + private static final String OAUTH_PREFIX = "oauth_"; + private final Map/**/oauthParameters; - /** - * Default constructor. - * - * @param verb Http verb/method - * @param url resource URL - */ - public OAuthRequest(Verb verb, String url) - { - super(verb, url); - this.oauthParameters = new HashMap(); - } + /** + * Default constructor. + * + * @param verb Http verb/method + * @param url resource URL + */ + public OAuthRequest(final Verb verb, final String url) { + super(verb, url); + oauthParameters = new HashMap/**/(); + } - /** - * Adds an OAuth parameter. - * - * @param key name of the parameter - * @param value value of the parameter - * - * @throws IllegalArgumentException if the parameter is not an OAuth parameter - */ - public void addOAuthParameter(String key, String value) - { - oauthParameters.put(checkKey(key), value); - } + /** + * Adds an OAuth parameter. + * + * @param key name of the parameter + * @param name name of the parameter + * + * @throws IllegalArgumentException if the parameter is not an OAuth parameter + */ + public void addOAuthParameter(final String key, final String value) { + oauthParameters.put(checkKey(key), value); + } - private String checkKey(String key) - { - if (key.startsWith(OAUTH_PREFIX) || key.equals(OAuthConstants.SCOPE)) - { - return key; - } - else - { - throw new IllegalArgumentException(String.format("OAuth parameters must either be '%s' or start with '%s'", OAuthConstants.SCOPE, OAUTH_PREFIX)); + private String checkKey(final String key) { + if (key.startsWith(OAUTH_PREFIX) || key.equals(OAuthConstants.SCOPE)) { + return key; + } else { + throw new IllegalArgumentException("OAuth parameters must either be '" + + OAuthConstants.SCOPE + "' or start with '" + OAUTH_PREFIX + "'"); + } } - } - /** - * Returns the {@link Map} containing the key-value pair of parameters. - * - * @return parameters as map - */ - public Map getOauthParameters() - { - return oauthParameters; - } + /** + * Returns the {@link Map} containing the key-name pair of parameters. + * + * @return parameters as map + */ + public Map/**/getOauthParameters() { + return oauthParameters; + } - @Override - public String toString() - { - return String.format("@OAuthRequest(%s, %s)", getVerb(), getUrl()); - } + public String toString() { + return "@OAuthRequest(" + String.valueOf(getVerb()) + ", " + String.valueOf(getUrl()) + ")"; + } } diff --git a/src/main/java/org/scribe/model/Parameter.java b/src/main/java/org/scribe/model/Parameter.java index f8f3b81f6..f91a28cb0 100644 --- a/src/main/java/org/scribe/model/Parameter.java +++ b/src/main/java/org/scribe/model/Parameter.java @@ -1,47 +1,53 @@ package org.scribe.model; -import org.scribe.utils.*; +import org.scribe.utils.OAuthEncoder; /** * @author: Pablo Fernandez */ -public class Parameter implements Comparable +public class Parameter implements Comparable/**/ { - private static final String UTF = "UTF8"; - - private final String key; - private final String value; - - public Parameter(String key, String value) - { - this.key = key; - this.value = value; - } - - public String asUrlEncodedPair() - { - return OAuthEncoder.encode(key).concat("=").concat(OAuthEncoder.encode(value)); - } - - public boolean equals(Object other) - { - if(other == null) return false; - if(other == this) return true; - if(!(other instanceof Parameter)) return false; - - Parameter otherParam = (Parameter) other; - return otherParam.key.equals(key) && otherParam.value.equals(value); - } - - public int hashCode() - { - return key.hashCode() + value.hashCode(); - } - - public int compareTo(Parameter parameter) - { - int keyDiff = key.compareTo(parameter.key); - - return keyDiff != 0 ? keyDiff : value.compareTo(parameter.value); - } + private final String key; + private final String value; + + public Parameter(final String key, final String value) { + this.key = key; + this.value = value; + } + + public String asUrlEncodedPair() { + return OAuthEncoder.encode(key).concat("=").concat(OAuthEncoder.encode(value)); + } + + public boolean equals(final Object other) { + if (other == null) { + return false; + } + if (other == this) { + return true; + } + if (!(other instanceof Parameter)) { + return false; + } + + final Parameter otherParam = (Parameter) other; + return otherParam.key.equals(key) && otherParam.value.equals(value); + } + + public int hashCode() { + return key.hashCode() + value.hashCode(); + } + + public int compareTo(final Object o) { + if (o instanceof Parameter) { + return compareTo((Parameter) o); + } + return 1; + } + + public int compareTo(final Parameter parameter) { + final int keyDiff = key.compareTo(parameter.key); + + return keyDiff != 0 ? keyDiff : value.compareTo(parameter.value); + } } diff --git a/src/main/java/org/scribe/model/ParameterList.java b/src/main/java/org/scribe/model/ParameterList.java index b365cbaf6..5cc23453a 100644 --- a/src/main/java/org/scribe/model/ParameterList.java +++ b/src/main/java/org/scribe/model/ParameterList.java @@ -2,113 +2,105 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; + import org.scribe.utils.OAuthEncoder; import org.scribe.utils.Preconditions; /** * @author: Pablo Fernandez */ -public class ParameterList -{ - private static final char QUERY_STRING_SEPARATOR = '?'; - private static final String PARAM_SEPARATOR = "&"; - private static final String PAIR_SEPARATOR = "="; - private static final String EMPTY_STRING = ""; - - private final List params; - - public ParameterList() - { - params = new ArrayList(); - } - - ParameterList(List params) - { - this.params = new ArrayList(params); - } - - public ParameterList(Map map) - { - this(); - for(Map.Entry entry : map.entrySet()) - { - params.add(new Parameter(entry.getKey(), entry.getValue())); +public class ParameterList { + private static final String QUERY_STRING_SEPARATOR = "?"; + private static final String PARAM_SEPARATOR = "&"; + private static final String PAIR_SEPARATOR = "="; + private static final String EMPTY_STRING = ""; + + private final List/**/params; + + public ParameterList() { + params = new ArrayList/**/(); } - } - - public void add(String key, String value) - { - params.add(new Parameter(key, value)); - } - - public String appendTo(String url) - { - Preconditions.checkNotNull(url, "Cannot append to null URL"); - String queryString = asFormUrlEncodedString(); - if (queryString.equals(EMPTY_STRING)) - { - return url; + + ParameterList(final List/**/params) { + this.params = new ArrayList/**/(params); } - else - { - url += url.indexOf(QUERY_STRING_SEPARATOR) != -1 ? PARAM_SEPARATOR : QUERY_STRING_SEPARATOR; - url += queryString; - return url; + + public ParameterList(final Map/**/map) { + this(); + final Iterator i = map.entrySet().iterator(); + while (i.hasNext()) { + final Map.Entry/**/entry = (Entry) i.next(); + params.add(new Parameter((String) entry.getKey(), (String) entry.getValue())); + } } - } - public String asOauthBaseString() - { - return OAuthEncoder.encode(asFormUrlEncodedString()); - } + public void add(final String key, final String value) { + params.add(new Parameter(key, value)); + } - public String asFormUrlEncodedString() - { - if (params.size() == 0) return EMPTY_STRING; + public String appendTo(String url) { + Preconditions.checkNotNull(url, "Cannot append to null URL"); + final String queryString = asFormUrlEncodedString(); + if (EMPTY_STRING.equals(queryString)) { + return url; + } else { + url += url.indexOf(QUERY_STRING_SEPARATOR) < 0 ? QUERY_STRING_SEPARATOR + : PARAM_SEPARATOR; + url += queryString; + return url; + } + } - StringBuilder builder = new StringBuilder(); - for(Parameter p : params) - { - builder.append('&').append(p.asUrlEncodedPair()); + public String asOauthBaseString() { + return OAuthEncoder.encode(asFormUrlEncodedString()); } - return builder.toString().substring(1); - } - - public void addAll(ParameterList other) - { - params.addAll(other.params); - } - - public void addQuerystring(String queryString) - { - if (queryString != null && queryString.length() > 0) - { - for (String param : queryString.split(PARAM_SEPARATOR)) - { - String pair[] = param.split(PAIR_SEPARATOR); - String key = OAuthEncoder.decode(pair[0]); - String value = pair.length > 1 ? OAuthEncoder.decode(pair[1]) : EMPTY_STRING; - params.add(new Parameter(key, value)); - } + + public String asFormUrlEncodedString() { + if (params.size() == 0) { + return EMPTY_STRING; + } + + final StringBuffer builder = new StringBuffer(); + final Iterator i = params.iterator(); + while (i.hasNext()) { + final Parameter p = (Parameter) i.next(); + builder.append('&').append(p.asUrlEncodedPair()); + } + return builder.toString().substring(1); + } + + public void addAll(final ParameterList other) { + params.addAll(other.params); + } + + public void addQuerystring(final String queryString) { + if (queryString != null && queryString.length() > 0) { + final String[] vals = queryString.split(PARAM_SEPARATOR); + for (int i = 0; i < vals.length; i++) { + final String param = vals[i]; + final String pair[] = param.split(PAIR_SEPARATOR); + final String key = OAuthEncoder.decode(pair[0]); + final String value = pair.length > 1 ? OAuthEncoder.decode(pair[1]) : EMPTY_STRING; + params.add(new Parameter(key, value)); + } + } + } + + public boolean contains(final Parameter param) { + return params.contains(param); + } + + public int size() { + return params.size(); + } + + public ParameterList sort() { + final ParameterList sorted = new ParameterList(params); + Collections.sort(sorted.params); + return sorted; } - } - - public boolean contains(Parameter param) - { - return params.contains(param); - } - - public int size() - { - return params.size(); - } - - public ParameterList sort() - { - ParameterList sorted = new ParameterList(params); - Collections.sort(sorted.params); - return sorted; - } } diff --git a/src/main/java/org/scribe/model/Request.java b/src/main/java/org/scribe/model/Request.java index 0202db0a2..26d85de02 100644 --- a/src/main/java/org/scribe/model/Request.java +++ b/src/main/java/org/scribe/model/Request.java @@ -1,382 +1,346 @@ package org.scribe.model; -import java.io.*; -import java.net.*; -import java.nio.charset.*; -import java.util.*; -import java.util.concurrent.*; - -import org.scribe.exceptions.*; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.scribe.exceptions.OAuthConnectionException; +import org.scribe.exceptions.OAuthException; /** * Represents an HTTP Request object * * @author Pablo Fernandez */ -public class Request -{ - private static final String CONTENT_LENGTH = "Content-Length"; - private static final String CONTENT_TYPE = "Content-Type"; - private static RequestTuner NOOP = new RequestTuner() { - @Override public void tune(Request _){} - }; - public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded"; - - private String url; - private Verb verb; - private ParameterList querystringParams; - private ParameterList bodyParams; - private Map headers; - private String payload = null; - private HttpURLConnection connection; - private String charset; - private byte[] bytePayload = null; - private boolean connectionKeepAlive = false; - private boolean followRedirects = true; - private Long connectTimeout = null; - private Long readTimeout = null; - - /** - * Creates a new Http Request - * - * @param verb Http Verb (GET, POST, etc) - * @param url url with optional querystring parameters. - */ - public Request(Verb verb, String url) - { - this.verb = verb; - this.url = url; - this.querystringParams = new ParameterList(); - this.bodyParams = new ParameterList(); - this.headers = new HashMap(); - } - - /** - * Execute the request and return a {@link Response} - * - * @return Http Response - * @throws RuntimeException - * if the connection cannot be created. - */ - public Response send(RequestTuner tuner) - { - try - { - createConnection(); - return doSend(tuner); +public class Request { + private static final String CONTENT_LENGTH = "Content-Length"; + private static final String CONTENT_TYPE = "Content-Type"; + private static RequestTuner NOOP = new RequestTuner() { + public void tune(final Request _) { + } + }; + public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded"; + + private final String url; + private final Verb verb; + private final ParameterList querystringParams; + private final ParameterList bodyParams; + private final Map/**/headers; + private String payload = null; + private HttpURLConnection connection; + private String charset; + private byte[] bytePayload = null; + private boolean connectionKeepAlive = false; + private boolean followRedirects = true; + private Long connectTimeout = null; + private Long readTimeout = null; + + /** + * Creates a new Http Request + * + * @param verb Http Verb (GET, POST, etc) + * @param url url with optional querystring parameters. + */ + public Request(final Verb verb, final String url) { + this.verb = verb; + this.url = url; + querystringParams = new ParameterList(); + bodyParams = new ParameterList(); + headers = new HashMap/**/(); + } + + /** + * Execute the request and return a {@link Response} + * + * @return Http Response + * @throws RuntimeException + * if the connection cannot be created. + */ + public Response send(final RequestTuner tuner) { + try { + createConnection(); + return doSend(tuner); + } catch (final Exception e) { + throw new OAuthConnectionException(e); + } + } + + public Response send() { + return send(NOOP); + } + + private void createConnection() throws IOException { + final String completeUrl = getCompleteUrl(); + if (connection == null) { + System.setProperty("http.keepAlive", connectionKeepAlive ? "true" : "false"); + connection = (HttpURLConnection) new URL(completeUrl).openConnection(); + connection.setInstanceFollowRedirects(followRedirects); + } + } + + /** + * Returns the complete url (host + resource + encoded querystring parameters). + * + * @return the complete url. + */ + public String getCompleteUrl() { + return querystringParams.appendTo(url); + } + + Response doSend(final RequestTuner tuner) throws IOException { + connection.setRequestMethod(verb.name()); + if (connectTimeout != null) { + connection.setConnectTimeout(connectTimeout.intValue()); + } + if (readTimeout != null) { + connection.setReadTimeout(readTimeout.intValue()); + } + addHeaders(connection); + if (verb.equals(Verb.PUT) || verb.equals(Verb.POST)) { + addBody(connection, getByteBodyContents()); + } + tuner.tune(this); + return new Response(connection); + } + + void addHeaders(final HttpURLConnection conn) { + final Iterator i = headers.keySet().iterator(); + while (i.hasNext()) { + final String key = (String) i.next(); + conn.setRequestProperty(key, (String) headers.get(key)); + } + } + + void addBody(final HttpURLConnection conn, final byte[] content) throws IOException { + conn.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.length)); + + // Set default content type if none is set. + if (conn.getRequestProperty(CONTENT_TYPE) == null) { + conn.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); + } + conn.setDoOutput(true); + conn.getOutputStream().write(content); + } + + /** + * Add an HTTP Header to the Request + * + * @param key the header name + * @param name the header name + */ + public void addHeader(final String key, final String value) { + headers.put(key, value); + } + + /** + * Add a body Parameter (for POST/ PUT Requests) + * + * @param key the parameter name + * @param name the parameter name + */ + public void addBodyParameter(final String key, final String value) { + bodyParams.add(key, value); + } + + /** + * Add a QueryString parameter + * + * @param key the parameter name + * @param name the parameter name + */ + public void addQuerystringParameter(final String key, final String value) { + querystringParams.add(key, value); + } + + /** + * Add body payload. + * + * This method is used when the HTTP body is not a form-url-encoded string, + * but another thing. Like for example XML. + * + * Note: The contents are not part of the OAuth signature + * + * @param payload the body of the request + */ + public void addPayload(final String payload) { + this.payload = payload; } - catch (Exception e) - { - throw new OAuthConnectionException(e); + + /** + * Overloaded version for byte arrays + * + * @param payload + */ + public void addPayload(final byte[] payload) { + bytePayload = (byte[]) payload.clone(); } - } - - public Response send() - { - return send(NOOP); - } - - private void createConnection() throws IOException - { - String completeUrl = getCompleteUrl(); - if (connection == null) - { - System.setProperty("http.keepAlive", connectionKeepAlive ? "true" : "false"); - connection = (HttpURLConnection) new URL(completeUrl).openConnection(); - connection.setInstanceFollowRedirects(followRedirects); + + /** + * Get a {@link ParameterList} with the query string parameters. + * + * @return a {@link ParameterList} containing the query string parameters. + * @throws OAuthException if the request URL is not valid. + */ + public ParameterList getQueryStringParams() { + try { + final ParameterList result = new ParameterList(); + final String queryString = new URL(url).getQuery(); + result.addQuerystring(queryString); + result.addAll(querystringParams); + return result; + } catch (final MalformedURLException mue) { + throw new OAuthException("Malformed URL", mue); + } } - } - - /** - * Returns the complete url (host + resource + encoded querystring parameters). - * - * @return the complete url. - */ - public String getCompleteUrl() - { - return querystringParams.appendTo(url); - } - - Response doSend(RequestTuner tuner) throws IOException - { - connection.setRequestMethod(this.verb.name()); - if (connectTimeout != null) - { - connection.setConnectTimeout(connectTimeout.intValue()); + + /** + * Obtains a {@link ParameterList} of the body parameters. + * + * @return a {@link ParameterList}containing the body parameters. + */ + public ParameterList getBodyParams() { + return bodyParams; } - if (readTimeout != null) - { - connection.setReadTimeout(readTimeout.intValue()); + + /** + * Obtains the URL of the HTTP Request. + * + * @return the original URL of the HTTP Request + */ + public String getUrl() { + return url; } - addHeaders(connection); - if (verb.equals(Verb.PUT) || verb.equals(Verb.POST)) - { - addBody(connection, getByteBodyContents()); + + /** + * Returns the URL without the port and the query string part. + * + * @return the OAuth-sanitized URL + */ + public String getSanitizedUrl() { + return url.replaceAll("\\?.*", "").replace("\\:\\d{4}", ""); } - tuner.tune(this); - return new Response(connection); - } - - void addHeaders(HttpURLConnection conn) - { - for (String key : headers.keySet()) - conn.setRequestProperty(key, headers.get(key)); - } - - void addBody(HttpURLConnection conn, byte[] content) throws IOException - { - conn.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.length)); - - // Set default content type if none is set. - if (conn.getRequestProperty(CONTENT_TYPE) == null) - { - conn.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); + + /** + * Returns the body of the request + * + * @return form encoded string + * @throws OAuthException if the charset chosen is not supported + */ + public String getBodyContents() { + try { + return new String(getByteBodyContents(), getCharset()); + } catch (final UnsupportedEncodingException uee) { + throw new OAuthException("Unsupported Charset: " + charset, uee); + } } - conn.setDoOutput(true); - conn.getOutputStream().write(content); - } - - /** - * Add an HTTP Header to the Request - * - * @param key the header name - * @param value the header value - */ - public void addHeader(String key, String value) - { - this.headers.put(key, value); - } - - /** - * Add a body Parameter (for POST/ PUT Requests) - * - * @param key the parameter name - * @param value the parameter value - */ - public void addBodyParameter(String key, String value) - { - this.bodyParams.add(key, value); - } - - /** - * Add a QueryString parameter - * - * @param key the parameter name - * @param value the parameter value - */ - public void addQuerystringParameter(String key, String value) - { - this.querystringParams.add(key, value); - } - - /** - * Add body payload. - * - * This method is used when the HTTP body is not a form-url-encoded string, - * but another thing. Like for example XML. - * - * Note: The contents are not part of the OAuth signature - * - * @param payload the body of the request - */ - public void addPayload(String payload) - { - this.payload = payload; - } - - /** - * Overloaded version for byte arrays - * - * @param payload - */ - public void addPayload(byte[] payload) - { - this.bytePayload = payload.clone(); - } - - /** - * Get a {@link ParameterList} with the query string parameters. - * - * @return a {@link ParameterList} containing the query string parameters. - * @throws OAuthException if the request URL is not valid. - */ - public ParameterList getQueryStringParams() - { - try - { - ParameterList result = new ParameterList(); - String queryString = new URL(url).getQuery(); - result.addQuerystring(queryString); - result.addAll(querystringParams); - return result; + + byte[] getByteBodyContents() { + if (bytePayload != null) { + return bytePayload; + } + final String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString(); + try { + return body.getBytes(getCharset()); + } catch (final UnsupportedEncodingException uee) { + throw new OAuthException("Unsupported Charset: " + getCharset(), uee); + } } - catch (MalformedURLException mue) - { - throw new OAuthException("Malformed URL", mue); + + /** + * Returns the HTTP Verb + * + * @return the verb + */ + public Verb getVerb() { + return verb; } - } - - /** - * Obtains a {@link ParameterList} of the body parameters. - * - * @return a {@link ParameterList}containing the body parameters. - */ - public ParameterList getBodyParams() - { - return bodyParams; - } - - /** - * Obtains the URL of the HTTP Request. - * - * @return the original URL of the HTTP Request - */ - public String getUrl() - { - return url; - } - - /** - * Returns the URL without the port and the query string part. - * - * @return the OAuth-sanitized URL - */ - public String getSanitizedUrl() - { - return url.replaceAll("\\?.*", "").replace("\\:\\d{4}", ""); - } - - /** - * Returns the body of the request - * - * @return form encoded string - * @throws OAuthException if the charset chosen is not supported - */ - public String getBodyContents() - { - try - { - return new String(getByteBodyContents(),getCharset()); + + /** + * Returns the connection headers as a {@link Map} + * + * @return map of headers + */ + public Map/**/getHeaders() { + return headers; } - catch(UnsupportedEncodingException uee) - { - throw new OAuthException("Unsupported Charset: "+charset, uee); + + /** + * Returns the connection charset. Defaults to {@link Charset} defaultCharset if not set + * + * @return charset + */ + public String getCharset() { + return charset == null ? Charset.defaultCharset().name() : charset; } - } - - byte[] getByteBodyContents() - { - if (bytePayload != null) return bytePayload; - String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString(); - try - { - return body.getBytes(getCharset()); + + /** + * Sets the connect timeout for the underlying {@link HttpURLConnection} + * + * @param duration duration of the timeout + * + * @param unit unit of time (milliseconds, seconds, etc) + */ + public void setConnectTimeout(final int duration, final TimeUnit unit) { + connectTimeout = Long.valueOf(unit.toMillis(duration)); } - catch(UnsupportedEncodingException uee) - { - throw new OAuthException("Unsupported Charset: "+getCharset(), uee); + + /** + * Sets the read timeout for the underlying {@link HttpURLConnection} + * + * @param duration duration of the timeout + * + * @param unit unit of time (milliseconds, seconds, etc) + */ + public void setReadTimeout(final int duration, final TimeUnit unit) { + readTimeout = Long.valueOf(unit.toMillis(duration)); + } + + /** + * Set the charset of the body of the request + * + * @param charsetName name of the charset of the request + */ + public void setCharset(final String charsetName) { + charset = charsetName; + } + + /** + * Sets whether the underlying Http Connection is persistent or not. + * + * @see http://download.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html + * @param connectionKeepAlive + */ + public void setConnectionKeepAlive(final boolean connectionKeepAlive) { + this.connectionKeepAlive = connectionKeepAlive; + } + + /** + * Sets whether the underlying Http Connection follows redirects or not. + * + * Defaults to true (follow redirects) + * + * @see http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html#setInstanceFollowRedirects(boolean) + * @param followRedirects + */ + public void setFollowRedirects(final boolean followRedirects) { + this.followRedirects = followRedirects; + } + + /* + * We need this in order to stub the connection object for test cases + */ + void setConnection(final HttpURLConnection connection) { + this.connection = connection; + } + + public String toString() { + return "@Request(" + String.valueOf(getVerb()) + " " + getUrl() + ")"; } - } - - /** - * Returns the HTTP Verb - * - * @return the verb - */ - public Verb getVerb() - { - return verb; - } - - /** - * Returns the connection headers as a {@link Map} - * - * @return map of headers - */ - public Map getHeaders() - { - return headers; - } - - /** - * Returns the connection charset. Defaults to {@link Charset} defaultCharset if not set - * - * @return charset - */ - public String getCharset() - { - return charset == null ? Charset.defaultCharset().name() : charset; - } - - /** - * Sets the connect timeout for the underlying {@link HttpURLConnection} - * - * @param duration duration of the timeout - * - * @param unit unit of time (milliseconds, seconds, etc) - */ - public void setConnectTimeout(int duration, TimeUnit unit) - { - this.connectTimeout = unit.toMillis(duration); - } - - /** - * Sets the read timeout for the underlying {@link HttpURLConnection} - * - * @param duration duration of the timeout - * - * @param unit unit of time (milliseconds, seconds, etc) - */ - public void setReadTimeout(int duration, TimeUnit unit) - { - this.readTimeout = unit.toMillis(duration); - } - - /** - * Set the charset of the body of the request - * - * @param charsetName name of the charset of the request - */ - public void setCharset(String charsetName) - { - this.charset = charsetName; - } - - /** - * Sets whether the underlying Http Connection is persistent or not. - * - * @see http://download.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html - * @param connectionKeepAlive - */ - public void setConnectionKeepAlive(boolean connectionKeepAlive) - { - this.connectionKeepAlive = connectionKeepAlive; - } - - /** - * Sets whether the underlying Http Connection follows redirects or not. - * - * Defaults to true (follow redirects) - * - * @see http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html#setInstanceFollowRedirects(boolean) - * @param followRedirects - */ - public void setFollowRedirects(boolean followRedirects) - { - this.followRedirects = followRedirects; - } - - /* - * We need this in order to stub the connection object for test cases - */ - void setConnection(HttpURLConnection connection) - { - this.connection = connection; - } - - @Override - public String toString() - { - return String.format("@Request(%s %s)", getVerb(), getUrl()); - } } diff --git a/src/main/java/org/scribe/model/Response.java b/src/main/java/org/scribe/model/Response.java index d433922c6..eb9d25bac 100644 --- a/src/main/java/org/scribe/model/Response.java +++ b/src/main/java/org/scribe/model/Response.java @@ -1,126 +1,117 @@ package org.scribe.model; -import java.io.*; -import java.net.*; -import java.util.*; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.UnknownHostException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; -import org.scribe.exceptions.*; -import org.scribe.utils.*; +import org.scribe.exceptions.OAuthException; +import org.scribe.utils.StreamUtils; /** * Represents an HTTP Response. * * @author Pablo Fernandez */ -public class Response -{ - private static final String EMPTY = ""; +public class Response { - private int code; - private String message; - private String body; - private InputStream stream; - private Map headers; + private int code; + private String message; + private String body; + private InputStream stream; + private Map/**/headers; - Response(HttpURLConnection connection) throws IOException - { - try - { - connection.connect(); - code = connection.getResponseCode(); - message = connection.getResponseMessage(); - headers = parseHeaders(connection); - stream = isSuccessful() ? connection.getInputStream() : connection.getErrorStream(); + Response(final HttpURLConnection connection) throws IOException { + try { + connection.connect(); + code = connection.getResponseCode(); + message = connection.getResponseMessage(); + headers = parseHeaders(connection); + stream = isSuccessful() ? connection.getInputStream() : connection.getErrorStream(); + } catch (final UnknownHostException e) { + throw new OAuthException("The IP address of a host could not be determined.", e); + } } - catch (UnknownHostException e) - { - throw new OAuthException("The IP address of a host could not be determined.", e); + + private String parseBodyContents() { + body = StreamUtils.getStreamContents(getStream()); + return body; } - } - private String parseBodyContents() - { - body = StreamUtils.getStreamContents(getStream()); - return body; - } + private Map/**/parseHeaders(final HttpURLConnection conn) { + final Map/**/headers = new HashMap/**/(); + final Iterator i = conn.getHeaderFields().keySet().iterator(); + while (i.hasNext()) { + final String key = (String) i.next(); + headers.put(key, ((Collection) conn.getHeaderFields().get(key)).toArray()[0]); + } + return headers; + } - private Map parseHeaders(HttpURLConnection conn) - { - Map headers = new HashMap(); - for (String key : conn.getHeaderFields().keySet()) - { - headers.put(key, conn.getHeaderFields().get(key).get(0)); + public boolean isSuccessful() { + return getCode() >= 200 && getCode() < 400; } - return headers; - } - public boolean isSuccessful() - { - return getCode() >= 200 && getCode() < 400; - } + /** + * Obtains the HTTP Response body + * + * @return response body + */ + public String getBody() { + return body != null ? body : parseBodyContents(); + } - /** - * Obtains the HTTP Response body - * - * @return response body - */ - public String getBody() - { - return body != null ? body : parseBodyContents(); - } + /** + * Obtains the meaningful stream of the HttpUrlConnection, either inputStream + * or errorInputStream, depending on the status code + * + * @return input stream / error stream + */ + public InputStream getStream() { + return stream; + } - /** - * Obtains the meaningful stream of the HttpUrlConnection, either inputStream - * or errorInputStream, depending on the status code - * - * @return input stream / error stream - */ - public InputStream getStream() - { - return stream; - } + /** + * Obtains the HTTP status code + * + * @return the status code + */ + public int getCode() { + return code; + } - /** - * Obtains the HTTP status code - * - * @return the status code - */ - public int getCode() - { - return code; - } - - /** - * Obtains the HTTP status message. - * Returns null if the message can not be discerned from the response (not valid HTTP) - * - * @return the status message - */ - public String getMessage() - { - return message; - } + /** + * Obtains the HTTP status message. + * Returns null if the message can not be discerned from the response (not valid HTTP) + * + * @return the status message + */ + public String getMessage() { + return message; + } - /** - * Obtains a {@link Map} containing the HTTP Response Headers - * - * @return headers - */ - public Map getHeaders() - { - return headers; - } + /** + * Obtains a {@link Map} containing the HTTP Response Headers + * + * @return headers + */ + public Map/**/getHeaders() { + return headers; + } - /** - * Obtains a single HTTP Header value, or null if undefined - * - * @param name the header name. - * - * @return header value or null. - */ - public String getHeader(String name) - { - return headers.get(name); - } + /** + * Obtains a single HTTP Header name, or null if undefined + * + * @param name the header name. + * + * @return header name or null. + */ + public String getHeader(final String name) { + return (String) headers.get(name); + } } \ No newline at end of file diff --git a/src/main/java/org/scribe/model/SignatureType.java b/src/main/java/org/scribe/model/SignatureType.java index 3440a361f..670accae5 100644 --- a/src/main/java/org/scribe/model/SignatureType.java +++ b/src/main/java/org/scribe/model/SignatureType.java @@ -1,7 +1,58 @@ package org.scribe.model; -public enum SignatureType -{ - Header, - QueryString +public class SignatureType { + public static final SignatureType Header = new SignatureType("Header"); + public static final SignatureType QueryString = new SignatureType("QueryString"); + + final String name; + + public SignatureType(final String string) { + super(); + name = string; + } + + public String name() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Verb other = (Verb) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return name; + } } diff --git a/src/main/java/org/scribe/model/Token.java b/src/main/java/org/scribe/model/Token.java index 4d8c0eeb5..b30bb5c35 100644 --- a/src/main/java/org/scribe/model/Token.java +++ b/src/main/java/org/scribe/model/Token.java @@ -1,98 +1,89 @@ package org.scribe.model; -import java.io.*; -import org.scribe.utils.*; +import java.io.Serializable; + +import org.scribe.utils.Preconditions; /** * Represents an OAuth token (either request or access token) and its secret * * @author Pablo Fernandez */ -public class Token implements Serializable -{ - private static final long serialVersionUID = 715000866082812683L; - - private final String token; - private final String secret; - private final String rawResponse; - - /** - * Default constructor - * - * @param token token value. Can't be null. - * @param secret token secret. Can't be null. - */ - public Token(String token, String secret) - { - this(token, secret, null); - } - - public Token(String token, String secret, String rawResponse) - { - Preconditions.checkNotNull(token, "Token can't be null"); - Preconditions.checkNotNull(secret, "Secret can't be null"); - - this.token = token; - this.secret = secret; - this.rawResponse = rawResponse; - } - - public String getToken() - { - return token; - } - - public String getSecret() - { - return secret; - } - - public String getRawResponse() - { - if (rawResponse == null) - { - throw new IllegalStateException("This token object was not constructed by scribe and does not have a rawResponse"); +public class Token implements Serializable { + private static final long serialVersionUID = 715000866082812683L; + + private final String token; + private final String secret; + private final String rawResponse; + + /** + * Default constructor + * + * @param token token name. Can't be null. + * @param secret token secret. Can't be null. + */ + public Token(final String token, final String secret) { + this(token, secret, null); + } + + public Token(final String token, final String secret, final String rawResponse) { + Preconditions.checkNotNull(token, "Token can't be null"); + Preconditions.checkNotNull(secret, "Secret can't be null"); + + this.token = token; + this.secret = secret; + this.rawResponse = rawResponse; + } + + public String getToken() { + return token; + } + + public String getSecret() { + return secret; + } + + public String getRawResponse() { + if (rawResponse == null) { + throw new IllegalStateException( + "This token object was not constructed by scribe and does not have a rawResponse"); + } + return rawResponse; + } + + public String toString() { + return "Token[" + String.valueOf(token) + String.valueOf(secret) + "]"; + } + + /** + * Returns true if the token is empty (token = "", secret = "") + */ + public boolean isEmpty() { + return "".equals(token) && "".equals(secret); + } + + /** + * Factory method that returns an empty token (token = "", secret = ""). + * + * Useful for two legged OAuth. + */ + public static Token empty() { + return new Token("", ""); + } + + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final Token that = (Token) o; + return token.equals(that.token) && secret.equals(that.secret); + } + + public int hashCode() { + return 31 * token.hashCode() + secret.hashCode(); } - return rawResponse; - } - - @Override - public String toString() - { - return String.format("Token[%s , %s]", token, secret); - } - - /** - * Returns true if the token is empty (token = "", secret = "") - */ - public boolean isEmpty() - { - return "".equals(this.token) && "".equals(this.secret); - } - - /** - * Factory method that returns an empty token (token = "", secret = ""). - * - * Useful for two legged OAuth. - */ - public static Token empty() - { - return new Token("", ""); - } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Token that = (Token) o; - return token.equals(that.token) && secret.equals(that.secret); - } - - @Override - public int hashCode() - { - return 31 * token.hashCode() + secret.hashCode(); - } } diff --git a/src/main/java/org/scribe/model/Verb.java b/src/main/java/org/scribe/model/Verb.java index 0c22f6690..daa9f75e3 100644 --- a/src/main/java/org/scribe/model/Verb.java +++ b/src/main/java/org/scribe/model/Verb.java @@ -5,7 +5,70 @@ * * @author Pablo Fernandez */ -public enum Verb -{ - GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE, PATCH +public class Verb { + + public static final Verb GET = new Verb("GET"); + public static final Verb POST = new Verb("POST"); + public static final Verb PUT = new Verb("PUT"); + public static final Verb DELETE = new Verb("DELETE"); + public static final Verb HEAD = new Verb("HEAD"); + public static final Verb OPTIONS = new Verb("OPTIONS"); + public static final Verb TRACE = new Verb("TRACE"); + public static final Verb PATCH = new Verb("PATCH"); + + final String name; + + /** + * @param string + */ + public Verb(final String string) { + super(); + name = string; + } + + public String name() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Verb other = (Verb) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return name; + } + } diff --git a/src/main/java/org/scribe/model/Verifier.java b/src/main/java/org/scribe/model/Verifier.java index 45f0e4ea3..df3ea34f1 100644 --- a/src/main/java/org/scribe/model/Verifier.java +++ b/src/main/java/org/scribe/model/Verifier.java @@ -15,7 +15,7 @@ public class Verifier /** * Default constructor. * - * @param value verifier value + * @param name verifier name */ public Verifier(String value) { diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index abde25399..57c7e148e 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -1,190 +1,210 @@ package org.scribe.oauth; -import java.util.*; - -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.services.*; -import org.scribe.utils.*; +import java.util.Iterator; +import java.util.Map; import java.util.concurrent.TimeUnit; +import org.scribe.builder.api.DefaultApi10a; +import org.scribe.model.OAuthConfig; +import org.scribe.model.OAuthConstants; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Request; +import org.scribe.model.RequestTuner; +import org.scribe.model.Response; +import org.scribe.model.SignatureType; +import org.scribe.model.Token; +import org.scribe.model.Verifier; +import org.scribe.services.Base64Encoder; +import org.scribe.utils.MapUtils; + /** * OAuth 1.0a implementation of {@link OAuthService} * * @author Pablo Fernandez */ -public class OAuth10aServiceImpl implements OAuthService -{ - private static final String VERSION = "1.0"; - - private OAuthConfig config; - private DefaultApi10a api; - - /** - * Default constructor - * - * @param api OAuth1.0a api information - * @param config OAuth 1.0a configuration param object - */ - public OAuth10aServiceImpl(DefaultApi10a api, OAuthConfig config) - { - this.api = api; - this.config = config; - } - - /** - * {@inheritDoc} - */ - public Token getRequestToken(int timeout, TimeUnit unit) - { - return getRequestToken(new TimeoutTuner(timeout, unit)); - } - - public Token getRequestToken() - { - return getRequestToken(2, TimeUnit.SECONDS); - } - - public Token getRequestToken(RequestTuner tuner) - { - config.log("obtaining request token from " + api.getRequestTokenEndpoint()); - OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint()); - - config.log("setting oauth_callback to " + config.getCallback()); - request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback()); - addOAuthParams(request, OAuthConstants.EMPTY_TOKEN); - appendSignature(request); - - config.log("sending request..."); - Response response = request.send(tuner); - String body = response.getBody(); - - config.log("response status code: " + response.getCode()); - config.log("response body: " + body); - return api.getRequestTokenExtractor().extract(body); - } - - private void addOAuthParams(OAuthRequest request, Token token) - { - request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService().getTimestampInSeconds()); - request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce()); - request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey()); - request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod()); - request.addOAuthParameter(OAuthConstants.VERSION, getVersion()); - if(config.hasScope()) request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope()); - request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token)); - - config.log("appended additional OAuth parameters: " + MapUtils.toString(request.getOauthParameters())); - } - - /** - * {@inheritDoc} - */ - public Token getAccessToken(Token requestToken, Verifier verifier, int timeout, TimeUnit unit) - { - return getAccessToken(requestToken, verifier, new TimeoutTuner(timeout, unit)); - } - - public Token getAccessToken(Token requestToken, Verifier verifier) - { - return getAccessToken(requestToken, verifier, 2, TimeUnit.SECONDS); - } - - public Token getAccessToken(Token requestToken, Verifier verifier, RequestTuner tuner) - { - config.log("obtaining access token from " + api.getAccessTokenEndpoint()); - OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); - request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); - request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); - - config.log("setting token to: " + requestToken + " and verifier to: " + verifier); - addOAuthParams(request, requestToken); - appendSignature(request); - Response response = request.send(tuner); - return api.getAccessTokenExtractor().extract(response.getBody()); - } - - /** - * {@inheritDoc} - */ - public void signRequest(Token token, OAuthRequest request) - { - config.log("signing request: " + request.getCompleteUrl()); - - // Do not append the token if empty. This is for two legged OAuth calls. - if (!token.isEmpty()) - { - request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken()); - } - config.log("setting token to: " + token); - addOAuthParams(request, token); - appendSignature(request); - } - - /** - * {@inheritDoc} - */ - public String getVersion() - { - return VERSION; - } - - /** - * {@inheritDoc} - */ - public String getAuthorizationUrl(Token requestToken) - { - return api.getAuthorizationUrl(requestToken); - } - - private String getSignature(OAuthRequest request, Token token) - { - config.log("generating signature..."); - config.log("using base64 encoder: " + Base64Encoder.type()); - String baseString = api.getBaseStringExtractor().extract(request); - String signature = api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret()); - - config.log("base string is: " + baseString); - config.log("signature is: " + signature); - return signature; - } - - private void appendSignature(OAuthRequest request) - { - switch (config.getSignatureType()) - { - case Header: - config.log("using Http Header signature"); - - String oauthHeader = api.getHeaderExtractor().extract(request); - request.addHeader(OAuthConstants.HEADER, oauthHeader); - break; - case QueryString: - config.log("using Querystring signature"); - - for (Map.Entry entry : request.getOauthParameters().entrySet()) - { - request.addQuerystringParameter(entry.getKey(), entry.getValue()); +public class OAuth10aServiceImpl implements OAuthService { + private static final String VERSION = "1.0"; + + private final OAuthConfig config; + private final DefaultApi10a api; + + /** + * Default constructor + * + * @param api OAuth1.0a api information + * @param config OAuth 1.0a configuration param object + */ + public OAuth10aServiceImpl(final DefaultApi10a api, final OAuthConfig config) { + this.api = api; + this.config = config; + } + + /** + * {@inheritDoc} + */ + public Token getRequestToken(final int timeout, final TimeUnit unit) { + return getRequestToken(new TimeoutTuner(timeout, unit)); + } + + public Token getRequestToken() { + return getRequestToken(2, TimeUnit.SECONDS); + } + + public Token getRequestToken(final RequestTuner tuner) { + config.log("obtaining request token from " + api.getRequestTokenEndpoint()); + final OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), + api.getRequestTokenEndpoint()); + + config.log("setting oauth_callback to " + config.getCallback()); + request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback()); + addOAuthParams(request, OAuthConstants.EMPTY_TOKEN); + appendSignature(request); + + config.log("sending request..."); + final Response response = request.send(tuner); + final String body = response.getBody(); + + config.log("response status code: " + response.getCode()); + config.log("response body: " + body); + return api.getRequestTokenExtractor().extract(body); + } + + private void addOAuthParams(final OAuthRequest request, final Token token) { + request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService() + .getTimestampInSeconds()); + request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce()); + request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey()); + request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService() + .getSignatureMethod()); + request.addOAuthParameter(OAuthConstants.VERSION, getVersion()); + if (config.hasScope()) { + request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope()); } - break; + request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token)); + + config.log("appended additional OAuth parameters: " + + MapUtils.toString(request.getOauthParameters())); + } + + /** + * {@inheritDoc} + */ + public Token getAccessToken(final Token requestToken, final Verifier verifier, + final int timeout, final TimeUnit unit) { + return getAccessToken(requestToken, verifier, new TimeoutTuner(timeout, unit)); } - } - private static class TimeoutTuner extends RequestTuner - { - private final int duration; - private final TimeUnit unit; + public Token getAccessToken(final Token requestToken, final Verifier verifier) { + return getAccessToken(requestToken, verifier, 2, TimeUnit.SECONDS); + } + + public Token getAccessToken(final Token requestToken, final Verifier verifier, + final RequestTuner tuner) { + config.log("obtaining access token from " + api.getAccessTokenEndpoint()); + final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), + api.getAccessTokenEndpoint()); + request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); + request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); + + config.log("setting token to: " + requestToken + " and verifier to: " + verifier); + addOAuthParams(request, requestToken); + appendSignature(request); + final Response response = request.send(tuner); + return api.getAccessTokenExtractor().extract(response.getBody()); + } + + /** + * {@inheritDoc} + */ + public Token getAccessToken(final Token requestToken, final int timeout, final TimeUnit unit) { + return getAccessToken(requestToken, new TimeoutTuner(timeout, unit)); + } - public TimeoutTuner(int duration, TimeUnit unit) - { - this.duration = duration; - this.unit = unit; + public Token getAccessToken(final Token requestToken) { + return getAccessToken(requestToken, 2, TimeUnit.SECONDS); } - @Override - public void tune(Request request) - { - request.setReadTimeout(duration, unit); + public Token getAccessToken(final Token requestToken, final RequestTuner tuner) { + config.log("obtaining access token from " + api.getAccessTokenEndpoint()); + final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), + api.getAccessTokenEndpoint()); + request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); + + config.log("setting token to: " + requestToken); + addOAuthParams(request, requestToken); + appendSignature(request); + final Response response = request.send(tuner); + return api.getAccessTokenExtractor().extract(response.getBody()); + } + + /** + * {@inheritDoc} + */ + public void signRequest(final Token token, final OAuthRequest request) { + config.log("signing request: " + request.getCompleteUrl()); + + // Do not append the token if empty. This is for two legged OAuth calls. + if (!token.isEmpty()) { + request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken()); + } + config.log("setting token to: " + token); + addOAuthParams(request, token); + appendSignature(request); + } + + /** + * {@inheritDoc} + */ + public String getVersion() { + return VERSION; + } + + /** + * {@inheritDoc} + */ + public String getAuthorizationUrl(final Token requestToken) { + return api.getAuthorizationUrl(requestToken); + } + + private String getSignature(final OAuthRequest request, final Token token) { + config.log("generating signature..."); + config.log("using base64 encoder: " + Base64Encoder.type()); + final String baseString = api.getBaseStringExtractor().extract(request); + final String signature = api.getSignatureService().getSignature(baseString, + config.getApiSecret(), token.getSecret()); + + config.log("base string is: " + baseString); + config.log("signature is: " + signature); + return signature; + } + + private void appendSignature(final OAuthRequest request) { + if (SignatureType.Header.equals(config.getSignatureType())) { + config.log("using Http Header signature"); + + final String oauthHeader = api.getHeaderExtractor().extract(request); + request.addHeader(OAuthConstants.HEADER, oauthHeader); + } else if (SignatureType.QueryString.equals(config.getSignatureType())) { + config.log("using Querystring signature"); + final Iterator i = request.getOauthParameters().entrySet().iterator(); + while (i.hasNext()) { + final Map.Entry/**/entry = (Map.Entry) i.next(); + request.addQuerystringParameter((String) entry.getKey(), (String) entry.getValue()); + } + } + } + + private static class TimeoutTuner extends RequestTuner { + private final int duration; + private final TimeUnit unit; + + public TimeoutTuner(final int duration, final TimeUnit unit) { + this.duration = duration; + this.unit = unit; + } + + public void tune(final Request request) { + request.setReadTimeout(duration, unit); + } } - } } diff --git a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java index 6262c3700..9ae5f2646 100644 --- a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java @@ -1,72 +1,90 @@ package org.scribe.oauth; -import org.scribe.builder.api.*; -import org.scribe.model.*; +import org.scribe.builder.api.DefaultApi20; +import org.scribe.model.OAuthConfig; +import org.scribe.model.OAuthConstants; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verifier; -public class OAuth20ServiceImpl implements OAuthService -{ - private static final String VERSION = "2.0"; - - private final DefaultApi20 api; - private final OAuthConfig config; - - /** - * Default constructor - * - * @param api OAuth2.0 api information - * @param config OAuth 2.0 configuration param object - */ - public OAuth20ServiceImpl(DefaultApi20 api, OAuthConfig config) - { - this.api = api; - this.config = config; - } +public class OAuth20ServiceImpl implements OAuthService { + private static final String VERSION = "2.0"; - /** - * {@inheritDoc} - */ - public Token getAccessToken(Token requestToken, Verifier verifier) - { - OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); - request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); - request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); - request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue()); - request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback()); - if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope()); - Response response = request.send(); - return api.getAccessTokenExtractor().extract(response.getBody()); - } + private final DefaultApi20 api; + private final OAuthConfig config; - /** - * {@inheritDoc} - */ - public Token getRequestToken() - { - throw new UnsupportedOperationException("Unsupported operation, please use 'getAuthorizationUrl' and redirect your users there"); - } + /** + * Default constructor + * + * @param api OAuth2.0 api information + * @param config OAuth 2.0 configuration param object + */ + public OAuth20ServiceImpl(final DefaultApi20 api, final OAuthConfig config) { + this.api = api; + this.config = config; + } - /** - * {@inheritDoc} - */ - public String getVersion() - { - return VERSION; - } + /** + * {@inheritDoc} + */ + public Token getAccessToken(final Token requestToken, final Verifier verifier) { + final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), + api.getAccessTokenEndpoint()); + request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); + request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); + request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue()); + request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback()); + if (config.hasScope()) { + request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope()); + } + final Response response = request.send(); + return api.getAccessTokenExtractor().extract(response.getBody()); + } - /** - * {@inheritDoc} - */ - public void signRequest(Token accessToken, OAuthRequest request) - { - request.addQuerystringParameter(OAuthConstants.ACCESS_TOKEN, accessToken.getToken()); - } + /** + * {@inheritDoc} + */ + public Token getRequestToken() { + throw new UnsupportedOperationException( + "Unsupported operation, please use 'getAuthorizationUrl' and redirect your users there"); + } - /** - * {@inheritDoc} - */ - public String getAuthorizationUrl(Token requestToken) - { - return api.getAuthorizationUrl(config); - } + /** + * {@inheritDoc} + */ + public String getVersion() { + return VERSION; + } + + /** + * {@inheritDoc} + */ + public void signRequest(final Token accessToken, final OAuthRequest request) { + request.addQuerystringParameter(OAuthConstants.ACCESS_TOKEN, accessToken.getToken()); + } + + /** + * {@inheritDoc} + */ + public String getAuthorizationUrl(final Token requestToken) { + return api.getAuthorizationUrl(config); + } + + /** + * {@inheritDoc} + */ + public Token getAccessToken(final Token requestToken) { + final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), + api.getAccessTokenEndpoint()); + request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); + request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); + request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback()); + if (config.hasScope()) { + request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope()); + } + final Response response = request.send(); + return api.getAccessTokenExtractor().extract(response.getBody()); + } } diff --git a/src/main/java/org/scribe/oauth/OAuthService.java b/src/main/java/org/scribe/oauth/OAuthService.java index 0c9c57e9b..cc1f5147c 100644 --- a/src/main/java/org/scribe/oauth/OAuthService.java +++ b/src/main/java/org/scribe/oauth/OAuthService.java @@ -1,6 +1,8 @@ package org.scribe.oauth; -import org.scribe.model.*; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Token; +import org.scribe.model.Verifier; /** * The main Scribe object. @@ -9,45 +11,52 @@ * * @author Pablo Fernandez */ -public interface OAuthService -{ - /** - * Retrieve the request token. - * - * @return request token - */ - public Token getRequestToken(); +public interface OAuthService { + /** + * Retrieve the request token. + * + * @return request token + */ + public Token getRequestToken(); - /** - * Retrieve the access token - * - * @param requestToken request token (obtained previously) - * @param verifier verifier code - * @return access token - */ - public Token getAccessToken(Token requestToken, Verifier verifier); + /** + * Retrieve the access token + * + * @param requestToken request token (obtained previously) + * @param verifier verifier code + * @return access token + */ + public Token getAccessToken(Token requestToken, Verifier verifier); - /** - * Signs am OAuth request - * - * @param accessToken access token (obtained previously) - * @param request request to sign - */ - public void signRequest(Token accessToken, OAuthRequest request); + /** + * Retrieve the access token + * + * @param requestToken request token (obtained previously) + * @return access token + */ + public Token getAccessToken(Token requestToken); - /** - * Returns the OAuth version of the service. - * - * @return oauth version as string - */ - public String getVersion(); - - /** - * Returns the URL where you should redirect your users to authenticate - * your application. - * - * @param requestToken the request token you need to authorize - * @return the URL where you should redirect your users - */ - public String getAuthorizationUrl(Token requestToken); + /** + * Signs am OAuth request + * + * @param accessToken access token (obtained previously) + * @param request request to sign + */ + public void signRequest(Token accessToken, OAuthRequest request); + + /** + * Returns the OAuth version of the service. + * + * @return oauth version as string + */ + public String getVersion(); + + /** + * Returns the URL where you should redirect your users to authenticate + * your application. + * + * @param requestToken the request token you need to authorize + * @return the URL where you should redirect your users + */ + public String getAuthorizationUrl(Token requestToken); } diff --git a/src/main/java/org/scribe/services/CommonsEncoder.java b/src/main/java/org/scribe/services/CommonsEncoder.java index 4269a69cc..926d966bd 100644 --- a/src/main/java/org/scribe/services/CommonsEncoder.java +++ b/src/main/java/org/scribe/services/CommonsEncoder.java @@ -8,7 +8,7 @@ public class CommonsEncoder extends Base64Encoder { - @Override + public String encode(byte[] bytes) { try @@ -21,7 +21,7 @@ public String encode(byte[] bytes) } } - @Override + public String getType() { return "CommonsCodec"; diff --git a/src/main/java/org/scribe/services/DatatypeConverterEncoder.java b/src/main/java/org/scribe/services/DatatypeConverterEncoder.java index d147eba50..8e7d1a4c9 100644 --- a/src/main/java/org/scribe/services/DatatypeConverterEncoder.java +++ b/src/main/java/org/scribe/services/DatatypeConverterEncoder.java @@ -4,13 +4,13 @@ public class DatatypeConverterEncoder extends Base64Encoder { - @Override + public String encode(byte[] bytes) { return DatatypeConverter.printBase64Binary(bytes); } - @Override + public String getType() { return "DatatypeConverter"; diff --git a/src/main/java/org/scribe/services/TimestampService.java b/src/main/java/org/scribe/services/TimestampService.java index 221a226b4..40f7b4dda 100644 --- a/src/main/java/org/scribe/services/TimestampService.java +++ b/src/main/java/org/scribe/services/TimestampService.java @@ -17,7 +17,7 @@ public interface TimestampService public String getTimestampInSeconds(); /** - * Returns a nonce (unique value for each request) + * Returns a nonce (unique name for each request) * * @return nonce */ diff --git a/src/main/java/org/scribe/services/TimestampServiceImpl.java b/src/main/java/org/scribe/services/TimestampServiceImpl.java index 486e93c64..733c0d5f4 100644 --- a/src/main/java/org/scribe/services/TimestampServiceImpl.java +++ b/src/main/java/org/scribe/services/TimestampServiceImpl.java @@ -1,68 +1,60 @@ package org.scribe.services; -import java.util.*; +import java.util.Random; /** * Implementation of {@link TimestampService} using plain java classes. * * @author Pablo Fernandez */ -public class TimestampServiceImpl implements TimestampService -{ - private Timer timer; - - /** - * Default constructor. - */ - public TimestampServiceImpl() - { - timer = new Timer(); - } - - /** - * {@inheritDoc} - */ - public String getNonce() - { - Long ts = getTs(); - return String.valueOf(ts + timer.getRandomInteger()); - } +public class TimestampServiceImpl implements TimestampService { + private Timer timer; + + /** + * Default constructor. + */ + public TimestampServiceImpl() { + timer = new Timer(); + } - /** - * {@inheritDoc} - */ - public String getTimestampInSeconds() - { - return String.valueOf(getTs()); - } + /** + * {@inheritDoc} + */ + public String getNonce() { + final long ts = getTs(); + return String.valueOf(ts + timer.getRandomInteger()); + } - private Long getTs() - { - return timer.getMilis() / 1000; - } + /** + * {@inheritDoc} + */ + public String getTimestampInSeconds() { + return String.valueOf(getTs()); + } - void setTimer(Timer timer) - { - this.timer = timer; - } + private long getTs() { + return timer.getMilis() / 1000; + } - /** - * Inner class that uses {@link System} for generating the timestamps. - * - * @author Pablo Fernandez - */ - static class Timer - { - private final Random rand = new Random(); - Long getMilis() - { - return System.currentTimeMillis(); + void setTimer(final Timer timer) { + this.timer = timer; } - Integer getRandomInteger() - { - return rand.nextInt(); + /** + * Inner class that uses {@link System} for generating the timestamps. + * + * @author Pablo Fernandez + */ + static class Timer { + private final Random rand = new Random(); + + long getMilis() { + return System.currentTimeMillis(); + } + + int getRandomInteger() { + return rand.nextInt(); + } } - } } diff --git a/src/main/java/org/scribe/utils/MapUtils.java b/src/main/java/org/scribe/utils/MapUtils.java index ee09d16b3..16941a4e9 100644 --- a/src/main/java/org/scribe/utils/MapUtils.java +++ b/src/main/java/org/scribe/utils/MapUtils.java @@ -1,24 +1,32 @@ package org.scribe.utils; +import java.util.Iterator; import java.util.Map; +import java.util.Map.Entry; /** * @author: Pablo Fernandez */ -public class MapUtils -{ - private MapUtils(){} +public class MapUtils { + private MapUtils() { + } + + public static/**/String toString(final Map/**/map) { + if (map == null) { + return ""; + } + if (map.isEmpty()) { + return "{}"; + } - public static String toString(Map map) - { - if (map == null) return ""; - if (map.isEmpty()) return "{}"; + final StringBuilder result = new StringBuilder(); - StringBuilder result = new StringBuilder(); - for(Map.Entry entry : map.entrySet()) - { - result.append(String.format(", %s -> %s ", entry.getKey().toString(), entry.getValue().toString())); + final Iterator i = map.entrySet().iterator(); + while (i.hasNext()) { + final Map.Entry/**/entry = (Entry) i.next(); + result.append(", " + String.valueOf(entry.getKey()) + " -> " + + String.valueOf(entry.getValue()) + " "); + } + return "{" + result.substring(1) + "}"; } - return "{" + result.substring(1) + "}"; - } } diff --git a/src/main/java/org/scribe/utils/OAuthEncoder.java b/src/main/java/org/scribe/utils/OAuthEncoder.java index 7fdbc84cc..f0245c560 100644 --- a/src/main/java/org/scribe/utils/OAuthEncoder.java +++ b/src/main/java/org/scribe/utils/OAuthEncoder.java @@ -1,64 +1,61 @@ package org.scribe.utils; -import java.io.*; -import java.net.*; -import java.util.*; -import java.util.regex.*; -import org.scribe.exceptions.*; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.regex.Pattern; + +import org.scribe.exceptions.OAuthException; /** * @author: Pablo Fernandez */ -public class OAuthEncoder -{ - private static String CHARSET = "UTF-8"; - private static final Map ENCODING_RULES; - - static - { - Map rules = new HashMap(); - rules.put("*", "%2A"); - rules.put("+", "%20"); - rules.put("%7E", "~"); - ENCODING_RULES = Collections.unmodifiableMap(rules); - } +public class OAuthEncoder { + private static String CHARSET = "UTF-8"; + private static final Map/**/ENCODING_RULES; - private OAuthEncoder(){} - - public static String encode(String plain) - { - Preconditions.checkNotNull(plain, "Cannot encode null object"); - String encoded = ""; - try - { - encoded = URLEncoder.encode(plain, CHARSET); - } - catch (UnsupportedEncodingException uee) - { - throw new OAuthException("Charset not found while encoding string: " + CHARSET, uee); + static { + final Map/**/rules = new HashMap/**/(); + rules.put("*", "%2A"); + rules.put("+", "%20"); + rules.put("%7E", "~"); + ENCODING_RULES = Collections.unmodifiableMap(rules); } - for(Map.Entry rule : ENCODING_RULES.entrySet()) - { - encoded = applyRule(encoded, rule.getKey(), rule.getValue()); + + private OAuthEncoder() { } - return encoded; - } - private static String applyRule(String encoded, String toReplace, String replacement) - { - return encoded.replaceAll(Pattern.quote(toReplace), replacement); - } + public static String encode(final String plain) { + Preconditions.checkNotNull(plain, "Cannot encode null object"); + String encoded = ""; + try { + encoded = URLEncoder.encode(plain, CHARSET); + } catch (final UnsupportedEncodingException uee) { + throw new OAuthException("Charset not found while encoding string: " + CHARSET, uee); + } + final Iterator i = ENCODING_RULES.entrySet().iterator(); + while (i.hasNext()) { + final Map.Entry/**/rule = (Map.Entry) i.next(); + encoded = applyRule(encoded, (String) rule.getKey(), (String) rule.getValue()); + } + return encoded; + } - public static String decode(String encoded) - { - Preconditions.checkNotNull(encoded, "Cannot decode null object"); - try - { - return URLDecoder.decode(encoded, CHARSET); + private static String applyRule(final String encoded, final String toReplace, + final String replacement) { + return encoded.replaceAll(Pattern.quote(toReplace), replacement); } - catch(UnsupportedEncodingException uee) - { - throw new OAuthException("Charset not found while decoding string: " + CHARSET, uee); + + public static String decode(final String encoded) { + Preconditions.checkNotNull(encoded, "Cannot decode null object"); + try { + return URLDecoder.decode(encoded, CHARSET); + } catch (final UnsupportedEncodingException uee) { + throw new OAuthException("Charset not found while decoding string: " + CHARSET, uee); + } } - } } From dcc0600442d9e7d7aa538e0c67281a77a8d180c4 Mon Sep 17 00:00:00 2001 From: Duane Musser Date: Mon, 23 Sep 2013 14:01:01 -0400 Subject: [PATCH 03/11] update build file to correct source path --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 4dac9f523..6c4b01c0a 100644 --- a/build.xml +++ b/build.xml @@ -5,7 +5,7 @@ - + From a2fd41372e679cc3ea9a25d64e25f122c924fa95 Mon Sep 17 00:00:00 2001 From: Duane Musser Date: Mon, 30 Sep 2013 09:40:28 -0400 Subject: [PATCH 04/11] refactor connections to allow swapping. use apache regex. --- .externalToolBuilders/Scribe Builder.launch | 17 ++ dist/scribe.jar | Bin 0 -> 95839 bytes lib/commons-codec-1.5.jar | Bin 0 -> 73098 bytes lib/commons-lang-2.6.jar | Bin 0 -> 284220 bytes lib/jakarta-regexp-1.5.jar | Bin 0 -> 33028 bytes .../org/scribe/builder/api/AWeberApi.java | 0 .../org/scribe/builder/api/DiggApi.java | 0 .../org/scribe/builder/api/DropBoxApi.java | 0 .../org/scribe/builder/api/EvernoteApi.java | 0 .../org/scribe/builder/api/FacebookApi.java | 6 +- .../org/scribe/builder/api/FlickrApi.java | 0 .../scribe/builder/api/Foursquare2Api.java | 6 +- .../org/scribe/builder/api/FoursquareApi.java | 0 .../org/scribe/builder/api/FreelancerApi.java | 0 .../org/scribe/builder/api/GetGlueApi.java | 0 .../org/scribe/builder/api/GoogleApi.java | 0 .../org/scribe/builder/api/ImgUrApi.java | 0 .../org/scribe/builder/api/KaixinApi.java | 0 .../org/scribe/builder/api/KaixinApi20.java | 5 +- .../org/scribe/builder/api/LinkedInApi.java | 2 +- .../org/scribe/builder/api/LiveApi.java | 5 +- .../org/scribe/builder/api/LoveFilmApi.java | 0 .../org/scribe/builder/api/MeetupApi.java | 0 .../org/scribe/builder/api/MendeleyApi.java | 0 .../org/scribe/builder/api/MisoApi.java | 0 .../org/scribe/builder/api/NetProspexApi.java | 0 .../scribe/builder/api/NeteaseWeibooApi.java | 0 .../org/scribe/builder/api/PlurkApi.java | 0 .../org/scribe/builder/api/Px500Api.java | 0 .../org/scribe/builder/api/QWeiboApi.java | 0 .../org/scribe/builder/api/RenrenApi.java | 5 +- .../org/scribe/builder/api/SapoApi.java | 0 .../org/scribe/builder/api/SimpleGeoApi.java | 0 .../org/scribe/builder/api/SinaWeiboApi.java | 0 .../scribe/builder/api/SinaWeiboApi20.java | 5 +- .../org/scribe/builder/api/SkyrockApi.java | 0 .../org/scribe/builder/api/SohuWeiboApi.java | 0 .../org/scribe/builder/api/TrelloApi.java | 0 .../org/scribe/builder/api/TumblrApi.java | 0 .../org/scribe/builder/api/TwitterApi.java | 0 .../org/scribe/builder/api/UbuntuOneApi.java | 0 .../org/scribe/builder/api/ViadeoApi.java | 5 +- .../org/scribe/builder/api/VimeoApi.java | 0 .../org/scribe/builder/api/VkontakteApi.java | 5 +- .../org/scribe/builder/api/XingApi.java | 0 .../org/scribe/builder/api/YahooApi.java | 0 .../org/scribe/builder/api/YammerApi.java | 0 .../builder/api/ConstantContactApi2.java | 22 +- .../extractors/AccessTokenExtractor.java | 2 +- .../extractors/BaseStringExtractorImpl.java | 2 +- .../scribe/extractors/JsonTokenExtractor.java | 37 ++- .../extractors/RequestTokenExtractor.java | 2 +- .../extractors/TokenExtractor20Impl.java | 50 ++-- .../scribe/extractors/TokenExtractorImpl.java | 59 ++--- .../java/org/scribe/model/OAuthRequest.java | 140 +++++++++- .../java/org/scribe/model/ParameterList.java | 5 +- src/main/java/org/scribe/model/Request.java | 250 +++--------------- .../java/org/scribe/model/RequestFactory.java | 14 + .../org/scribe/model/RequestHttpImpl.java | 207 +++++++++++++++ src/main/java/org/scribe/model/Response.java | 84 ++---- .../org/scribe/model/ResponseHttpImpl.java | 104 ++++++++ .../org/scribe/oauth/OAuth10aServiceImpl.java | 65 ++--- .../org/scribe/oauth/OAuth20ServiceImpl.java | 9 +- .../java/org/scribe/oauth/OAuthService.java | 11 +- .../services/DatatypeConverterEncoder.java | 22 +- .../services/HMACSha1SignatureService.java | 86 +++--- .../java/org/scribe/utils/OAuthEncoder.java | 4 +- .../java/org/scribe/utils/Preconditions.java | 136 +++++----- .../java/org/scribe/utils/StreamUtils.java | 63 +++-- 69 files changed, 823 insertions(+), 612 deletions(-) create mode 100644 .externalToolBuilders/Scribe Builder.launch create mode 100644 dist/scribe.jar create mode 100644 lib/commons-codec-1.5.jar create mode 100644 lib/commons-lang-2.6.jar create mode 100644 lib/jakarta-regexp-1.5.jar rename src/{main/java => apis}/org/scribe/builder/api/AWeberApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/DiggApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/DropBoxApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/EvernoteApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/FacebookApi.java (77%) rename src/{main/java => apis}/org/scribe/builder/api/FlickrApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/Foursquare2Api.java (78%) rename src/{main/java => apis}/org/scribe/builder/api/FoursquareApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/FreelancerApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/GetGlueApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/GoogleApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/ImgUrApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/KaixinApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/KaixinApi20.java (82%) rename src/{main/java => apis}/org/scribe/builder/api/LinkedInApi.java (97%) rename src/{main/java => apis}/org/scribe/builder/api/LiveApi.java (80%) rename src/{main/java => apis}/org/scribe/builder/api/LoveFilmApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/MeetupApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/MendeleyApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/MisoApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/NetProspexApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/NeteaseWeibooApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/PlurkApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/Px500Api.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/QWeiboApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/RenrenApi.java (81%) rename src/{main/java => apis}/org/scribe/builder/api/SapoApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/SimpleGeoApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/SinaWeiboApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/SinaWeiboApi20.java (83%) rename src/{main/java => apis}/org/scribe/builder/api/SkyrockApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/SohuWeiboApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/TrelloApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/TumblrApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/TwitterApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/UbuntuOneApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/ViadeoApi.java (83%) rename src/{main/java => apis}/org/scribe/builder/api/VimeoApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/VkontakteApi.java (84%) rename src/{main/java => apis}/org/scribe/builder/api/XingApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/YahooApi.java (100%) rename src/{main/java => apis}/org/scribe/builder/api/YammerApi.java (100%) create mode 100644 src/main/java/org/scribe/model/RequestFactory.java create mode 100644 src/main/java/org/scribe/model/RequestHttpImpl.java create mode 100644 src/main/java/org/scribe/model/ResponseHttpImpl.java diff --git a/.externalToolBuilders/Scribe Builder.launch b/.externalToolBuilders/Scribe Builder.launch new file mode 100644 index 000000000..4f6129480 --- /dev/null +++ b/.externalToolBuilders/Scribe Builder.launch @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/dist/scribe.jar b/dist/scribe.jar new file mode 100644 index 0000000000000000000000000000000000000000..bcf4bcd203ce89c3becd4eed4bbd539118025feb GIT binary patch literal 95839 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

`CF@(u6aLJrk8bq( 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

|Yf_WZ!duczzo?tV8>Pnk?`BL^_(g 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%0DSh2+l;L|*$wF?P7}7wSeE*} z#E9I709|?L`}o=nAi8uMe*fwph^t(xr#2@v(J~K!J3>T?3!_i*l!XrUTM>gja1?p> z=i5;v$zwL@=qz^99WA675v6kwZj_XD(CEk8mhir*BXjD8_SR04#8ph&Q$o^SjxEfq zzqqo(%dJt&iaGN|ePNmV5wV%}a&65_ii?=nSFxjsEIPaDVlhO9T9kiNv}xkAq)7_u zW2HoCUY(Id;WsX4h6gLvbOK2=thr%R;Q6e;;~rb$KT5N2q!&a5NHTV_Y+Rw%{t-CHm7urG_vQqj>M!HeXs4O z+&YC0j!woom+{l_Kov@f&-f3nVaK_EQ}aS)6%fkJ?Y5KuO;AARWFl)UYBWtu{b&dg zpyXaWEqVwQw`$VbT>KS(wP1N_Q!0_i&C>Zw-s#opF^+=8W?Qu}b`E)8`h@zWxh$ZR zBFvq03sO6zH9z+|PeiR$vKUMd0yN{JhdfhJo)E@^3KI*Z+T6H8Bnf67 zHik6a7k*2X6i?yKu_RCWs`zfk-Z5z6SsMt360h(K1|+@b)~Z#Q%bBoc)XT_56I+B> zX*alF74cf8Nffh?(jic(LZ~?sWEP8%CqkTxXx(&okbQJOtZrl|IAot)Pyb6}t2Kg* zCcBRfG!m7TI*xSG=vLXIEqj*yuPW{$_Oj%a5~}Q8azrT&caYsJVTs;`NcZJsLU4%P zzD59tS@Hu8_h>k^p6#xOHIefAs5o8iWurYPugPwwd;h@mjZgDO-+-!hW1SdH-bf0n zD}nVc;|2X~L5Sao6sqn>ulj1lq|C>hAQmC2Z?GEm2Rhf1V|$3&Ed>&v0-hQqva!_k zsX1FI^#?Lv;|->-?VbzNcSW>2a4)?210W@voh2hLTB|mS#i7g$=VcC~S-Q`7IPF#c zDT2v@vxp&1x$LGz=8SySYJfN8`WeMQnR$irz;terq6qy)recLOn-a>Jr^r4 zbe!dy#>C(f)REGC>7E5J6s2sb(y-XE?cG9I!)ElzUqT)1bs#tLwY@*9$@0JyP4U>I|z#UH}w!yY@#8YHl9 zqsU81x*S1ykm8FmA$ntWxL@o>R>E8|ZgaeQcoj9| zm4%qr)a7vC&8;2gv?<+Asrn6NPhfKJ8yD?1nzPG`oQl8E7snGl+th*qxp14DZxp|t$oES6}smgI1jkR5<3Ij`1X zB5KWufTk{H;7@Si@;-UleP|%URsIfGO=q-@3-3BrSpE2ugO0(y)yb#JUtOcLORTVN zkKn&cE9{VLVcacgZ8AjZl_ZA=pv+az;+c@ycPUr)CyQ`?kZf3>|kqplTS z4rli_2=_gfP%|i}`VWJWZ84pVfSi8CYZ*IUk5V_I#Z*ryc-^kP4+$eA$J3f&7X#NV z^U^)X0>0Sz@p+4I7(oXTl}zPl^7#ukr)?*@sj)VIF1_)-IU^s-iPqyI4O1`_rIAcb z3g&=UPQ|;5+6)_M2vx*Ns=h{j)S!Juqm?ku)=n!~s2sshyG5XK@=6nF(u4J)qryej z4#Lw#Zb$Js`e~t#wbL8dXVXo#>(T5tgn0>GrLH*g;p3%^w&A7mrPP+@<&eA9F88T< zti3Y;vl+qKih#Eo0K@7ty*WT!2|&RX0Efl*!9U%><@&VcDHF9p!NI@dmxhO}R^XYI z`XKX}X?{S8-EwgUurb88(g*bJwcYGXC=6f}K$i-mUh5*+?W^tKd}K|H))vQn|1SNejk?wHe9Lnr_`+Y=n{{OR zBCH+SHip_tP}~1L`P?=U6!)mU8RHos<0AsP^RGMbPba`b^0PJ7jAk)1AO4on~veU{h; z%kdy2@=_SQMS5j~`3x&LH>8**1gFjU7SCIa_(~m6X~4+)JvrJE;if}+#Fco6Vu8cB zdza}b2Zm|i{CenscAQokuJrfgE(ZDvfc8(Kj0&yCXhj+60n3o?K*3wdOXK;WR+FaJ zc=}giA)1#7a-RO}qhVebbRO}+Agaz(2yGws$VP!54@p^rP9*~UT3ERDT9bzMWD2NZMp0*uZ5 z6iNLP=YSQ3okuhH)tR?^5Ld!8NNa;!G`Yy6&p z_wCU%dnD7y&oQ)CV=$1reM;@>(Lf;9{L1DdAZH}Trk?c5>qTybhyKJp0(U9Zw2EqH zm)jF&ohFfu$!9n8RCM87^vnV(aUC>E9f31PM%tfGih{6v8a`afPnYtp+qn65aSN@Z zC+iAtPeZ?+XmY1p4Mtmct9p23wsZ6CwoB}07g~>b>+E>iMwVHGH+`>;smt54>Jtm4 zD6cq+bYBu7lyl6K%Ti)d-(aE3e$^1jm`Q6YO>Y2HcFKJO z7~b-!6Y`X$V#^fEX<-!TTAIK~T2jplM8+4H6`w34P>^(G#mlXGRa;#HSRk93?-p=1 z<3OQp=3nZt2bfr)IcTVH+R0~Va@vt+NWRE~$NQ}Jnru$A|M?Z8nGVXJHlwT`5naviF)lhJ2hi>mIa zmX-LrhVvR*waN-UE>6qi&ABeQoHLBNayhjVjfyd@r>7-LtT8%+Clw9TDgA#1np7!< zCiJ)QX&Ys(YdB*Kia7^bde08v&nm6?Ag+Uo1Mb5V$^+~%7kQ&OFw5kOFvFTxd_8>@ z(7OeCtg{hWXtQbaB)M zzrQm-nA`)_$SymTDuFzK9BE7^$-$^P&Rex(f2+`rmUZB=N?1F}`l_K#z!$cDaO~iJ z{Djz@Md?XIvDn08q0uCf)YXTS6k)0HIjchgMWECntcs!2vX^B^?`$ z$5HTMvUErQ);4a;E~50nZHVGEQ1;H1wNM7zL^<(Yg|Jg1cXYrFCk(NlVUPGrfNyAR zFY5)moQIlw^j1R;x!ZZC$(lkcK)xq~X7FxBrikiGMa+#Qz`=|8vY$kw*$x0N$rCEjyxgd?ePJ+ zZ&VQhwgfVLBsxk1&58C1qF7y2@}wi$&_u?@FOC0Ka6ko%1EI7cS_g>}%)a+k_I3~a zoz_H|an_ucZY5H71y53NK0k)XswJzjGbLtbLPB3CHI;hyKI{o`8l|b*>O$tuB^FU( z1*!uzMl}d)$IWmvI9)N`U(+P6n`U~nFNJ-{Pzf3ZPF)!#Hi*vzWV2DmmX7HTqr>JM z$tDrD9EoA1^+>_?(uKdpv?-6t7x{R(QJ`>9Kc-#ZS~i1zLuaMeXcQaD=eE z_=uC~GaW|gw-D5?!P((X+TW*VOVNFt4>^0=kuq|I#8tyuXSdDKL+t*Q{QKI@zBT`G z2XI3A_dWA}dxifw+o$%fhOLJ4t&Pe!$;drOWRc{Il^HrEI3~2-G}JW~loDcyZvn23 zlNyj?>;~ovq%t z-5C_`^t93Lbp7nxvweO1-qwis{k#bWz`XYicrikcm-v%g5;;o^K?I0=bEt!U*vJ5} z?<)-=A1>BDWCZ99f%Yn$_T zsD0E9kUP5adIQ7T)fa~LDG&TYs+(vpGSK?rz7}WqOFoJMLhaLCWT4Ww3$+inYlg*J zY`_iJyw9GX+gonnndHNtpx1{O*DQW8G@m4E|0m|8_~oozJXjzieY{`PMLcGtX{0Pe zJYBScp$0Q32JSIuvEUDdR9xxRF1QTz`O|r*Esp-p@+G?r{IqHBh&<*zOtla3d?`ui zQV)BzvhY+HCSNtF%NH%`eRaC5XKS?x!71g{3fNLY8w#%d)V3NLM`>(@?R?2b3QoI} zaf`)ln+|SggS@k5Ok8}%dDAWei)^T^Ue-V(bYf617t{LS4x98jx>$jQw9GJeMFls# zTX2LN=cs(ivsGxZ7Ltx>Y06TJK&V$YY+EWe$Cc6cSf78Y@oIdd*U%P0MrcRM6L+$_ zcjazU)S;%ZIv-pn*MmJ5Ii|KmW989Q? z?T0B7LlLP*B&$cQXNj_Ia)HjJkN@@6ZpV@XBe|uW`~{Ys9F@s%%{r$;Djvn&SDv`# z5QRe@IR{jM!_UE)Eh@H@u%w{;l{v&>G#7~g4T$E%2R>HUK^h8Pvta{rP2rq4|F&84 z=-TK+jA^x4mA>X@&0PVb(P0t4p_(Smj=KW3{IYAVELFTA2t%7+#0pQgk2yF(&Voui zS4{egWs+uA`b@Z`b~gZ)DP`fZWPckkCMp-@gjp<6;j(RJWm0?EluV6ypLc_9AKZ5= z%oKy{hA6Vm?P}tM`mag$5c42vTJMlgSUJ{^&j{mL-E@V(G`{!~Samw8_SF4v4tV7t zZr%Rjj$_fOu@{D|_!}e)zTu{5jjr)9D@0#XBUl>5t;AcWu4w>_Zg=4UI^z#S8tC&) z1Oi-l)iH4+-4URz_*>W`i83;_BSz&es@;z0=Q+ZCA8-79Fx!b2_};`DD~#TLJB%w$ zk~-+;>ZP@25scBgeahiJpE_nEyZ^)3J2qz;w%fYh>DW%5*tTukwrv|v(y?u)W81db zv28oMXRTUQbG;wl+EwRIxa&S~jd6_Gf(vLS74R}ka5!cQah9}NRYxyABgpC$Uf4{~ znG7|eQw#x%3-{f6i=5#0nnlYR|S4Vr)2|UMO=o7 zQi~~$DJjo=M7&G!izw~I|Mu-lb1f@byKblrA)%-+Hf<9NV?$!oGBK78eQrfa@1S?c z{&#CruvgU7n)`(3FIdQ`r2NQkj%Wds@=9gW?3FCm&}G)mLp<5B1-BvMJ{@Y^x+2aa zom>-lFr-A~N!AIXMwcJ%3*`59ZwS4$@fc)NW`34gx=J$W!4c@CB93;_x#j@+uqTedomfxD`1d{{G?Z zmS&bj^`VEX!AmkwY?U<20)1!BX>x)N?b9Gd5#9M0)`2x0Bx;TW9xAo~H8x%!Lnp$@ zL4~5ck1_wmLu?Ky|Bnb1ZLd3;5+C3ybBgIB0;Yx}SUsVSI}kn4y~m(VqYZ3~U09?j zJ{OMt(x@KO5W6~#!w!w0tN#xis8a7ybzz=2-Z>GWX`qJ00DtP?mp5wmGt@hHx(mwr zsg^dAd+<&h&?6>qiY=ASJ^vKPr#VUJ09{|)&|TC3Pn4Zw%n57AGARjHsxYaQQd@wt zi?1^YfL4U|!W`{S_|P-&-`Mj{`r6F4+7KL6@_Sa$Tj#p=rk2peTfz?=ie6iNIs5X7 zU*eH}?9xBp`kT!8YhP(QPH~%H(SO>Hx+pe7G~+p3BRS5?Uo-@z@=;TAVqB+>Y7F$8 zgbQrkF#gGHP?$Qv#y!0m(~Ov61fO0x-9h_!J zGsCeLk6r-(XLmh_!8uhx*GuOQ8{~k5Uunr3mFr+6rU4`vv&0}L$YU=jfcnTRsZ1w_ zg(T%5&j!NV6mk2-A41o8R0z`J&4?tcoZ~t7aT++HG=WrR2E@#Y6QQ=mLGV7qVQ~yW zGu;B46tR=}_E;l0Zqf7M<`20^2#UNRv1r@~)+G*u>9!UX^2YnBN!09)5TEm{%uK;m zDoL5}i}rfGN25oQ+vGKcG>w}1E3`1J)<=mwGdl%JNG323BZlB=>#mD#kuo){zn!$k zNW6#Gu>Q23A3I)0n>x8p9Po%H;l#5D=}@tZ9EF9z@8v;gUmlyqJd;d-J2;dD7zOZbpGoS6t83H^pd96C1n9l4odH+nj5Pd7X zK{i`O`v{cXjlEFK{MOrJ7g;NG`*}5ld-7ZC`U3>3H?OKo?BXdwmGPvJP10@n5A&hn zzo;v>95ZtUssjqXut*{qn&B8M1{BHefH%luIk$xM6-@8M`NOq(5%)Z33;m|uPX;D- zqbk~8TNzkkhuQXp@$URbX9p0HgN@0s@%}n+pLKv%f!%SU{v4rgIu4Dr{w&`7-Eh{u(8 zjin7f{K9G5cGq*(eYW?EyFTB?@wDy_U5eIPykI(D{LT@8Jl&iV%W0=J%n(Uj$H8DW z@c6|eDH91I=JvJ~hDa;~CRu7IWQ5_UA1dp>Oy>vRKX(k33E%F?0?dZaK?#vje+U6t zn`e%5Hu5dV3X=)!M4O7A8T;iE6{qOt0D(w> zG3>GjA1Sj(Xi^pr4>vO{My&LLW;(=iqLP~o6_t-2jn-0>l2I7kVdN=Y838G?lR6VW zbK*>Ld%Y5!?JSORq!b;mR43`Q#v(f4BVI&>Uh;maYqT$Aa^^?{JjLM8LiW3~q^RKy zR)Y;8vFt>7LQ%U_ic8SZk})zbjoQh-V!~G1Q{W+ zE?K2a;t|S;ZU}LnmwX?AQ(A2Al_t?KG=_9#DVhPUnS@yd18l9-Ts}7?QY1YE8a9(C zeCetL;A0l)f{jqNJeN6%<>Y`nF@v6XCm8bF=BbL$?b(QpecOu7XtQtj8ykCeS`q)( zKiM@3Nxdc~t?7HD<(Y&WuLB(=h6-tJ;Usm%s(n_Yt%#qc8eN$aRV6#K&ivDWCTFS| zvmrZ)jI;3NV`wsRRjQO>vIyeUl?yRgy1M&XGz$|ED*N2q?{hVyVV&RyqQ zAZcvI7lR1C=H53U2a~UuT!Pw#Qhwf;sq}%OR_S)XoviM6!@0u!8?>lb30?T z%WGD~PR*ng?8EFbO~;UAy^_+Qt^-9e;bovhk4F+eQZY+j5gK%(sDx-zx!lx!*q4!_ zS4f8_`Thd{c7b1AFfKAkf!9z8<}bNLbF>&Tluaf^uN_jY0g5I@bg!I79So9?-6oWx zP05_()L$c#RjF;kZgOz2T{ar_3d)PMI|JF)FnAZMUEQUdQVPoL3K*|}Ef}7VTBacl z*@$+l2)jh+N;9+~8R}IlbURik`ixM1OE*|w7ecO{-j$O#AzHH1o=Q^4 zb2%}PnC68gMz}}BdJ9Q+Ov%!)aWP|IhQ;}_miiXK;=gKUe##S_y3dtncD)P0v`{zX zdW*0ID6BmjwP@SaKDU(B3l=Yz=76cJt7@?pardfu&vKU>s_as!W5yGXwP-!6WR&OA zL3BTNx`d}?1AtrZr`ZkF8U|queLrLOkJ1@d`TC6C>+13bcyKT`K8RGri%P><*A>27 z4))f7M?Y%-eE!PuB}}*ZI%zXdi8p44RHb@nKj0G2=V!+@W9;zk;vwEK4%V;cv;HSM z^K-Pt*X)*EYT}(1tVCARR?7Qxo_lM*(wbAOcFP-m@gyo&J&;UcN&@iDX~jLl9c%bi zY{&QnIbFQ$0VpTCW#i@L;fup+S=MSVmg00_ZqAwxaC*4F^Uxl1%Z2IE;HW0_xwyO$X!`BQu!2^dw9AjKFON)Si8kuU<-? zyqT9=j@TZ@WG;_j#?B!ckJP^ozyIFyq1+-l?>Qg!t5?Er*MajG;C&2rPLBILtPC#K znKkEtt%{)=Wokr{#e=BkE4=^Hi#5IT*kOiYb&+5Th1x&@>IqFoL*odsh1zX6BIYzN zU4q_M#jT05_oW|{D}_;({Dh~B8wW%&qc($6@rns(cykSG@E(M;Q|)U6jn4y;T?^t} zt(Vx(=TrkB%7Qo!k8pm0j}-OIHD?HiZK45J$1#dfE{Xq5c@Zm!O{(E*jfL~{VDKtE zSC<(GzHAt`n7rZ5?gm}OpO`fK(teQ;tOdf~{{ewL1TY1z{)522ApH2j_Fr0olc|}_ zKf?ySu)UqLi<7Idi@nqT>IhZp*2*}lSbp%6G6ScRctcAxd0`OCFEpVuDUhnXL_t>)oPXVHIDpW%yH_Y6-GtV|h!zrQ0ArdS23r&I##0tr zSt#k1dGf|e%3R*UnH+X!kS-`{?v+AXtGCX%LTwlrHL{h&WhQ4{O=C9O6So;eS~s?u zb+xBf+Y;wbkZ7}`EZ1d<45U>QxvaTq%d55g#*~Ri3_y%ru3_cZl@rR`xh04tjrKHv zmYaN6T>}+|uLe7^SrQT&Pccrlm%u$an4?P&wg138snbDTY)#29ySGG?wt^Out*ooo zVz%nk1#DHE4Ork~DyqYmx|J>JjFyydTtPj4<0;#+LZLi?a)=QXCELk91$YXm#%{|R zqtV!Ba}oYIfuts;*b_<^IKX~nRA>k$?27Igty$K|m&Eu;BbX&04tch{7pSFU~Ngr@rv-g`7pqc9iE z2X=A4Isl_5lpEpfq4IX2?1<;B8f6d%)c~(4lcpM*lznIkao^AY9*Y5J5aO(cv<%t* z{h-=QNR3jDWAH9SMYqF<7P}9HCO=*RBTwm}HN@MT@4?g@DRe0LS zSX!(r8EFxgLd`y&S!C_x734lr8`&B8%ZZuRI5WmLUV7!x0N$iw4GckJ!NJML$m#54 zCw@0Sye!ao1e^@asx_6E@?5^PL&((9MIDY5T&XNs^rx-k+~_3aV1)Cws>{D{>Bvb9 zXm;#`keh}A~Y>o2_%gSWZNWSlo?&v(29iWVy|cwiQ8)j z`nbT#MjQX}Qog64E`BGlJ!ANC2j=y>eI7{sPzM4mV?jpKJ`%x~mgu$$3}zd44;ByqNDYL{*Yv z{LV6V1IaWk^%LLhOGe)_sdgeaT+( ziF0@Fd>jwn7YAR%d$A~6mX(o|wgfb;5Q`UY|D0BH^eq)uHgy_b)Kzp9H7&E7Ku~-3 zhkf&p=_bmnDZ6U1Ae~qTrSG`;ggnC=B)l%EQCzt$Uso!qw&;v$|AhlZzLAG%PAJ?5G?#)`xblxt6Zha~1Z#be4vWM04_jsUJCeh7JmMD; zV)xcEOmkB})Nr=U#;*48bY$2Bd5%+V&(t@iTl4E-xqMymlzb{C|C}jsOEhmP*M;fX zYLc`tMnG+pqgM!oF)9F)5b!L3_FSNcBN!}^rx|7VyEWI9E@aaP&N$DT{#6T50*P~c=6Os5k6(nr%K=&W$YSw)IOfME%Vht7bYp-W9mr3 zW83}zz4Cs#*>LjyTbUH_{yUN4|Mp5TOH&(@|EEiOdY~QxzJ0w-Ql>yjaR}pfkV8l^ zbwMOZNaDkAB1j_1pd&C6r${t6F9tU?CA!X3wY9x1tScUFME*p8QxQs>>()KZdNn>( z^X8O()?6xoSNU$Ik6m0`*}zhGz8tOFZ(aLtZ(s9v+i$&WJJ0;G7}gKs_*E#F6+Hv$ z$ZHqpVEls}Y2L8+@&OxZ z_RjWlfjqvH2`G`SmRGGNKygpl%2@{+Z&@k*s3-x;My}$QBx^Ohz0{wvFX;ynrUg1g zOchsSK?7Ui71nXOAymCw6{d8z5uutKxgzj&Y+PwiXvtLe91;jKG)ts3#$F;u(^ZFV ziLwCy-iLfI=zmw|Tl*0ec&|mpz&K%ol1HLPu8-c?-&fdrENR+-fryFA}A< zfLsZ}TK0aos8{+djZ;swnSv{LN7)-_6~5lU%v3 z5YlQatz+Gud#o#Tcbq4O3~;tozgWXY`ZCHv>W)fdjLWoKpgb(*BJCkJ%=n>@M_20O z%v1(XHRgKScTt-$e@RDDyR%2gih9ft8rlHhO`3mD$i2df4_i@Fy!RLx*^AX+}f^p>D%R$}Qa%ab>;;SrP0rDR_ex8;Vqg zq*SkND30_;1ab{;5im+PfJG~FX--6J2H2<~v0W9?=whKEU6DU{BcWtUxAcXW&1B^z zkne1g9;LtUYgVK^Y=5H-NZpl+G*Q-O^zIp`a6vyLIWzshyGFV3a!VCu{-?g3p_oJm zK&v!6vf?_OC!@lUp9ba2pA`_t;ilFlidx-^zEyqHn+`F#WrThI`Wh{VpbRjRhPMpm z#kl?ku4p#O4Ez{;+sV*Xeb zev~<3VMS_jyT&UOVS%8h`WR}Z%Gfo-2<|-WITy@1BAgc#5M46gtFL;W2Z@nx?QHC{ zwyL7nKuZWqk(I=pfs2E#r84}_JYZKOD%5;-~EEWQ>&{E*t;iHCG_sHlaKT zN&O0la7c6q$+;Q@?TlyCo|D-(g&?Wdmvht99Nh@Gcj(?#1Y_F=Q6kTW)t(jQ{wvU8 zDZnErmlVI4f8(fv6MS7S^^KI&HOulUy{Esc@xWRc#THFGdsOihZ9EJb%oS|k{GgCoT(A#*-kt_Wo?yk7L2DP$KCwS@M+wtn+C zhSDPp$MwW%+MM<{st+aQPJD2?jw*?g0wjAD>2$jTUV;&upD7ESP<7J~$8@jlc|d#L+71#0>*8A)WNKSBhwb?jiuOrk zr6exXLErv7ugYzFp4F!xLwa{>gx8$g`#aPMjCoqnpqz^H`4>91EdKJ+aK(1z52tBFM`=CG$HvHs|J;`{xIpwa}qR4&zf zwYrs-ZTe6RP!lE^O>-=4Rn8N8bl15iZc;hf))W>cY(tJmM~dfW(A z(a4RJ-m$MG-N}~-l-w6Il&{7We_TL<7`IAKW2H)Y;wBat6wCkWo`_ZD9!;<#k z0C(?TGjT_xfzxw!uV`VXNaZkzL$=&E3twa^L&)k&YVjlb&nvfDxW7TwOKEV1-1^x6 zRA$D%TB2Kw+Tn7y(t<8~rB}Q+#A8i_0@P}EV6zfStdCTBZbltoDA<kVO-nuABgMz`_T#>3emPax<#s&PE`_Zn#z z8p`COkS-Jb*vsnb@{TQsCXCc$`j`AMCHgy*x&`QD~&88M%Z2`5wbY766p-^?Df ze35a?0=-+}A@cNCX3wKX#R-xsT7jdOj}6@VW&xS1w+plGLof;4)_VF^hFjFpgqWEc!l zaFO-eUM(y``$gPe!QxaMt#y(veIp_=Tdj2-p||@Bq621LW9Xz8k{F$Z1IoQU*eybBP(b=#Q1zZ z3$gaQj*Q+yI6L)7^3b8Bs6N^>-H9W+Y53bi&!{|?;!rt?HTY2OZ#em5_B|QB`+lSBy#Nuk@Z|PH9S=ys zdL{>IZk+J^XhXNdc9Ssus6)5IchNd4cT~X=k?%6KwfZxbS5TI{NF*+ip|vVS=I2o4 zYVh!x>j6ljL2K2ImUGiNzx#PFX_3c?ARY(2gmvU$SyzV*Ho`dJa6_4G;8-Lzx=K4( zH*oDP&(G|xEv_xE;hrBwI{Gt!y@i&?T6G0H-&hZdylgfsgO%|}!v=NULW_JOQ81qsiJ=QPk$|xxNyb=>C&JCHC)jK+(MRiKX&DZrg7NRsnWCr_l%#Qa$q zx6?Y|x43vN+2e|}if86D;^hEN3oJIt^7O1!*>@(-eMwaD`zaGGGO2~Mg)RzH5pmb` zlX+X;L5H;XTgBkMu#1^44v-ELCalmN(qG(LUnR&}LnW|xfh_Pl`?V;=2_K5eJP|PcJ2dyE!toT~9wmnrxbbp1L zk_hM3LL=w}Dz2f6SdU1}x2zJC{Cw@9%~tWgsEGSCQlY7PegjQMVe*xAA%DqGKZRRW zAK8#VLA2|gs0c$wZ;b1*)&OQ`y7E@w1l1Rb%^UMq!JZxqui$b3`^jFzVXizNa;s-v%Xw6b^H!&o9HdNWipMWr!hvEU&OP?` zqa+T_c`QsX)zPk6uq+Xax37*;av38u`j75_>CgVzC@``s!Ka*b4jWu1&~Z`p5zC+T z8=c502`9S#f>;`Mx{3S?x=XVBW&&T9V-(&FPtC z%Pw7r!0PVg=q!<4XfCgqtuK%8A`R`vROeXeOBbahX|W1XJ}4wJ6onRES$vW$6XhUyyFcn|Qo1T7wNb_lwG{4BprLGIdSO<#yu?TO|4 zX+BUiMm)QLfIkfsX#rRX=Cwx1P9vOBWkYIM`X`oEc`gR*vQYwg?u<`yg_%6>qs4P$ z;yRIRO6P2T_(I(BO8j_7lyN-?rc<~6Js_le|+!(;uR1lI8WC8y#vIw#YR%)QdGJAl}crut?!rJ#&>qPBAK3zK;Q zccfE_=oQ>*thi@$z_3pUb9&GBP0m9U=UBFmAN%3&2KVIObU8*Q6WG_u)*J_*E92JA zW_9iSJ~Y}H9~b<64bIDzzx!`Ft7DY6U}&;YU}r&3N00_1t6e)N+T!?qE4|V?{J_1) zX;U;gxR|Lw{sR4Go@B$?n$2%Neq2rx@z*%bOk36ru3MYcnt^x{irHTN{a~2L>kcK= zcSFu>ZL$L)H9BvGI)M0f_-Po*{O9TSSe@VVfq8Cdbw38I%?Uzj+x+PG53vbEI*1!`gCz5HG z`*d+vjWY|uvW7}dSb`EqNl9xx zp;ejxY)u`714|TjigW}hGI&F&^Q7cCW;R;(36D3=SmDQ)HoL`iIyN)!oy z%*9eIPBwX$ubsD91-x_!pb@JMv@S7OX=^mG`<7)}f6_Qv)4fRpq2dYO{{uV;WroE) z_Ro!85BUE(Be_`E|L=Qclg7I<$_jwjo7U3S)Apk`01os%#S}meWKS}H1zi`yTo-^N zF`-><7D$OAQ6{j&lg$v%#DL2WM9i24Ewx<8Xk?^AO<==KJC)(K<@zkkX0tVall~5p zTc34ySFfjmVpudBcE8?w-@Nua_BrOp;~>2(_R zc0aWp&PavR1u(*%+MxT{8wul!AM$}8qe0|Xb0ZD%GVl2RUvi*IM z_m@{L<8uENkmaNfZ_Snmhvf~05Jd4dBO(!6YZ&eD$}zMI__87b-i8aHnW>W#{7DY+ z79|mcKJ@7orAVF@NBjv6F+QKl68hL`@)XDo$F#0#=k|V)rCK}{Bg<4JRrO)VQwf1G zMj|hZZ7qKiuE4k(#753oD84b7BQQG1FQrjYGxUKeGI;YEGR&Nf2~YeoR|t~yv+iA!mI{VJ2tsYM*ZNYGeW0(~o?F{oXFZvG{@J##<3f36nx zTqSG%hKsGX+T28Pz_OFjmd%&0xtA$ z6|Btzlz+(qDOKe|X2A5H`9D51_SPA$rLYT5&( zLP;TY0k`s7jA+VhI=b0DZ0LdbsoE5~rP0mhYO}rD)7W@qE3~;eR1WOb#RR5nLpiY! zGexTc>l5zsa!i!2t7kh*p_xzqDZFM3tDZ$bpNhTV-#E$p*NkOUUZko!C_<+?{mPP^ z3mSH!d>vZt=w&UsB@2DD(3)E(l{j>r#$q2av{U9U<-E}CoKwDm*%cKzMrHNip$&#* zIPhe8;)aGlV=sm8LYsud=GdDJ-2^{}2934Yql)o7C%)sdn| zvJ2LwKK4=-z(PW-cct794=>S8Ks4^G@!Zd{(vY?vu^D9dVt`g<%LwTlD?2SBX{H8= zDoh9n7fDZ1_$mo_JC7on1It$<3tpu2wewpOGqmD`PcNZBG1ECodZNe6tnvn zdV=p{;ds;BOJ1LjRQVA3(r1vQ`wK`Kvvam+?A>1Qj2{`MKvIoy^Pkq=PFfNWeywpM z=5;O0j(`H@nH9dE&io|u)HbJ@)8e)ILFh^rVaj2uO19(3x=>>feIx!{HM`0o-y^>B z3*Rks8alqzw`#%9A2GDu)Yj&Dq0Y&~_UR4%ocAm7ZBn9+_b+y@pf>dLqMpzehgF5b! zp}FY=sHw5U9BIGD$?D=m2Ph2fF^e%2o)n7*&auTj$;R1R7XVLNzz?028*5J7YX+#} z*{ElkBBQn_%GR8c8ENQLg2~q=%-ARshDpU_`9_@m8Q#Uu z9Pe)k&0mQ5CB^6?#`y6GgCs27jF}*iP#_UuI4%;t+p}@%e88+CYdEKzrZ5z4H56ht z#2aX|lRQ4`HaC1U)1Lx9nTfKh0<(&#A_cE9&cl)PD$*49hezaah@}{v84drs>e2Gg z2c$to_;{|+p?v<``k#_HF7|RYn~wCsQd0??zf59#V_o*Nj$88N0(;5nEVu-+hV!U` z`N*PW^RZNi1n4)X%6sf_9!w|Pi5}L?u=QuUT6ORIrZ-HtxWwJ+6v6vReNf{&tm8W* zrVd^praL`tu;omqH@mpwz5IksX*rS$HIfVV5)1Z}!P|=9xk}(YrLcU(uwOSJqj|Wv zPol;&hH{a$laT){fbuBM;quY(9$m&2EV^F&APt#Er`hfM$aT>PN`La9u z)?|N_FaOEtP92TW*X)=2Hd95biGsxxQ8E_m2|4cx_e)xJ4{?VTN{(d0ahH_bf-1be zi^NXZu|UqdL_T(f^TO%lCXbpvTessD4{<~Ky)Q&Cg%E780?45P%!NS`m2jm=WYaWq zDg|mPMf&nunMoPZsV>=QDIGm#t1l4oVnCAt7umX&+XQ~4+oJgkUE-Oc1`LR+x}t6> zY-{WEft^LNFrYlKA$aB6%t=EoSCtZ87665xRS+{rC)C!O8NU?_Fk-wymaY?^kYvxD7lwl{wqxpC)mfs2sGmmEZ^{mE z{pRozh&jCkvA-j4ICwVk%s@bvB?3J~=p>=Fz-w|V5(#)=y)>Z@$j$%-U_zif$m@CG zY%*xLY4ptl#9WRw9${sx(P%;=SaTuoz(BLP;DD1MwzaE+_AVkDSog`l&62gs^hD7#scKX>WdW0<_O7M7609LARd4hqwqlX2?OIwOnk2%k*ic`}UdEF#7V z*%C=t<<*LNC|7^efsS?c=kSCLfBy&T6l1eut@EGX%<^BP>3@qe{ih?aG_YB$1rbBP@7N5|Ycohqe##l72nvB9AtDooiyXWlh9R`E3QyP_qzg9u*sJ2u z-0S^ygQ{~6se`Dx|5G%^H%zR&{Oa|)ro7`i*Y5hqss=?tfIIS*^b5gmVF)M8JuqGY zLagbG3o`oplj}n$?;4o@Ya536P}FrP!qxA5X8-9LqC$Y;0&7OZ8+fs&lpV)?BhPBs zYQ>`)xru^{Q;~>%9i{5~yDnn4Q;ywPaRCT?EXQZDajniOX~x}lZA;x$(i`BD3T0fO z+B59d<9ySJz!mbW^D3cJDUSfzXLT#`Uxve;zsSu6p7zj=O!f985hAN^DLRhcCwWsr zCgW|s^+$;N;c&cV#-mI>@%3e-NmCd~^tS>fp_qY9-yJahrGDU_1$EXL+cC%Q0PlFm z#|psx=>7gLU`s7SuVKUqWrKto>k+@S_{Wbr8MGeAjNRWAC3g}P*dQsx4b|~xB_P?eHvM`_3 zUr@N_E~q1JTn{h|Oz58l%wH5E_cqOAAo*_mJT=cb|8h01?l1WNv2IZXU_*oSWGGMi z8ZGR`)5=D?p?y5`hbut<&IPXmEKq=ZrUYmZjkw$VATk>0Qc^~(>XC>jZD_4Js*G3> z;n>*o_=MZ=AiGMa{dK0R(H9k=%~rd!Cm?WbwznK~JE^H!(t|QTQ>#8r+WHlZ)z+by z)X-GLSas^$=!)*`0q@c1E310u5uGq(1!h5ZSFigwGScC#Jo zFv$yZsOda6j?{+gbs6Jk`6`l|O051OKDD?p~4YYKD1tm3AmkZ@l%3YQzWi>GV8 zg+2PEDR)g-8>3*S*m}aO-d3(|Yg_Uho9HUA`fwK+BxPg_dz6vEP}d}jH`$i_4n+)O zny3feTyLR#sPidRc5l6zEq$h9om>HHg%#mE5c;U{G+&)IH^V!41YxumRuT| zWvfwTTj0u6rSnvWusQ$F=;!K5SuCpm zy^DS8@D-QGG{@h^79h^x#BzB@%DIClW1M;=5GOvANc=bqOuiOQ@fXQn2KV>od_%?T zlC7jI*fgG8e`sU?%6c7#EB1D5;(>Z1XcE55Qin~B66mRF<)iqJCJFO zBALdZGny3v3O#V`8R+5*4cSK`A5gp+@e3$jyTRW-HbaRaEMhKpeMom@S$=gBb=5#U zM5Bm_kInJ^iSO4N$^_aXwhSi|Tu9ZT`jH7n5)1AjR#7gCY6l%R&WNX(!*jXqNQ=22 zhkz*N3z)K;Rjej85>%^4P;g~`WpMZODesf;&v+&kVw=)QTNuC7lD@`tc9%XPBpryq z@sQMr4{ng28JBpZ=J3aF&xma1)AS%7svGf|l;b0Lr=G;t^?o(d1jo=2^EeNp{RvG$ z3rx9T69t!#RZe4Mx8JX(Y0=g68uvU$_T(068C?qjMQhhkEDg~K*#65$TF9Rk&d&?| zSQ|&S>VCIzZbCq}RJ4!%pASmXZX;>g|EO1KIRD)e^MA}RqRz&K4yOO>FPN+W<)N~K z_BG?(zziikT1(nXLI7kB43JiNLi`mDB+v}_Aw`~;YU03zLT<0om_ilSy0~1dwn()X zv_u!c8eSlD9`qh0y;;%JtX8q)x74oceU+V_Dw$?LvhD4h>OAv0({{}N%!l`Vv<2}a zX$J*kylyE3tW}`1`LAO>%(`Pd47v`DUh1l287{wLU--nuOW7}eXG2Ij3?cPZ$6^@a zx~0I1!Rwij&|ZM#H_{tBgVC#$%UdKS?tdK{VD^Fej;*4d zbjUT*z>}&1*G$}w%ht_6eW)t;Rt6~dh>)Ja+>_7Yz-_Ku?hD6T>l)0zY54+ftDibEY~)63&En2sgDOXxjuF>m3rwK z_~wz|gf*rt0_qfsT+#c8foD|XRuj}KDe5Up%ScH}HvMees89fBD66@oLr`hYMon_q zDtOU{3=i)_yb1)C5Z8PbELdPFgc0GKJiJy^vjTaaK5leV3MdyyA6pj*rmemC;^`4J zS8yPFS07{uHy~U(byFEYY^XFBZ%}H|U*m?w*v}|=tI%j7N@H?TrwK@Dz_wzstDX4_ z`Rg$>oVR5N#3Y<~CMts&7Q*cu%w#jMfj)=I1{T0_s8@}LEj9~c5l1mhksrw*T2YMm z-DfPQO3SM7WF`hEj8ON#)q51z-@tMT&w@jn3K!8LTK-e=l+-Fbf#%n` zSCsb~cCjMTMK%quKZeDZu+?Z_XmTyS?WHuG- zEEZ)D&_r?H2k@MWVP3lN91k1vjGfk#@nuIs^pr-%i*v?{c(>!ubligIHSUwLe*sfB zJ-}+(k@}>j?*+{wYo9Z)Yxd#Tw+3^e_Irpap_n0*s!C0ytX${@bndM7k%$+oOKI`8 z5s^^%h|kU;2f1AJnfiPau$X;8X0(Yk>|w-HI_d;H68)1#d+HdL9+Uq1c zzsU6b<)dgZbjes`k09l9Y(~88K7L(yC`Oao`2_g4J60oZ)9B&v5wm}h4$BQ0vGa*> zE8EW=W>}lpzof8LEd-0@=Bs!%hCE7C%#q0>Rnw&uP$@d%h_R5yX(!d?L`l(CJlfWs zfFsFh_IIVrf#bD+t%KAt5gUr&7zD<^^Uljq;4La9NXW8fZ?@Pt!H>636*ER-Aqm@~ zISWTw6n8ToMy1l4^B5m$Wc^Ynl9yI9tNEj;qN}QInKN$L&``7m9*R$m;BwaW+pt|m zOn9h($3OOtk~uNku-pt%DS4I2ywpyGoV`xth27)P7bI6Ap%6@O;)h``%?%uAVNkdQ zaB$9|qEcVUmj@%M|0iQ9aOgDa&kjzK3gdB+Zd*|X!|q9?#9bfW0(XBPK@HdAi61OS z!m9zC7_k@u>S<-Tn8x!cY`c1@ye8=rm0SXtp`zt9z>#^C38qaWIHo0fxj)E~;b)WP_n>xEW#oNwfBttPu!y*88dP8#Zu zoRPER!W8W*AmW+AOphFkfu~X*>>sD;>M|>YB;FF}OdP%B=8YIMzRMZ+JolG<}g zH5hn^oEl70dG0yc-;?16skYXDpCVQTqh_tmZo{hF)aldA+642&%lf`+leGr7@>9=p zz~e(`-dzdK0s?; zdk(rlQ%oRunpTv^R#HR&w}0N|x1M2<<~w5%P7AoGe4#(c3jIhAjV%xOK2=yR~tp6Jl1P;6;F5rnz(b z>?o`dc|)8%#?|B6RUF=s$wwfKAKATfpS-1$&VjAMedTFC#ni&!_2vuHQuOE*L|HXq zM@?xvZT-7SId0 z4_t>52ALF0vy%3Z`g3{Ll~KE|)kZK~TEGuhLDEII*p;S)i&D^d6- zV-CDt3!Gk193Vb|Q?^H#DgF_QKd^@P_YE=6_}B+#>Gr-y!Z-Z=W^{i$_SMM>38_cKt2*;hrp3c#8$jR>@zF-)cL$S|QIC+*_s6 zw?B0Q5l*puL{@f<+o5u2?LIQEdi^aB_=@R##GZGY+wt{hgI^->238(Oy7LD(1n3i~ zBo)S>E{;{JvLM+G7JMy)!@~O{vkRzOkX_KKToXVGNKf*NSa1*4Q1)7j64PsXB$;x1 z=Y#l!haU_k`3_tOd-SvOD;v3(ML>{T$&6CUs%*p-VTjUiwn+9DY&majj!VyRW#iw>vTGL;K|R z!9b`?`2L^Y3MZ@F&2SI8ZL1#pddlTuq-Ypbo1@FwLlTMEw6PFd8Qz1IyEc`y%WW(z z8`(LCeoC^tQtnQ~V`FgU@T2jjAtx7-e?8GPFB?BNcj{yCwT*2k^$4{}trSwV!n59_ zQ0l(b)VTY|aeO#DV}ulYfhAU$Ev7C>%iXw>4CnX?vSzcvj64f{H;0+AeQCJUTk$2~ z;81TX#7eHi4JT1flq>%Ep2TE9W@|*m^T(rzAOhlM;MWeCo0yUbf`^pKLNEAipA)1y#1_0_Fe5*Et1O!Ubz|CY;!|ofF%( zZ6_xa+nLz5ZQHhO+qUojd~emQ>i7M$t84GCdo8(VXi1KV+g`)JMWt)`2z)f1h92&8F*}D(n`FMf0d*??t~ym zA<5oE^)8ae6ej5j-TEXuBBk2e#4U?o8xZ+2^UedZ{ei7Y+b< z#@PzoreE$3Ln*Uo+FNQVFls3_Ruir+$3z334>Joq9fW-4tBwDzG*GacJRXJ=H`gDw z49y0z(Uq{A4B}@l>ThjTR!1y76_(*xmUFMDw9sLt5?d36Dnw)#;0far`z*wFw;)ZM`glGGXH+~E$A*e4TbSe1Rew8k-t45h4>1;5eQ=cRn1 zm6Lyv?pO!eSGvL;6tfZl*PtD{4<`?O{H~QHb|oCEgPCkH$S<^E^o;Yv&4nmlU7>va;&5(F&6g@%~=d^D>WUVN+@ zhiQb>9%c2~X+%hD8Fk zRhDLn4O5gcauE)BSVvQ4iTb92`x&%W+tnPI(;~57UV`K3L{oPWP|^*T+ZJ-#N(GK7 zs1v;DEui2-V>pX^lP5GP`%@{DHg-O06l%{~P|idj4S&>{pf%6SMins{2)Be;dRlcW*;hr&67UM(!OLxFMEQ`y~FXke;5$~ zu<_a5i%0?RRX=by{n`P0L*AE81t9sT^%e&c$nu7d$O` z*y}>AJRM6DbUz+R^LIbCWO<*?64AriDaZK9RV@ZIz7AKw&Ch#L9Y}NPLvY{mu;ccp zKzG9)O)yy26ul`;r}XKtX95ZOKw}O!3SN~YdFI79o96IUfX1&($$*1brf{6dlX^nzwT3=C`PWn*FnpfJv;xSj#0j~yO zw>|LTR6S!R1)ScR=x5&Ip-EKEx=xzAuZZq$m()5=T)RALv{udmNWmPd%(Kp9&6#4^ z>H(f&`KENT$V6{l1o^ZWajkxLu%uIdGG9h-4Y$K`TNDS7)!CX%Y4YNX0?CII*i{IZ9N8qzc)ULD|HcvFVF@l$+8Q>MH)cZzg( z=jok*7@c&>%0y%VK$>#YxSNP)KCH) zYKcR&O7#0>Q&Kr)sxn)(s}~|spqH_`yR5rPs#lH6BJLkwQCl?8WTox+q~1y^@j`vB znW%6uq)l}dP(x)wY38L|$yQr;hkDl6%yFVTJiUpvse&1;X(}ozFdA(r$odJcDzK!X z+ga;iy;&AyZhqhlvoSH&!ul`L?PANcjg7Kw*@B5>bFe~D2s5*+h^%*Wl!sA`_2}Yk z!0)%-Aj=jqAIms6k3>B(%I^`FjT<3QQK2D$rKOaHP`W$BoXca4eg>*Y;**eme{Y=B)ywzZAO4%i748 zi;7tXsOMBt);P?I1QhXel_6A_f0$V5nkv#V3IWPsMsHebj>;*A*PF-J2NGGE5T9?A z)qcmx?eE3u!RNGUMOz>wkgnz3AOYUTmqu3-M z{d{WLQ`A$TxLyOdG0t8GCnu>0oh+ANnYE2&MVYPTRrpJwEa}GZ`rLA_rQzSowbACk zzp@t_sd^0L5}8m-;_;TN%_5kCBo8bp!>YmaDUE?6y+y4CRzTKf<0^;ht2k;(DNg4O5rL?UgUHI`-iP3dzMCitt%^_t*Qbrj}m@nRCdsw!X^@UPheV~(8GT5?{vf97#8 zE=g7fRuYl)LNgpznUOWC$iDqneX)&)S(iJVaIt1_nkuIi{JLc{*MTn{poYMCEUu8A z+ucfY9_O5FOf1Bir9^GA5Ze-8CkdF51uPn~>W;7Na<&H5_TZB|Az;cWEIG72XAd%O zU18jMNOv~`=jyXOdMoklW(G8tl6u}34^?E~FgCKYzUs&^5fmYga zL}M6|(D$*&NeK0YhZ)wzPJXRjb;VJ<(V5O>Sf)5c(`Gup9%eQJ?P}@OFlZMV(X34- z|JnMg$c!bADzcRpQh^M|L0%p!;P^h_RHUrbwDTK>f3DZzE%K8OIHYlGuiBH7Wt21g zU}wN_A6e&o+2Ai29Mv+@%d97EeqFLoerCo>Iur89Sy$VRNA)f)P`U3FJ+NK%*Lj$D z<(qkC52?5YEcla#VYIcjS^+ zxG9xXND^qgbr>X6xet|PrSOo?=suOxQ0ejg!$nzYsqMkdaP763*D|}}DQe5}6RWYc zIS0{~uUhkmW%QNzyVLExB$w)Lmk}Xn@(N=WoN1u%c zTIuB|KJPMIk2YzPSJ|g;l%_;Pf;3oJ$Jxq_%^-MI?JYnBHNge0XBKOFHJ<(RL{V+>OKREWcl?RDi#!>eL%!8SV%HC1VE%HQ= z0=j&Pojn|33|Dh;V_k@Yrfian%WtWEohRe7R;!vKuup&#A!)C$Haa_T2x0P&^;o*o z@k+)=O*uc&T(~n5)cH@spRzGQim}LJZ_O(-P*u2X!E&_k=7W$or61TRy_tPGkH2=< zkc3zdzl-oOe!gIXuUfO7oH@itFgQrig=^~vDuzm`t$aBibjD4i#2fUA;N;YN>%#11ea zwTXrpD(XC=){9(&S$YC;thRv#>7ot|32D ziMFX86SC5%%{F*o$+ctuWuvdINr10*KN?rliwxnyo-D7aFs{doD&H+COPTcY$zc2$ zqqL1aKPhGaXcu$H2V2W1^Gef_lqkx!TP3BZTDmJFvZIWK(PIsbi>UwG7uIrHY++-^ zIzD4dM!L`IDVB5>CmF&j1zIp%YezwY#3EvT81dp4SJMP~mn zX{)!Ql#!-4la9?4oB;eJip)W9-IdFEjdKY=crj{`?@;U*E3>`}qiCw)yM_Fm z3vq4SXp5$|-BZnJ7Ty?hZn+Iw?;5z;9;lGJg725>SSb4%Ex95dZ0u<4@a70b@P4J> zd)edHc?YC)=S75u3gx&UWK-x)G@QFwzPvYXMb34td-K`j#8q$A@b04Uit^`RQU~7^ zEmA<-7b!(P13eod!{pb6`4~kfcPChKo@-s0sl3@&fSVskInSldDS!{mK^gic?xruk zD@GwFQe*bV;i;zzylRFmHh`VeaUm9yk{^bfRETLT>ds*-fOzZ z*AbYcafR}C5D3!6C88i(+*}@9nT?ymX`j$`1P!cD7XpEq)MzSnH-$2Oqt*8jqAxG( zZVH5LX)25&4~ow-mQJlc0ei<~+bm30z2JCljN~xsUVMp9FK&-_7c)^O?vf85&sFV7jDr*^`pdU_3(P&|uVvXX_Mh5Py)lHRr z>3F6|w|q3}?;>I6oZl3Bv~OOcxY|dkkFuTKOXob((0_$X_bmGypuC{?I7t`r>b%ok zT;06hdvHSY5Yb-*3sNkx`LeMB0~4tDDwxbk`RZhkktMhWO} zmc$P`S6P!yR-&cFlc#e?{0x>@@!Qst*CXFw8Pmqj+#yTm;&g;&;ReOQ#cHQ8VHTuW zA)f?ERY1y)Y1LU-kmtPSO+I5JAIH#1A63gVviJ^4+uM9YW`PV^k%zIHwF*0bcOk#^ z?!;?~!m=Gyik!{!2-5y0GVpHSk8x58=Y3W(<}Pqmk4nQRx32Ae(tsX3srd^8>X8{^ z+G;cN=a>|BJkAStt{}&G&P*HwQq_4sQcV+%r!pD?X}cZK(*p$}ep5kXZ>}v@3LMIY z!;NQ%InL|Y6rO2_b+U^UA|6FpB>(+89jrr3RBpeha5};n?qK=Bi>!}w4|VQ)Wjjo> zbwj|(gCQDNT@B2lOCa`0_&lr3A`fY2K`aQ0KmXTBdaStK?**h>UJ`s`w)~1NRC-`u zyTcO`3m09;TAfZ6`r~EKSHPTetm{uVex6rJMxsUcAJG6wmlPfXZ*5E_A;MBLY(&F| zKwKfwaPHsqlh>%wbzJf>LBF9%S`n+J8YQSyM;mmZO>z?a7G0_BUj;+ljA2y0g%&Ns zg{&f|EzNeVJ=c`d2y?13+fgSb;U+tXHs=tP*e(gOz+!nqFZ9tcF!?atsKur?i@cjLaI_w?D z4BEZ}#v=9mzGTDj0($g@R^XF77E*>VMd>fjS27YC->})(YgO$nb$1&T}eGEdAH1sVt@t=~|E`u}M5H^C|5PS+Dai%P(y1O(kt zV{0w^>@kG^y;SYLSjhoGA2Ng^bASbWqVi4V2?;xGQiiTd(0COxMgo^Q0U;VD4@wIc z{|)-5m8dWB&1mQdpIUyf)0kcX6y5&0=hOSV(ZwH5=bcw(!{ zFTqKb#;iH0vzRI^VdgWeO_XyICFvDOd~{UEb8dq4Hy~Q9Zjn~NxNdPk0BBU*3oKx) zSup{(=>*J8v4h^EWpc}iY2ohVXb-4pf-;Ko1F3-o%41@Q zyw*z3sB=TzMn3SSBI+@R=#g?1PwljZrWsAb9q`^($YL`GrsaakOg49h>tgietAbkT zv4L!X=_-i80ma-X0e)-Jc`dSFU;%>=j<87-Sv|SaJz$2i{y4*AihV4-JiC3Yg~oLVHniC1>D4DJFXeru;kZzcVrNd-Drj1|e(l6~CJWj7t0G?v)RI3aV|fejUqCSg*d5KM*6;5q zkj~KeI^+=Af0Cdujzm96guVi?{E4yBk$mKbvHp`qJJeeqLFC%Tk!jFxh`^A9)cycO z?tD(;)l0iI+}l+h^vf#aPrbS$1UFT|>}r|V)r`ib0?LrS=00>QU2@VC|G}aa(q?=) zXR6d36dA~`Wu)e9rhX208e^+e8_K4kP^H61>2~Y373wP|47n81E31|NnizfhzgL?# zy+N8Q#Sc0=k*f~Lw=rTH{zq==jMr!~{9YFpstFM=s|2JbSwVsgmd6&^kv|)Cn5GrO zEE}+sO;i0s8&;VH84)PfBL%~3Gc54^YlU^wg>`asqec9C&ikUixKZqdXOX=Ooswi7 ziR#G}RZCU5NL@{ZSz-l zL~44<7;Mv^nWMFs`=_0-Bw6EVmgvyG?9vIdihVjwmF_*y`+R^lkYr=plr9;)U<|U( z@Au^<=h5)US7Td}&l+WT62)gNlfzG*bH*@ZayxW*D<4|bo7sftT! z>)E2V8}hR&&ph+Z7z#EYSkd)e5=>rDBTDYgR~W}EDt>y!G#P*AnO98abcXUtn|!oo zg>Sq<{!&h}(lZ(0VAWm?+}Oe0c%}T6I2KsmIy~aByXdy*2zKqBU@deQ!TgoNhluYz z>)IOZ`p^#XWw(+$b6xz`z^Z`(gC;t#Y86@9sO^*useLN&8kj8De@tlT7+X6Q|00t- zsXDH2ffxAHgvaYR(v~>f7CGG3-=8exm?@M%cauiiDR9`3JyoX>2!wT2V9BAAHxRDV z5>-7ndz84KiV$5@?qJ`bw0!F|LQGHNNlxV`lRU+!`ONoS8Jb?xNLkFXWHuSiPS7mF z)cTCQ^b?2r>7tyFzL@M||`Lu3|ywxh{Ia9_;6-)?5MBk)KdSbe7fw$~{#_lAI2>ZpD;eoc{^bO%Y zUBG}c!!_!*S`wbY%-on=v{X4*y;m!EH@#v zRWUU(Ce#k2?k_gop|32;)GyjNnFFd9odn>?yu**Okqj!_YlevyNX4D&SR<-zca9|6 z%MjITNV)?;x>$~GC>a-KnGQWr@W$nFY>vT`7s-tpY1Lq^HZV-eUxAV3G6!`Avp&7j z#97W^sZ@eR+?;mGc3k@pG}3aKxe*_<@k@2%z%T5`7X1j|^993%4=?(v?I5w10_$2!{HTpE z4DXJF^-TQ@i>Mkf+$xZ&{u@0m%lQ5bSJ~w6Er6++(d;SLD5@C?1>6%X-7hcz_9CU$3z8k zthBopb7}4;2W!cT!tG_pzQ7PdJ5Sfz2;KP=Q8FF{%d#Iyvm1`a!dXaH4e z%Ysu=ZzcdowwaZ>D|{a;X~6E`xI<~nS;`sm?w#sel92c2lk5wz5cR_F)ZmE3K6y0ZQ# zi^7wtMVEvF^o8KyG(DS8pfDLa4%dLm9M*WSe=!_dDjO=ZHKl1?o^5+_LUz)^KON31 zGUOMeu#b+|g%&9}NPCIjKOpHWv!cmC$9_<8ez@1GZhbQISYj}zd&YQBBQTc*N@rkE zD5gl3!3*)ytm&TRY#U*BHHE~WlDM6?EtN#%3E+Kq*n2PH{Ws39c(!q(-NHt0DYW;z zkM^B0e$o6SSFbd|+v%l&@jkd_x;UGg@6>~s8ZyGCK7JqkXJRu z4#`E+zjUSvd8QdYr~mj*gNS4XQM!oDZDNoj@+8Tl zjLM%ZbgGv;Gf9{)KrIrCR7ezKSS(y5$_$@pPGU;Jrn=kLj@*>IyT2Riq$bdxbQMt? zYzqN(lMYr7ZkoQE%|h9=i@&g!6IvteAYzwR938>{k zkv!o%J>f~=@Zk&Q01#H|M;2tJAf5mQI8KgIcRR=HH8L%Y_*D&Kq8qF1GH`iS>CipX zag!#EKV8S2x~p1Ig6F-tZ-`)T$Y5_sU~ee4R)sO=rKa9$gM4{qVLislem%?>M{g7k zUo9-P)@!Ut1`n?S=2rPj>U;%_dxVUC!iT?EqrS8!R=p?dK2nW6W!H2I)SgL_E^UHW z@;QRN4sXYfxcAslsdQyrvp5Vb7R>{v`2S?gj4^$SrhY;~onV*{{fPRWs8c%n7{`rC zpj5>5mzXdq(Zy``+g`(D);LwjSc}w4mb_rX0LRGmIOQbbf8s&TD}}sAa|V`B^wa^b zx?PH==K-k|1WMK4rw7>oe5#dTq)f@BOo<7%{zCr_!!1B%QGCx60>-w@2unB*i*A!) zO&nzvnh}b8_o~9R{DmN5MIl28XhuwEMozFHI`-_8IeMRZG6-`u~g$_27`X^fP54nO7F(xBYW1%2a z!+fSJ){5UJP(jgPvcYRm>36%f^-SbMapOc3og})CYIx{n2E9C0`M!etb`q`zAR%OhU?gD$LHSBS&P2j;gxydw#q6isW z5N7I@0SY6My5Z)V10Z6SqH(}9I6o1m9(jI6rD(Jhzdx7v$Vr%yNB=5@q|1b0e3;8B zX}XjdZRx_rz@we^++>}ywBjG;z{w5c)4Y!gFq(_G? z=BbNu?M8r93x@F~pNz`~;{aZ-jw|BBmLaXPxWYv-;*@SE>osxaUi2Q1EAB}LO6&X< zsCq|2d>>61C$k0BlQ9<9a(;?QllD0G#CeCT+D?^5R0*0c{Pmo;illR>K%oR9+<#UEDCE|Ao?Ud!$YE%D=>+Au zMDR`JMN3DMq;BdDIPP+JieAq%>d53YXDgt~&F(p|Hd_pW8<_{dQe-E{*fv)KiHM*@#eV z`@Z7YN9U2w^-S*H6B!H#@k*|m@-A@@vIxB?FI z%m6w17W_@K)hcf*2P|hiSlrllVP~*fR~_N2pR9(XvLEV}9Dg@^(huTgN8Hw)AoEAaqgb~e`$PM$3m$ZupooNT7fR&*gYCjIp%{|l(wYAEeD8hOF%2PpM9Q%}`32!l^yF;qe{tt9Ur^nr?#hCes8dn&fN*iStSd;H%Xd z@L5-AbQ{Yf*Jge7U_YCx?I~^6k2e8y+d}pDFyisNlrt&EzIzGIY zR)()Wjl=7kR6Nek?+%tG=)_Y>IWC%H8ekJREA!ve20Tj1FV?LQjkdYvGg%)?uC5_* z(!C!fe}{Na@Oe~EeCUQ;n_`sOitDCDG27^I!XD!ch;(iIyeO{I6OUudqZ@#Ls+DfTeR*4es03E7eT+yrAnPY;5~uh~);DfuCKciM7l9c4Jp37`W zJu^d9zg+n`{XDUQ{Ku^IB0FC#y%eu&$iY65WzuKg1Xw8tiz==9ClfuQs7}d^4qd|d zDK<RyqkKqQyXFQIee`-=)5+PccN# z+@!XJi1pPzFa?payJ{n(&XV<@e9=`CpNosvDb~?WZQT^&W8Ny`9(0*40FpqlL!D5r z^A!MmQ7_!u>Am?vH@p`R<@3wtgX{8UEA-|Pd%H|Mb=<|wK^b}5)Hr`IXq$;pXk0`OJ0#X-vG@66D@*aF z%^2Q^dZ6K#~INK)Jnx_CsGWzhVY&S5KV*+;Ne5j}a> z7(-uj?Oz5?|{2^^s>Vi+)1Afm+yjJQo-*) zNuWx$I20&FhG*$n+4t+enC(x^ z!=sXS>^yDXno0Z~J{Ey)J0dKCiV*Xg=kpR9Z_$3J zfczxs1y$Hp!sxh$E)3Rv4XSHKOrr83d!x|yg{Cw5RLthRE-}fxuW)_?w*Xx92>(QkA(Lpvp?P2CO;lS-+#_g zKT4d8erSij0cCI$+lUTQ6&OjRKRjcp+W9WsXA)^ykPtyD1U-uo!w9J{n zNI~G7Q*uWawLZGLK~Ol^)L+cv1aQ}h+Sq+KpZaj)`cU}$U=aHtAo~E`U%fF;5e!@T zBc*)74!#s+9xx1p`GeoSIpl6BYA5w0(Y~XNSs#G!>2$}VgDcdG>bL;S1}UH!NW&0M zpZ4DY`$Urf*?PlnCG@=2+T$O8xUccnafP_fO1COznrITLKK?`v#z+lDe+|ZX4MoXH zOwmeA*-A|L%2a{MQerik|4OXM7y9_M#IVknOYWW^K+Bg^?LCHht!}kHnw6Y;IdyHu zot%4EW3^5II7HiIjmoxWUnyYEUG6wJ?~6?2%|z5SX_RbOr$8G&5JbmkcNZs+(sa-2;O6UqqSKW>7;?yMnTc^Uz6|kR_3vYU|x8Qfbna zx^&kL;U01~B)@9D7D-|>#68PBMWuZ}S7hLB*&vIF26LoY*P=AU)I@LYsvS=L44)YM zVASW!p84&$`+OtT>q{W{?SuMGATZto8Ssg)Pe~o~!0#XSEzY>sGm~fs`!(rk(t!H= zH!dAJ1UPV!BYd7ODQ%l^UnJ>_cWlzBM#<Aokt^@sKG`Dctcx7+N`Y)ZeVut15E`K-$%-+r$CY_9%%uKrxE{zC4K&q(gXq#(`` z7&9e7kz+Gqd~@0dT&CL$9@i|Wp8%tfAL_neHYO(JnD1dfu7|s8u+7M(4Xm!HFoCSF ze10Cq!mM(S@#%lxZCF^s6z~LG`-|)LUeUT>$#V)5z*4lgm=D=5aW{vHWy?gOHhU{J&j5cX$px*E#mf-gBAW>FKX2PI`W|C9yMUB-AV^X zbT&gLOqc=*O=2RsMz6T)G5unzeHszm@kb?1ur9%M!TkfDr0p_6sY?aoJW zOMwcmN73bjGUV4X3%F&Q_j6UicS9Hey-E1@6KM?U+ZW!eKZpGK3kMX^UUFAh2k-R{ zJ2>C)l%ISZ&8;gB?(1ayzja$C$DXmtukbV#r4wL;eTL3|o?XG3lru4I_k9@AuE@&a zJzD#6osGs_Oip$O5X&eFg?`>(t%luAQXL$+zb8i$?5T|sE7rt^=u!8V5Gm=UgY(vG ze)JT%l|4b95Gc~6mjY-sCgmtzZ$@Tz@SS~a$7j~(#?guv(Tb(RxAT;L$>#9C|AaH9 z>j|bRDU{=7`QSS=IK$+db{@F?^I`xdR($?bDJ%7Xks=uRB#SZrO_z)zhJIBfN+bCc zIEqZII5Xr~=R_dqRemW@)b;s`U^#-T*>LuNW9-tA>7~vwN4fPdH~zBmvaIwA%DYmz z!U>pUQ#Ef~@hH~iW#Rzr$9jrh4No&w1c0wDyowWZR%c4x3ryEGDq>YVitrX*@LlHv zR);v1l+?;2+g*Bbo@Vbiwa>OM$;=%oc-L(-!dKMJ8dTp4zL^~4jK}kRu!}o0eMoQl zbc}keJ{MIX^8Ge;Bi?c6de4uNx~F{npS@JN{Z1_{AXU@I4-&`^QZzOtg_YHZNz-pj z3Vx?yWVE_D{(JXLy-g9{8YseR8#j^s?`hU#7tn#sE=N2MG8naHI`=Ej9rj1UMuxH^ zUc^l#ou)vqxeMM0tbJGf-)kS{<)-tgNLnr|Vs@Ve1Ga)2M1vay9M72B2*lbTN*`~S zfu?)7{DZU7H~72e@cP+t>q((UcmY8Qz}~L?-9tB-N0S7OtenCi~!f&{@tur z(pM54{7y)Ah?}AA-7h!VR!Dv*zDSIKm|b?3&y7BBH~!UVgwm;!zLHz_+mTn-TTL%4 zFMNGSUvk_&jQ<2*WJoaGv{C^*hyejLp;F}p1plF4;lJf*p}qxaVYZbvg!1p~RflaYtdg*laCGa)W1~C~j(?J!c$W-YnCgG8yrg_IHP6yVIM^fF@3dtVj2^~+_frD+dc3it-^V``XdaFB*O+71ihPWb&&#R{GBG>N>8LX zf7v`!4sI1=n_}5v1NY=b(Tm>i`z-->F@>tQzf-(v)|0@KaOR~s|D}DaGOVszp-d9i z0)9E<6R9aosrEi5XGG5#6n>S8Lbye-?*55PX1QesijMbD(TQb}a+_;j0iBK562Zb?O7k#G+Tp1h7dgslkwS)2GP zZ_*7&iDu7Pibq6hjz@E&KK)ttM|I*a z!nkinYN4Fn(%GHR!=8iGS@Tr1cZ%Z>zLEUd9$DE?B3jinNnXu3eLtdop*B)p=%RgM z(<_Wrm?Y&TAya{p2G1>>j3AgjIPpD%5k$EE0{G2=dJilEXoG)gw5_W$=&;ITAm&{4 z`FKs7=Xmr}j(TJjy%-rGj?>D1-?L87%%DJ+Za+=aqkEoyq|sQ&%l;(0VDUaY`~VF% zT92R+LkTzkA!m42Ni1qHDJ7#u(vHFf#Y}10%4Mpnvx@0O&FF=-iRW7+ZgyWavf2<8 z3dlH3yFe-)gc%~AY0;S5J4&dT7D6LkOPo-SSmYGRqG@7>wy;s?Ac@Y0-;+EeZ-+1R z{Y@+$c#aYyck3NFEWR<+nqrzB9l%uD*N>X`A4hklqsSBCF|IOSnaTyo$A z`S~Ms=tB|HCo=KE9`+BvU@Cu5`0WCEv-wWA)4Y>WYqZd#Vl~OcbA>DqP3#xG68E{o z)GI<(chKTmq;`XO#Sl@O{BK+p^9ozm88vyz<(9rQ7QSl1@0MB)9sjIb3~Bz&=*eu8 zyYuqHE@V>rqypjSWR)Y!wR$CaUPFSv6h3!y{ZoI)E<4d$?HUedtA%sy(MbgvC&zik zjK#H5YDVk`)a$&Px~Bga#zSEQF+>M_764+nFl<~1@_jqtzchvH7{Rh(m2u(k`us~v z+#sWlYSLzA>gvGuboLkT*Fe_!U^e@pzC z5hHfvRQk6g4t)pl)s4aUjK;3akV?eN;=*b}ZiSzSGz$Qlc`1lhQ0zlLK`%S#&{p@A zkd8(ukW?oDEOf()_PO53r=2w@t4m7gJ0lAtJvm71W?A+EP=#^Q=J-Q#3c(}$h4;mh z5G~QzshIgPvh5U{{!Uasg-o?ez z8;pH9OgOTBFga7SmfYj%j4G6_H&klXmJZM#y>Oq7%imS{^Tb`Kx{k~6nTWFXbuxN* zR67;Av0voVbd8G`?h}GaAWl1-cE5e|J9EQsm$Ie#totC2p@CXs3HSK=cgQ8 zZX%2nr#M;dVV3UKDm{$$s*XFL50>0%)Y~~!=A(mgDBvYo=E(z-0BIl1uKVo$q5t=^GeNm7V$+hD=t zXl6+q$lgV(n+NNJWpsimby}SooOpa5(KnLnH>qvZvky?;?$J4=L3Dk2rW|dNMq^g**7HyvP*eIEpzD2FOTx-4B9t~>#cQ!v;RG~b&Zs} z9$$8ok1>f`Tt`r<$OV76bS zNN1wU@&b>hEy0Y7x>7U*PtAFx5`T2zOs-#p!fpDBJhZkCpOm~oNLLUe7X-Y*NFh?623Y)l3-R|k)tw~(g@(v& z%taMPgY6&mcaQ;KMy7!aGt}gQl%T>2>-O1YYB7LVgOk|9f9WYGy!}L|eMwvjW!Idq zMcym}IdkZ#QsZwbJoc-rRT@~uSz(fWLoByV%a7sFMBtCsN?w;Q=WEJ2il*u8!07_6 z;3gyi@)<-=jfP@e6x-AsDAoQ1y~=iM{@^FMwYxf`(9Qsi4~&JoAkv8zy1FJ< zoGMfnv8!gCoeC2Fjixp!b#JbuYH@3VQNYeo2i!SAj0=f%{$%?l}JT>Y*eso!D^OQ zfZk;tcy7+LQtOK-JOIQ+_gE={)|5fGMtGu@8ZUhp1FXBR8t5^Wxxp@U{Y}5Jb7n+# zD6Y{uiljDO!N68dK)%BN`N#_NOhxQ^iwoHa!&eGH8$!eEQbzhf`oCoSX{Nd&m_I|w z24aPyPv}HCiQ~K&8EMTVgfR}|f%qDN`v(n7CJBtFb8}}}Aa>R7oTDNf>VjI0Gj{h& zife#gzIBUa`j`+WBO_7#SFRbMkPpcAV)RH+;)MG|389z3Y#9s@4R|^kmT5|rqILUY zbhopU$8z0M$sYdGR=D{aP3_(MoQ8^VWhUwIk7j=Q8B0{ zx_5NF5U0H-Of@&qVbtx=upsum)qc8EIn|u-YvRuLVL?`}aIS7Ru7h8bm zF{759GCbxx{G5*3JOF=Qb{E{Y4i;#Itk{UyQV_Yb5i`WS(&fFlvR@lZH@rM9J#WuK z#P^kH@)pESD=D1V5V>%|5mUZp} zcHV=y(229q37pW0?EZrGUC~>zV%!`Y$Q(5L7V7{8Lqg-OlIu6y-&vq87`i4D%7C zg3WbsSCnk2d#~fvBrpxTIK(KbA}CFER8=(HcDo)qK9)p_ta0~ryHiR==!ca?Jz=E4 zigDAj4&^cKPcJkWyUDUW1JQ{B&ot#<0ei91vum#It@?qt<7Z5Bj`Zl_uoS7j?;PUG z?7_gm#ScQ$1?f6f;s~d2sRdZp-*7&FX=lwxVh)mpR!_>nYFSfj!Cj zd$4&b%nuM4sNgg>cmSKMViq2SCY9Bjd4Q- zxOklQmsvyO6%XK-59pBy=n)C{!3`1x6tteA!60|Zl6q9MczKC5`-!miyZ7ldxOAcd zNh|?VXj47yZdCUrQZf3YK6oOLYLNN(%KDJ@*Z*=5eu>f_2=m>O0PbPPhLU4CFmqta zq`A&rF#V{L&WAC$T^*7aBpTOCrHXsd|5HmLS9``2p**9(cBH0{PF>)gX30i6Xup9Y zdn`xOsLsgAHyn&n>hZAwQ%dHIB~R;6aqIMMhoumso&>3vF}jSt7#Y}p9n~pCM#J?N zYG4(Qj4Ptx_^Z}IXQJZ-6AT6)9Ir}5DBv@@zofpVX+iRkM*>Vch9cG)8+Li9%~{hO zp=n@N3`y2;RYq5_=u7X` zESQv8Ap^?1ToPX63hQB&2WLz_x#H1}028I%(85Ci6Z&I~^kqH85L6$aN6bP}R${GO z($$y^bjty?BYzF8`zxfN(MiG~J>i%xnEa*Dt5FIuatCbP>d`4u$2@To^25ds+4;r} z64+o(qKc0-Jt)3fhC#!;DS!M<9dl2XSw=3{f;O}7v%(9NgVs(!p5Fz z)qf*~$(QkyZiCl;ye@#ux(~$2tr)vY!N(}xz`VK;M*neRBTq%VjS#H5FLV&IG_Xk} zFjRy8;p`oQGzq?S-?nY{v~7FZwrv}4+qTVV+qR8q+wZiEX-(sHoE<05{qGNF-?$N3 zQ5E$qBXX^*de+L{Q}qBkgFK zA?+P+8vgbiX#YN^@$A zNuB`8>^peliXRxU5SQ5q0r&uA>;idL4H@@N*!^zhh_a6Ha_9V_tt$+eQ{{i0uNFLfKzc<>EgO zUC%a()=w(pKH#&~Gq^dP4B1Ee#9c2@I7fqs#~>MFY}fJH58687x6b@EbKi}&!vvNs z9JeDZfh7FI2~yuZ@WN%x685I37KiOF_!kj4^!`-H&n-q(FTK2r4{U$`zJm}^f!@Wq zkX&NdPd%5wH)!@i0Y#mWql9E^&w`*w3QAhpO)EY1;}5VLBe`Zzmz|Etq$cVfLI3W` z@YUfO%3Z=IK`ggN*bP5pIL>0ZK3N~_2}C9Y^9kbhy=a93fl3$!fo45$y@%)vT!OIR zK-I)}#dbMFG7K8yM^wkk$^-icpG0DmqMpXLswVtl55t^1Y{~|EHHxEg0@X3D1XYh8 z$wbu|vr?yQs^^`3@36nMc3v7~M~h%7Qs<=yb6rdF-}N&JWOt$@J{5l4NNaYXyX!7< zNNUbfl@}|#{y5)deCX+#tN$UH_ik8^U&LhT`6ya7M^P2+{W6BL|5Jo2!G^e+ioo=W zmCoN@L=ovsX{>oZreh63)0cttZZ>lCH`SbeWb%vnDSAH+_+iE`c7GnI@%oYZ7j+z> zemu$1`oW5qRvhAf&~KRTVaE&7Ov25G%9}pX7wS2%dmgVp2IHP67rP&uYvg7asOHc6 z`6E9@D70Xdcx-z4n(NN}p?0tE7B=raC>~#layRL_c$Q@AquC?bWHst?Cs;}5$k;>s zS;Ie3eaLh!H@P(Q(xHK-2m`En#L#0xQZXbPKY+UU+sd2W1R#QS}c=0_vU&dYT( zYVK{*4{J7|j=YD;kC!#_J;w=Jq(Tp{)13J(?&62WY_N#ve(7TOnEsgGi95cF%f~4^ z3x@TqveJU_1az`U1$ji<@%XVf@(=Vb^Xbhv(&Q*ok3YzyNb{vgvQDG?qYQ9rG5BoWSs)x@wbt8aqgRsOED39t^2x=z8&8GxNE-;LE;brEm81rEZvi%ErS? z3Alf=@QWhM>=;yX69e4h&_| zP1ES1m)`ye(Gos~bqc=rPGQ&msN7`_>3@FY%4XZ|~m%C)*T$`{gNPgyCjR+m^D0E~|@n?X)via~T zj`uU?*8?GAvClig?nnulEZ(c*GfrQ)hzzQL8e{gn24kL`@d1`SBI9(p^^12lW414@ z3;}gZcf_$Eb=F^P3R0f7c^l3~8>gXteF#5QYS~YaVIFc7r zIAdt~xYJryG(dK9{-FxYd<#X{W-gq2$ajV~VM9OJiT2f)K*3PsmBwo^*6lnyBuO6z ze0w5%Z3qztf5qN*^R(an{0+3riztt)FB)W-fQw=LA-3X!>-elfGycV$#z;N(u%5y6 zO^~zt$2wtVh~8~%xumkpU2H4s8pjFd2-xF5`94c^Q(4m=O6`klQj2(odF`VY^+@#3 zugJpGC~gy5`>@`4;KC*_u5FdDFZiM`WNfjb!TI4jhJc9+M+uyK<27%A>5Co`6~d$g z4hX+b2}dV!BV3WfeT_9Qkro|AQ+wWP3`t5RLJz>Nz93S#vb3JmQlp9PTx>!aIxkHw z8D6I5b+Wsb z6g=d!q$;6}Jm!l>3E79>Vb5W-Lyvy%rQ3BaI4DLW*++C zHI8?$wqV+3w5yHQtZO1;M_6U$MEy*Sxt%{4h|z5Q(q-~~3sv;9Z-V3-0qkv3;f8T1 z&O^W$)!M|X&Z@!Hi09(-cfr*@W}c)R(|8lU5-ER^?6%M!2~hyg>kwbqAb;<+{oOq} ziNy*9ozsic8%(f-w^dsX{x?6!;AwWO43b$z9o zAFbRXHP?bJKXRlC)$RydNt8Q7SHQWNBe!J}B^vs|6OCg*i(C2*>F8fq%21FaQ_h=H zQ|popO26-o?S5dZFW-pH@WQbZ|4`DDQ-r;gHrGh)(?nTsF6S7TzCOYJgc}@`A)|~f z6@ZZgR-)p?3?Ih)Ff*Mjeme=bF;r;VywsFBmLeNkQa$x5OZ^OmQp3uX)EdAsVk)4) z--&B%QvUpzT8>1`AcqXp|a@18lT6mtvVDP<9#ekx`IDU20NEw zY1*_3*DhWwCbAr%!NE!)ox!MW8HTRL-`W#i8s>a)x+}G9Gu;xVbB%6}XGXaycd{Mc zqG3Qz!WPtUk8S>vp)rV>QaL;Qr{FE5+_WusQEsfMC`CWJ8Tc}TUqY|LRZh$Gpro$I zPgFLOFjX3WgBv?XatjN)h!))(y1^k{6~Ah4Ujl1Y($FPd@p2gzhrMJ4Z>o7W5pX5x5My{uGvv7p7Jw`yM<>{>O^Ckox-2y?TfZAK_nsbt;ncd9O&k$6*Q9#=Xh?X6PxkQL7=n_)|R zodT2BwxWinjbZ=p@HAb_iybYJ6id15V;KN+E2eglIlR#}x&wvfeX$c&7a^n_P?NW6VtzMQ3NZ=0!{>$QH9lnZ; z@Zlw^g{}4p0Yz@G^ORW4;=z?P^Au2PD#0`)*0mfEtude$t6gv+J-CLY;zRVz+_1pX zB?^Y(CkT85bo|oPn33V%3Fvqd4%adz4;Nil(7kD$8 z=#PlQ9VhTP(9+vhSY+J_D#Tj&c9R+SNZlG-NpbQWAJZ9Q*!ZN9M%P>smUqxRF{Mo?6(%jrU2ewEQ7Z@qpHQfu>TK zsnwZJ&Phk~y9aRE<*?6|R-(}nQxfl_hirasxo$Hl&I;q9mh04RPx-+stc$IEx zIyK4KrC-A=WQrdm|L9{Uwqw8=A4SxAa5_&+Q#leXS;3ZsFrE^njyg9v;-@afk7OPM z*ZUVS&h`Zx5JQFYSo7LB6m2fe=Tk&Ab<-Ete`zT*$7MVSlCV3D(O65jIP1t=;5lqw z8nNrH0o@M);8jLT_dGue^TMrdB(lNPjQ4$UY4F{aEbV+FQSD#6KQBnaLX!FeT%jRF zgSbTI8k_}DLN-0X>cB*KL4JaJk2u}he?stsT<|bkK#%NWiy=~c)YopwJMC_^f|PlI z6ak|7yTSA*9)6$^C%*g|i69rGze9~mknxo}1fmrrzLboVlM6E3;YR(I@l`l{Kr>8y zDH_Qj@1wuNjH;LMl|Q^d+e>^Y8)+x+W4I%Xx{>i!Jp6|yl=xCOl0fcHe}^7bAoDIq zDli1On4=@hQ+Xm#5r>WEXb4u8NLw)B?6rT^2PBGWY_^p&y@DVs2g>eaO5ZZ*~PDL@P9h2 zxQ)o@J`O2=%~;W5gi$GhnUY`2f=+hCMPBsrXslF*>n_pK%X{xk{mAT+LZ=^zT+5ew ztiPuH3ZUjL!g2Iup&lU;q14R=SkC+sZ_c4ZTGQyS{0SsY$x1_j;+EX6`XpD1Xg(-L zMDm`Q$k?_Z=B?Vc z295i{<^JU{uli%lweBH06rHT!U@ONKWsMC<(GP#n5D{AJi!Ed+^j(^HN^(cZ;Vun>cRn%AkMT3@ zz8KNF!KdcKmcnM$a!HQohNJyjPF`}a&YY5?e26L0U2;+rC*^V}-&VR9|W zcwL-s5X@wEzYxqN$UZW|;ptRYvvVkOv@s{fuk#sn=$_;7!yQQody4Kp*LSFSxHWm==4A3U$kxzFa zHl^?vpj|naa<*{ygWr=FDOc1MV5k5syFf;$CIg*4ohw4*{*7f~nAS@RQI!`VKPm_Tl5!ab=s=lgYo>ovi`=nskSdd)(2dDsVyy zB;F0ipd`#u8`#lnxZIk{F$6y8Hpzc{;~~R z%@6I6<3ROnC`l_`H!H6OgK6vw0fPGpsxMeS9>UTzw^=XiBP3p}>Jb*}2(pSh+glX8 zg-tel{861de!5Vy`3O4dR?}aon#uWyG6zaEWR)_n)sp>kUu5J5u0x9QwcYNHpgy1O zYYu-^NbRmw+osX$9C($xf0?X2l7ce7a(XCcvB&Y0D6KrwY7XI8cwLK}3dL(_CHm#v%G zbS)_LF?(Df&nJpw?uTZt#zAW1m~yq(10$lrg(68h+u;9fR;lQYwXL`MOmYM0xUE^l z?ek*BH`;@h&sBEB=jO<;6I|`WdQ>uY{Qev+22r|;3XbX{R~b& zU{}d(a$F(iI8I=59T`zN=J}QONnINU zK4vJukXezjI+h<{^ei;s^&Gq*S2H7EYK}563KI$>L+NJHz%FLIgZ$ZkGz{{q8Om`mj(tCCFhnPe{iv`$@Jw?c(MJx;m6ZcYWJ*MLyLRjh z7O;doeiQoc&uvUKALM+fkZG2`jNHEiOO?})?iu~+6I7mE4$Hs8FS<`W!v>je{;9mb zaa{0rkelaJ_i7n*k`;jJ+2;j%fE9f!GW6)zgx;2k4f{HJYzS#!@+rSxdaMz&H8Txi zunT?S5M=G=w2QUgk36>rR_fPa4v+CXNTK_y0lCdSs7J8Fci>@fmM-)t?HKb|{ln?6 zLdRIoYL7zfr*QF=$)jTOHA?ZttYBe(3ilUUF1}TZY^+0xazD<;zqdzOP%4m{AegIQ z^g@`q;)he4P2zSDo{!sXaUln+dF1HQM~lkR>B^wGsue9{NfR92Mr`j}_Vv(=0az)T zQJ(`lUsT2c#RC=buYL5`_h zD5>>I?L3VWoS@_DRSh%8!;o!QdN#5~wO49(4f?Uw_I$TeTZHQlKCs1Yzgg-?iHh+& zlX>wJHK`7HY#<$!vG+MwV%92b8x^kxa+b+=3-cqHDl8B1&&6MYyfOU?cLVn-J*cDK zGFc`4)U|8;OO`A4Xc67zwQZR+HZN0BD|%HnjD)m!1`Q;&dFAY0hyS~JHvwMr(hmj# zLI4ES%B8=-|p^XY63fdzl=fwDy`R$nZCtZl80+q7G6*q zwLB7r@9_zZ{`?85Ip%tUV9H0x&Un1-dM$9mx92spW>_EyuH4xIv^mwZ?F#Sa=!)zw z>ltM60ar)&f#bMUA4)5+woB!^b`od~@vI4LuxEhnH~R)(BL^&%3Yx`P> z7gN7x%*yJ#8H_rH;M$xeHi=#VjwNW4o)H+0B0HpKLH+fcb>Rk`F}V!)TxlSsEDKxr zvtA`cSx)@YQcN-O1LR}-Cqar*BIw_&8l3P7qpI}BT}6if(~%t%u5CB`b~Q6?p-t{?0<7)(yA zqsWmNQ*4CfyO1<0tTm*@G5NY6IfL4{DL1&e6r`N<40G^sx{Xgv}U zfR2C#4KQCwO=tN&x=?TZ#r&a`gsMfF-DEHhgbp&$=KK)kiNpki_=u2;q(R6kA<7WV zNK3g@ReC_;`42(~Pcqao{`xv^nWlW!Ggw~B)10)VbI1QQ-7-wFh7Cgn0r^P|0>b@2 zg@d@Ko4JFTxtYAVtE;i)e+Gq)kMHtI+E@MzkSpswklZW~6cx;5Xl8`kWIpgm=nr8u zB3QB8pcJ#@SV}fyi=qmtT3N$xH{HEM^nw;lhPG^@yC9~9b^GqNt%&FZ_g3Al6?>2F z9e0n?J)eO7S97%RHR4X!n~xozxz0V;Yo5L7h>!xm8%U6qhpA*o#6gJXyqoL@>sFz z)lq0FEvi`E5$Urg`%8J&aQU+z>mcARpz1XMynx0B86Ql@;s6Dj)Sm_=!*KhMWu)2y zf#Y_;jz%rc@LSnoi7`u!RhBz2!CoMz$*KT!&pJq1iYWmrs5q_Q-S0VE#X+ZYPE*-w zesG?SD2t~{U8x`)4b$^iK8B0FQnMHzLeM9Q$dKvwwAMyx@FVNblochqEJX)1=0$Wl zTcs_eDgDkzmZu`Xv?U?B_u(+g)1vQ(l2?g7+Zx<9U@|^)6IXF0`^{&|q%z$~S5YpH zY(v4WNG#ISXEEM_XT45+yv1*qXvf28_Jfi8YTX3`N=9lHwsN|;vBt$h&?9@H zuP@)05ZM!lp%Nhg$p4pebGuUUa=k{_S&6!_k1@VV#o`yQoRZ=@16)}}) zmRxmPHC1l3n;tea;F99?k4$bjfbt(Y;oQ*A_?ECrwa3jP1dM42#_7gD+ZY^?yS}bZ zH_8pVOfNfR^eFLr(y6oA;3xm`Izz(Yyc znU+OV+)~F>IGJL}EmLbl)lJmjF|;fw_}w9~%k0ZJ*!WcOHAXqW-xGR#OhUmYKG`K1 zQzC>kiGDJ@JZr0I)WhD!xQ~VW$H<)4qN^z_K8ji@`pGuBh;s0MWJ0A~oeOJ(@*cWt zztwq~gGf~y-2xJZ%4}hBmLBxCeLp>@ih9qZ@7FOL+$6Se`Q+e|OuH91`$u$YN8Fg{ zaY!q*T1-chesiC5OaTFaAB6%(JU%rLrq(rk%S0E=z+rUR(qx)CDm&m?Y9_^Ze=a0d zslZ+WR?a{bqJ)P~SlBph(H893GTsw47Ey zlQ9Lp4HqM53@2bW^=0txowGnr~d)Hm5qnV`u`o^)q#EkllFOyjXqM@~L| zmhyTWJe;1RR5%^iC5dLbRGInWPgYV?1m+B~YzhsXSt(7mSu4#fKco*scnynrZ3~$SB2vm|@lq<|8Rw)OP8B33W|vDOi?U^KrFE}QCXuLjMA$3yX>*mU)sGt{w&_DHOSKG>2v8)d{ODe@HE7xd zy+SrXsko786r;Msb{e9MUaIseKvMOaoHd!1jje2+uBla-0O)SIHdC<(JybM#ef6>) zl}_xlg0^=n2d<$8RZ4EPYd|6sj+l-vF;x1GD$)YZ;|TIr36dZy9Flo=l>6UUC+$#g zJ&qcBKo({t(|nzCbm&MkFZKwg^u7PkYh%*rrZ9H6UB4yWfJf|MCge8r>y4k6p8ji) z_fGaHBSsXJ9m2ya;x;ACs?;2D9l@W{$Sa6CHm@kL4DTDIq{Q&Qg9OK%Gzr}_=v zX`x){S&x?e^-y74PYpI2l3>)Rjeaj&Ug7v;!oX)EEHu~6Qt-R?>U`C_rg_yIzVZmn z-*{K;Xe_o|w;PwxnpXtcHV>?UygZcU!mTn*a8?z6S(Wl;O9z-^KyVXn84ohebLA}S zZpuFFIMv{0sK^gQ7)~4SuX#G`+(Z%h0hgAsY_0ikv9T~B$-A#i7f366BrxqQUe|F~ z!YZdN=pE`ZGdK$Jo*4#v|^t$dmjLZ`Mz?QBTr9?$|~_#eT}KU$HCzqe#sP;#hHxi&JsHL88DtLxD!fxP_24(GvF z)#H6Xt)^coo#3DJ`1dYov7ZnBlsyz%`fFC5<=|_6{dI<*6Dy!jCZwH){D~{ z4~@qbd8qSjkXqx4Sk$sQT-n%apc#kyi115}!BdJ7s@I$SpR-@4kZpG$+^4+Cm&AB~ zR-w~8x*K}K&kF_LmK78ZmPluBQ^a0kmEpUPOeNKC;Ju+xpwTZU5Om!ufXYS2W>HPi z;RI4>_>)`}0~}-wl(S5&(5Xk({T`$ZqO z(0)NfM#>MXA{$;WS4#6-k@JhiJPjDf;TLB$MlM0A3(_ z8RO1M?m)!dhqWWGcO`?t1i*~o$h0%vZizg;XO_o4hd~BnPkzYqKQEoLwe)wwdMQ-% z%=M{G(oVv(md}`5)o}vfsJoluvW=JM-D&RM224*i7aUpFUq0{PNjbtkZH*^G^qr7~ zqeAy0b16(f+ZSHPNz%@!$lW0yb*6%1bNt9Ul(nrZ+m28)H`dJLjq^?Jzkli zF3}U`mF^TOCF`R)^z_#QWitmM5lTbbwiz!1Yy#2aavp15&Ewt?6^iVC3R;VX@nlho zBD#x$|8nII=1p%qJi?F%fSaW*3zyvhN01Zd+T3Pnj;$5$9%NTM^{$v(Cca8moN)>F z%iW`O)tH6H4tyes3KA&bNQCmCziWN$X%}yPj;(#kxAIhW# zu^zU@2k7#OC-|;_Ru3WOYX0`?;RHDKF|w*xVfR=wx@#>@fA-cOtJw1S&A3%w>p4C4i23Kw~*pNRWhy57livy?nV-vkFmXj{IRB>8A9Ne^L%_8QCw|TO?7Qj^}5cd0C zq9i8(6zG5L2`;~GjKV#zg_lib0`JiI!)|VMgWgUUw*t!7g}WHW1FCd^l=q_kx+#AX zOc3E;Pnvi{YiDt%UOhsxx6X}s^LtiYwY&reI@$_%gPM4)l)`zbi&*4*WuN}DdP8S4SD}M z+=9WudXPE!#l0hOCx<^Oh(_a)Hce{8pxcXf+vTxOYNA`Zk#3^u5EDeRi3yuH&weec zTFZ30mB6BoReVn)(TZ-a+Z$007B23wjrEpCuEZA6B!y3T8)|4N-`s z6TTfJ(}~`E#3*s=?lvJHHPJhg(G#lv%3I_T!XK&o$9S76VV}ecLvis-ak71aH-Esu zEBVrd%OIt^MTn6i_!;%gvT`8;(hQb18!@a3SR4|cfRrp<@g@|c+?~O4X`=BJ{*;qr zcc#o=?x!{>SKo7VG<7oBQ1i!!PqX?`{VKa&yTJ!p1L8_ck4LD8HzmtSQ{IATGW<0p z0vS=cHHy~Fj0x@!&(J-X>|zW;w_k}L(^>IM+X$b9=J(htR1c)>sSur(q`Dy!cXqv| z=&{S`SohD(GNxrxJqu9xoS=ByA%i}P=W?NqKRab>#Y&4c9ISSa+_jB3?S6yWdKB8< zjkgwd9ANA2FoCAjdaj=;S_@Mj#f**F0ac7Ee0~8Fq%(0;**Xr#bQSD(`wNoYUi|GS z_1F}+z!Heno7Q-ux;IY!&y0^0Za~iQ^!h<8Z16vounn-tK7Dy`bn5I99JA3&T5}=43>NgrG^qCluF|qjSc4 zeALr3`AESbPo0nU=V_=VgY>*6dn-je(&i2CuHV{I-Fa_Wh|1q5HZgV5k1z$w^RuTi zc^S**M56hUmY*NGjaUC#^@nj1`b2|0RvzT^l?W`4NgsxWJV85%IOZdxU2q$omN|H4X>IQuYf*6;4hK zD^{f9*LtA=Fq1amr%FA2B=?i}t>Q}|WwOxXqW?SBe@Z)+DUpgr-;&PR_w|4CQ~zH| z=YI*D62_)(jxJvRrE>z}S>T3#qKJQ4$;GC5!nHafCklo^(7OaXYnu#FepibgZLo+2 zM5DqnTkf!jPgovKg!0?@K*HFClZ|Ag=*T+1`?HL@>G1@co3_=fFbqA^pAsHbbk(_M zSIw#eNA$$PYGRq`^lw@xZEay<0$o=R-vMkj=&N&@(Frxk64q;Nb$nrxLc#^`L+@Lr z?T)eOnLlxiQN%-8iUy7E^T|e-{&T*61h^79z(GKIzm;9V|4GXF_S6yqSlgMIyO95% zM-_A9?-&0y`#g1hM|^P%fo6m8jWbSSd8?q!j?$o);t>WEy+xF4Ej1U6Ry1K@d&8zi zuDiCUy4LRaMM0%I6t$qAKZaygY2jdqtSD$X>L66SP9kpEP@d!4+tSKmWcfUf=Xx#Y z1YA8np8Es%!IgeW4~=MpN8FZ`95CefGO)yXpi#>p?9(&N-Q6IEYv-P1&5OUxIQE)8s7CQTd||j=*9xLwC09B*Hx{WZHKI z1$uVPO3MXLp`r;ar$+Bd$A7f%v;kyTpi6bFR(^T}M}<;?*@iSGH)-Zng z#)<%1j_CqqK9^K2=@YCKz7FFEip@eg!kN@*a({P7s){suZ%~u@4ufoKxx7nM4X|bY z{Q}|NIAhiyV6zr9GGuhFiX<+t0#*s?$I5sSFz~FQjNmv;VWxlBXcBTgQO76Y$djTI z?``B2k&OZg?==jIPAU6>-BLYaom(?zT2Z@WI-Z!HA#|>%&`&l0t_Ymkj}Tvz{e?xl z=S+HQLFU_t@FN}ijA#Hf>rYF)ZW49fiiWYrrwG4P(hoYH&R`-D4$D8$j*_Y^ey6ruN7xIs?L_6 zM$6go*^7s^dt95g6udu$wKTdSI|Gx7kZc_eAl0O<2j(gv`;T>i4O%vQ0SoFmJbc|Kw z`-C3a`{ZhKcxqU=T?Nlw$i~^9e)tH`dWn9<3*Y~ZX6+Kk^$fu{4k_=dHHeK?aY`23 zLT;CIx)N0QeZc3|*X@bWD`UU!*Ie}z}-GKYM+CvQi0`l#&_kXYU{GUYd z|H=t!j<)6w*53a+EtIP6DK05td|q#|c+<$?ASn%0s?A@^m!NaFs!%AUbNleSy(@!xjsyUBHR4ETI|A`Fa+Ab@hf&lKMo zAlyD`v7<2*Wso=5p=gm=x5!K)6RNynWzVA~+Psdshzq?E2RdU=y6=aJ>P90kUQfM9 zpF@w6?wT@p5sUJmEk45-?IHWUW*T=pTZbN#gzU!0LyB(Pi8?37|0BKb{0QWiRru36 zScv~`YA&yfHl>gi@=W|j>@)z4C1e9u6tx|kOBw=Fpv#W%FZ_H(w{{jj!pfL(_mVZQ zWr>Z62%oL*QlXWS1w1T+#{Ey*h}Ybjo0xQ%!bn$*Va36>_-$W`Qs z&>{*}4Mf9+(QaitpTo-fE+$3z9py&KW9Q!x<9e`slzA`NQTp3l%A?Uyh<4eYf%4(K zUpNpukpbpksMQ?HSq}Qi2@Fb+zWQ z%kCBv3_<@oAL4YLG3}nMvnx6I|YG5a}R(bIR!cfW$t8_ zkVZ*Grrlj%&NzOtb^AYGjLL#grt>Uj$`=#!#Pc7QWMxsS(Z)zD^1>wTk;NbHM|8Zk%b zQw0axh86ybJaQ11`-&^-N^ZM|XvxV>gG=FaV4z?67o15RuzO#~+?#ca{&>tD630Pw1%G`V+bM=jv9|1oJ9oDblg6KSRSP zgJhd|h4x5rEEjVi3pha*1|v>Kr0k+z`f)V-_sv}EZI6-#fmT1>@zZ(6ZL+A^M7?@w zD_yg6ej1RIk#|k9TT>u{jJvj#r-b~gI*S1YpB(nYZ_PG~ozZ$Zqdb3`ccApwp}2RV+#g*_e?OnTo8 zLC>B&B=A*$T*tGZ0=3}z&NF1(nSjbHLOJO%W(p^JXWxQi*kltn$$ua?abBXM@NVoib`H zZsLafzzy*Z^`9#}4=q8zixLE+!2|?^;s1LA{;zMaQavvtwUreikKXfBWI9*?=3n&;eqySESZ#6qATN0-jfH5MF5 zTEiBb&KehiVRl%xvt`gl`ZX7wFcEdF*N=@fn{BPy@@@@en=jbgLIm{` zi5-3&NZ>gX9a!M?RX5)7{0iDBYP{k5mGt>J07|#cfaFfsEpOVsB<_)@V`H^0Ez_%N z+Rg5c9a0l6wKkLA_H?YY7G2jSRS^@^TvtrCtiDBbd5r{k?l!TeUYFBEh+<%X51?9J zaA&DKZ{?7+vAIaEH5oX^DOn5W>mnPBpSU;jQJjcIQjHzy64kdKd^#$uyKZxmG~J=^ zaqruFdh-*%@dvzuLAA9CFffSCxF|4ym*Uf~&GU-nV6_4E=`9b!_rnJ7pNz)eTt?T8DFQ!BC1_8B&_ke>qd}V|XQwXoraWTnN8EeA3N%A^s4ThZ+tc{rg zbzT%2ee0|EUrx9eqDkJOl;9o?XPIKj=5FKqTnwli7`J7prj@lV4i8kiJ{6{ZC21E( zvzFsb*wJYq(OF>FtKrK-SF_E0+0MaZKy<&nWd(_f;_h-f4Al(GdWnQz|MgUJDLzfW8lPRg0zr2uSF_TvAZicC+Yyl#Vifvm*a-a#raDxI9V~Bisit(DB-M$jX2r< zkT*DXKQLFvUsA`lf^TsZHP&c*A5-cySLfPSyNn4U?a|1RYOy9EJWkYCLYGV&DEduQ zH|Qp5VN6bD(;l|vdPJ5MhVc58!$dA!M&-2Lm6}`W{v#}lU$P{WLkJfYsyT&K3h}gQ zQP?mSZsRC~DhF?u^}Yt9j%oZt6^KHupEq@M9@e64q*Pn>y@6s;=M`)oxvETAx}K(M z)9eJ}=Qu#<@P!BMWUeZ`t7qgtTpcPP;&qx!f$<{Pgz`O$ZEjB64qsh$#AcCDAf_&L~~d?$}Of@`?S3 z%TB(q)edxW7qR!{%gze-$1_>SrkZHli;qx9({*itZ;y&SR+4Qf7f@LveOhf=+)NE_ z=3O94OwQUIK2T_EC3#4_#?(DXHgaXVA4MxQ# zE~6k|XgwTQm2P3aU6B{d8r0gZS1n2`0NGh=`&+A4(F!oaBqSMK_3M^fEEovbr&P=0 zy2T@el(XlVz6KoEgoT<;Y7@@H)BDkKmfswfOk3RWEra z>eQUxNuUcI6Ms^e?kudj}I>7Amt(!6>P_>j}eOIK{Llb}3;R?Y+GN;&q79`niu{y3yTF>O> zT6=4@zi|2jt!>eZACmlKNVo!TWXGC7>oLX8RM*w5t{&b)Ecn!8d1(a=BrYD_BDo|8 zqbSDV&(6sqRtQ?#Che6qKw7Mp>@w;Qyx$04#neEu(sDk-70dc+(4kn7V!(RPVJS#) z<43lu7Y`=p;Pol2io)YSF@v5%4ep-g?_V=}__i;88mGbeMm`=pZ}H58M2WVDBHkNr zwPj^~{D|mECkHT!dc0rLvsP>q;~OMhwaL@1P~Ez5WE5d#9cZwUgydwrc{BM8HV%5imQ!H<#9?|C z&h_jLT0Xi%;1%B1m6^}FfPyEn;QYD))mFqGZOoi-q7Y*pJ@px~Y)`|gMxQ)8p+;{I z2lpm6;~4a(K|ig#k$ACat|vFi=(X_ZPR|MopcSn@4^yM}-CGxuzqE7gpHvf!v>nOe zk5lOdc!Z&EgFtgpE6>1iXzLe}GpGoI(5PnOgL+tAj zi>Zu?HK~S?i$c`N(8Kb$xOLM-ua8S{+4Nc+Rla(Qv+V3rSz8SjoUBVh@T3kFQ)B&) zOAf^5jAi;-?KV#u#X8ujq!OOlJgbYeJ)3v82u@UN!d3G1D1A5D6emB8p}*T=AH2tZ zI2SCI#&{_2NF?S4)Wsrsdh?0H=m_6`bG^+MS-n=b0v>n>XH+zYQ<^OZG8q)@Gjw+M z_8Qa?>wvl@I^^4t0>&AQcgkl<)4!AmrYMy85F%C@pm5lO5bsGK7`P3QL9ndCjOU^7 z|D40{siMB z?}4T6y_?=AU5^cj8W{~9f$K@GBRu4T!+PE^nx?J0?<`PD2;`7pL{=jhj;um=8%YX> za6uWR{3PtxPb}M@&=WCnsWd`^qU*2ve<*vWAkm^_OSEj;wr$(CZQHhO+x9Nowyj;p zE?2$k?)&1sbH8p!oOWJBAH7sU^04_d*Gt zYSkH(iShRDpIq_BxA=e=^glcEch??ExMU<*B1Mivh-cMEL<@(BSJDwC)gnzY1QXBv zz;cTlxdlz3AkxeOlY**%I0DeTFc)_aetZ@|>C^`&PX0t38UZ8$<@gc7FCIc3YYyQh z+5WL)WaOHMz0f)G0lujp6dZD0k;{A%kDc)WyU?hgkA4uZ+r9~HL3}dK>W}oisZrAR zH^DYKEnO(qM{J?bdGFzpEm9~D`~v(L>&ySNuR_ZPc|a< zBHwR%?v&tWFVDg%ar2Jnd!%%{U4IlteA7L2uBhF-08;yw3G#!|7c?{)y?>Bsvhd)wI zxnmv=n;U@D@5gvm>QZAPV+#^|_$d865bQ)-LheFKGdet#JUn&jdXt+^(Nn0o7jcpm zStL!=E_rQKu@tqBhBskD3bs@kREY%5A!t-GVT|`iFX@!D^p>rY%W_s9HZV;X*Z^^8 zirgPW;zkR_vm}S#rn+*$E<*~Irrs5=Q_9GRE@$LB)TDjL4D~q;2%kya4OAhi7aE8* zbMKd{i{ma0W+Ox$RI_mq6@59nbfcD?RGi+r_em$*6FdF`1hpZR95a$+-;1i$zs=}PD>;J*y|A>zTcG#(X z_ldVFFQ;?p?EOw)oi(Exy0m}^QO9NvFYpg*LvBF>H(~A$DCm_P#=t)T$Uoqt z#^zkPJJyR^Fp{*Cz)cHGekL<;M3I_T_hh7-hHywAVqXJ}9hi5KS9~%H#0Kgg*f#e9{VYg}5J@GWt1HtMOHc=kkOr$Oh*8Y>Lx~D2nHX9lm3bzN1X8 zn=?fE0xECx6@>XhK5nQtBzgTsrm$=g^R#8I!K=~T5|=m2 z4qVtU({$R>z$wsJ8nl-Phmit1(PT0#CxMEl+1zP56$~bELu}#T7-Wn0EwF(~+9)R^ z*@ls}$C`3Tu>p}{gVIe|q*Q=R(v&hx90pgS@h@utG3+UUQPUb5)|ze;*f`&@v~iLg z?@-$~r){uZm}D=0w;_%su1HtDvYci{38@q!tXSk-Sma?^;M5+~voE3P^iazFq zpK{{QG=t3`}DY zBLzaHL6@59l=W98WKfHk9$cYwh=VNFhnm(gXpi398xQD9y!!+3RL2Femp8yiF$_k3 z7<4eGU|~{yHz7KvL;7EtvkzJ9RxC%>wxO2phAHU-3)5^F)|_x<7;ON?rePbTo``7} zcS8P-p%or}(CyfEif-A&qDWHvBV@G?RS1|RTI&`%VdWb}w{D?$#CyF9S#7bl+)B3a zq{+Fw0%bT8#WGs&0;_R>*??qq6{;quDlgG$+K)Q`NPP{g)`ff*c`HEcUdVJCCNpJ+ zVYdN{O#9MrGo`0t+lele_SG=qgs)@XiSMTAbznFJ?6CMCy!8FmqH?t4fD#w^_0i#w z5Bp^$kS{JtlI1OMZ_f!+bplbM{a!Hd#3K16PU`>jek-W?DUZw=xpT$`M*NXV)ZN*{ zV~aFE7rChzf<`!al$5g2v+gT8W}pJ3G)GR_DwyD91W=VYX5a#()F&-LdJ}(M;2K+@jxmo=A0FCn%v}b5x$Zh;3KD00}i?>j%@r)PN0^9 z@^@g#fHwugngH-kK&d7hbaf2Lm{wZAM(TGVAN=eske>`<-7>&S$)3+qa{?Jb zD;>m|wSa7Vjh#XEZlDA7V4Wnkz!>=KL8NqqoUoY?l9D(Yp%Qew0*;K7aQPN??8>D0 za2Xs4DWQ80JMq_~==Tlk@8akGU6_**xNfnN)Z-tSA#;b5D-C_k2^9Ve+fg*g4PA!F z>3-oY>rO=3rgbQ*`%N0`z`OnRO|b33zwLmJs)3)>C6mpmLV7$%dUJS%{8VB1$u#hT z)Dxbb`ki^@k3)sYCOYKE6gg1T@0c+?-?qV*lRFa7@Rav%0D!QKQ7cZk<^|KedbHop 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

faTD#cVqP`Bc$9F_6Qk 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 V7&w7~N(TO&0!w$O34wS8^?!3sleYi> literal 0 HcmV?d00001 diff --git a/lib/jakarta-regexp-1.5.jar b/lib/jakarta-regexp-1.5.jar new file mode 100644 index 0000000000000000000000000000000000000000..652bc822c96b4c4170b6988b40ef320b005b8ce4 GIT binary patch literal 33028 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 literal 0 HcmV?d00001 diff --git a/src/main/java/org/scribe/builder/api/AWeberApi.java b/src/apis/org/scribe/builder/api/AWeberApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/AWeberApi.java rename to src/apis/org/scribe/builder/api/AWeberApi.java diff --git a/src/main/java/org/scribe/builder/api/DiggApi.java b/src/apis/org/scribe/builder/api/DiggApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/DiggApi.java rename to src/apis/org/scribe/builder/api/DiggApi.java diff --git a/src/main/java/org/scribe/builder/api/DropBoxApi.java b/src/apis/org/scribe/builder/api/DropBoxApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/DropBoxApi.java rename to src/apis/org/scribe/builder/api/DropBoxApi.java diff --git a/src/main/java/org/scribe/builder/api/EvernoteApi.java b/src/apis/org/scribe/builder/api/EvernoteApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/EvernoteApi.java rename to src/apis/org/scribe/builder/api/EvernoteApi.java diff --git a/src/main/java/org/scribe/builder/api/FacebookApi.java b/src/apis/org/scribe/builder/api/FacebookApi.java similarity index 77% rename from src/main/java/org/scribe/builder/api/FacebookApi.java rename to src/apis/org/scribe/builder/api/FacebookApi.java index 61fcb0164..afe17fed4 100644 --- a/src/main/java/org/scribe/builder/api/FacebookApi.java +++ b/src/apis/org/scribe/builder/api/FacebookApi.java @@ -1,5 +1,6 @@ package org.scribe.builder.api; +import org.apache.commons.lang.StringUtils; import org.scribe.model.OAuthConfig; import org.scribe.utils.OAuthEncoder; import org.scribe.utils.Preconditions; @@ -17,8 +18,9 @@ public String getAuthorizationUrl(final OAuthConfig config) { "Must provide a valid url as callback. Facebook does not support OOB"); // Append scope if present - String result = AUTHORIZE_URL.replace("%clientId%", config.getApiKey()).replace( - "redirectUri", OAuthEncoder.encode(config.getCallback())); + String result = StringUtils.replace(AUTHORIZE_URL, "%clientId%", config.getApiKey()); + result = StringUtils.replace(result, "redirectUri", + OAuthEncoder.encode(config.getCallback())); if (config.hasScope()) { result = result + SCOPED_PARAMETER + config.getScope(); } diff --git a/src/main/java/org/scribe/builder/api/FlickrApi.java b/src/apis/org/scribe/builder/api/FlickrApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/FlickrApi.java rename to src/apis/org/scribe/builder/api/FlickrApi.java diff --git a/src/main/java/org/scribe/builder/api/Foursquare2Api.java b/src/apis/org/scribe/builder/api/Foursquare2Api.java similarity index 78% rename from src/main/java/org/scribe/builder/api/Foursquare2Api.java rename to src/apis/org/scribe/builder/api/Foursquare2Api.java index 08487dcbb..63f2cb0b7 100644 --- a/src/main/java/org/scribe/builder/api/Foursquare2Api.java +++ b/src/apis/org/scribe/builder/api/Foursquare2Api.java @@ -1,5 +1,6 @@ package org.scribe.builder.api; +import org.apache.commons.lang.StringUtils; import org.scribe.extractors.AccessTokenExtractor; import org.scribe.extractors.JsonTokenExtractor; import org.scribe.model.OAuthConfig; @@ -16,8 +17,9 @@ public String getAccessTokenEndpoint() { public String getAuthorizationUrl(final OAuthConfig config) { Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Foursquare2 does not support OOB"); - return AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace("redirectUri", - OAuthEncoder.encode(config.getCallback())); + final String result = StringUtils.replace(AUTHORIZE_URL, "clientId", config.getApiKey()); + StringUtils.replace(result, "redirectUri", OAuthEncoder.encode(config.getCallback())); + return result; } public AccessTokenExtractor getAccessTokenExtractor() { diff --git a/src/main/java/org/scribe/builder/api/FoursquareApi.java b/src/apis/org/scribe/builder/api/FoursquareApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/FoursquareApi.java rename to src/apis/org/scribe/builder/api/FoursquareApi.java diff --git a/src/main/java/org/scribe/builder/api/FreelancerApi.java b/src/apis/org/scribe/builder/api/FreelancerApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/FreelancerApi.java rename to src/apis/org/scribe/builder/api/FreelancerApi.java diff --git a/src/main/java/org/scribe/builder/api/GetGlueApi.java b/src/apis/org/scribe/builder/api/GetGlueApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/GetGlueApi.java rename to src/apis/org/scribe/builder/api/GetGlueApi.java diff --git a/src/main/java/org/scribe/builder/api/GoogleApi.java b/src/apis/org/scribe/builder/api/GoogleApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/GoogleApi.java rename to src/apis/org/scribe/builder/api/GoogleApi.java diff --git a/src/main/java/org/scribe/builder/api/ImgUrApi.java b/src/apis/org/scribe/builder/api/ImgUrApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/ImgUrApi.java rename to src/apis/org/scribe/builder/api/ImgUrApi.java diff --git a/src/main/java/org/scribe/builder/api/KaixinApi.java b/src/apis/org/scribe/builder/api/KaixinApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/KaixinApi.java rename to src/apis/org/scribe/builder/api/KaixinApi.java diff --git a/src/main/java/org/scribe/builder/api/KaixinApi20.java b/src/apis/org/scribe/builder/api/KaixinApi20.java similarity index 82% rename from src/main/java/org/scribe/builder/api/KaixinApi20.java rename to src/apis/org/scribe/builder/api/KaixinApi20.java index a0b65cb57..5f2d0aab4 100644 --- a/src/main/java/org/scribe/builder/api/KaixinApi20.java +++ b/src/apis/org/scribe/builder/api/KaixinApi20.java @@ -1,5 +1,6 @@ package org.scribe.builder.api; +import org.apache.commons.lang.StringUtils; import org.scribe.extractors.AccessTokenExtractor; import org.scribe.extractors.JsonTokenExtractor; import org.scribe.model.OAuthConfig; @@ -22,8 +23,8 @@ public String getAccessTokenEndpoint() { } public String getAuthorizationUrl(final OAuthConfig config) { - String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( - "%redirectUri%", OAuthEncoder.encode(config.getCallback())); + String result = StringUtils.replace(AUTHORIZE_URL, "clientId", config.getApiKey()); + StringUtils.replace(result, "%redirectUri%", OAuthEncoder.encode(config.getCallback())); // Append scope if present if (config.hasScope()) { result = SCOPED_AUTHORIZE_URL + OAuthEncoder.encode(config.getScope()); diff --git a/src/main/java/org/scribe/builder/api/LinkedInApi.java b/src/apis/org/scribe/builder/api/LinkedInApi.java similarity index 97% rename from src/main/java/org/scribe/builder/api/LinkedInApi.java rename to src/apis/org/scribe/builder/api/LinkedInApi.java index 45255dcb5..4e59dcd62 100644 --- a/src/main/java/org/scribe/builder/api/LinkedInApi.java +++ b/src/apis/org/scribe/builder/api/LinkedInApi.java @@ -15,7 +15,7 @@ public class LinkedInApi extends DefaultApi10a { private final Set/**/scopes; public LinkedInApi() { - scopes = Collections.emptySet(); + scopes = new HashSet();//.emptySet(); } public LinkedInApi(final Set/**/scopes) { diff --git a/src/main/java/org/scribe/builder/api/LiveApi.java b/src/apis/org/scribe/builder/api/LiveApi.java similarity index 80% rename from src/main/java/org/scribe/builder/api/LiveApi.java rename to src/apis/org/scribe/builder/api/LiveApi.java index bfd199c76..51d784c21 100644 --- a/src/main/java/org/scribe/builder/api/LiveApi.java +++ b/src/apis/org/scribe/builder/api/LiveApi.java @@ -1,5 +1,6 @@ package org.scribe.builder.api; +import org.apache.commons.lang.StringUtils; import org.scribe.extractors.AccessTokenExtractor; import org.scribe.extractors.JsonTokenExtractor; import org.scribe.model.OAuthConfig; @@ -15,8 +16,8 @@ public String getAccessTokenEndpoint() { } public String getAuthorizationUrl(final OAuthConfig config) { - String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( - "%redirectUri%", OAuthEncoder.encode(config.getCallback())); + String result = StringUtils.replace(AUTHORIZE_URL, "clientId", config.getApiKey()); + StringUtils.replace(result, "%redirectUri%", OAuthEncoder.encode(config.getCallback())); // Append scope if present if (config.hasScope()) { result = SCOPED_AUTHORIZE_URL + OAuthEncoder.encode(config.getScope()); diff --git a/src/main/java/org/scribe/builder/api/LoveFilmApi.java b/src/apis/org/scribe/builder/api/LoveFilmApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/LoveFilmApi.java rename to src/apis/org/scribe/builder/api/LoveFilmApi.java diff --git a/src/main/java/org/scribe/builder/api/MeetupApi.java b/src/apis/org/scribe/builder/api/MeetupApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/MeetupApi.java rename to src/apis/org/scribe/builder/api/MeetupApi.java diff --git a/src/main/java/org/scribe/builder/api/MendeleyApi.java b/src/apis/org/scribe/builder/api/MendeleyApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/MendeleyApi.java rename to src/apis/org/scribe/builder/api/MendeleyApi.java diff --git a/src/main/java/org/scribe/builder/api/MisoApi.java b/src/apis/org/scribe/builder/api/MisoApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/MisoApi.java rename to src/apis/org/scribe/builder/api/MisoApi.java diff --git a/src/main/java/org/scribe/builder/api/NetProspexApi.java b/src/apis/org/scribe/builder/api/NetProspexApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/NetProspexApi.java rename to src/apis/org/scribe/builder/api/NetProspexApi.java diff --git a/src/main/java/org/scribe/builder/api/NeteaseWeibooApi.java b/src/apis/org/scribe/builder/api/NeteaseWeibooApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/NeteaseWeibooApi.java rename to src/apis/org/scribe/builder/api/NeteaseWeibooApi.java diff --git a/src/main/java/org/scribe/builder/api/PlurkApi.java b/src/apis/org/scribe/builder/api/PlurkApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/PlurkApi.java rename to src/apis/org/scribe/builder/api/PlurkApi.java diff --git a/src/main/java/org/scribe/builder/api/Px500Api.java b/src/apis/org/scribe/builder/api/Px500Api.java similarity index 100% rename from src/main/java/org/scribe/builder/api/Px500Api.java rename to src/apis/org/scribe/builder/api/Px500Api.java diff --git a/src/main/java/org/scribe/builder/api/QWeiboApi.java b/src/apis/org/scribe/builder/api/QWeiboApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/QWeiboApi.java rename to src/apis/org/scribe/builder/api/QWeiboApi.java diff --git a/src/main/java/org/scribe/builder/api/RenrenApi.java b/src/apis/org/scribe/builder/api/RenrenApi.java similarity index 81% rename from src/main/java/org/scribe/builder/api/RenrenApi.java rename to src/apis/org/scribe/builder/api/RenrenApi.java index 78998cd43..e79300bb3 100644 --- a/src/main/java/org/scribe/builder/api/RenrenApi.java +++ b/src/apis/org/scribe/builder/api/RenrenApi.java @@ -1,5 +1,6 @@ package org.scribe.builder.api; +import org.apache.commons.lang.StringUtils; import org.scribe.extractors.AccessTokenExtractor; import org.scribe.extractors.JsonTokenExtractor; import org.scribe.model.OAuthConfig; @@ -21,8 +22,8 @@ public String getAccessTokenEndpoint() { } public String getAuthorizationUrl(final OAuthConfig config) { - String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( - "redirectUri", OAuthEncoder.encode(config.getCallback())); + String result = StringUtils.replace(AUTHORIZE_URL, "clientId", config.getApiKey()); + StringUtils.replace(result, "redirectUri", OAuthEncoder.encode(config.getCallback())); // Append scope if present if (config.hasScope()) { result = result + SCOPED_PARAMETER + OAuthEncoder.encode(config.getScope()); diff --git a/src/main/java/org/scribe/builder/api/SapoApi.java b/src/apis/org/scribe/builder/api/SapoApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/SapoApi.java rename to src/apis/org/scribe/builder/api/SapoApi.java diff --git a/src/main/java/org/scribe/builder/api/SimpleGeoApi.java b/src/apis/org/scribe/builder/api/SimpleGeoApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/SimpleGeoApi.java rename to src/apis/org/scribe/builder/api/SimpleGeoApi.java diff --git a/src/main/java/org/scribe/builder/api/SinaWeiboApi.java b/src/apis/org/scribe/builder/api/SinaWeiboApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/SinaWeiboApi.java rename to src/apis/org/scribe/builder/api/SinaWeiboApi.java diff --git a/src/main/java/org/scribe/builder/api/SinaWeiboApi20.java b/src/apis/org/scribe/builder/api/SinaWeiboApi20.java similarity index 83% rename from src/main/java/org/scribe/builder/api/SinaWeiboApi20.java rename to src/apis/org/scribe/builder/api/SinaWeiboApi20.java index 829b08a65..e4b2abc99 100644 --- a/src/main/java/org/scribe/builder/api/SinaWeiboApi20.java +++ b/src/apis/org/scribe/builder/api/SinaWeiboApi20.java @@ -1,5 +1,6 @@ package org.scribe.builder.api; +import org.apache.commons.lang.StringUtils; import org.scribe.extractors.AccessTokenExtractor; import org.scribe.extractors.JsonTokenExtractor; import org.scribe.model.OAuthConfig; @@ -26,8 +27,8 @@ public String getAccessTokenEndpoint() { } public String getAuthorizationUrl(final OAuthConfig config) { - String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( - "redirectUri", OAuthEncoder.encode(config.getCallback())); + String result = StringUtils.replace(AUTHORIZE_URL, "clientId", config.getApiKey()); + StringUtils.replace(result, "redirectUri", OAuthEncoder.encode(config.getCallback())); // Append scope if present if (config.hasScope()) { result = result + SCOPED_PARAMETER + OAuthEncoder.encode(config.getScope()); diff --git a/src/main/java/org/scribe/builder/api/SkyrockApi.java b/src/apis/org/scribe/builder/api/SkyrockApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/SkyrockApi.java rename to src/apis/org/scribe/builder/api/SkyrockApi.java diff --git a/src/main/java/org/scribe/builder/api/SohuWeiboApi.java b/src/apis/org/scribe/builder/api/SohuWeiboApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/SohuWeiboApi.java rename to src/apis/org/scribe/builder/api/SohuWeiboApi.java diff --git a/src/main/java/org/scribe/builder/api/TrelloApi.java b/src/apis/org/scribe/builder/api/TrelloApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/TrelloApi.java rename to src/apis/org/scribe/builder/api/TrelloApi.java diff --git a/src/main/java/org/scribe/builder/api/TumblrApi.java b/src/apis/org/scribe/builder/api/TumblrApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/TumblrApi.java rename to src/apis/org/scribe/builder/api/TumblrApi.java diff --git a/src/main/java/org/scribe/builder/api/TwitterApi.java b/src/apis/org/scribe/builder/api/TwitterApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/TwitterApi.java rename to src/apis/org/scribe/builder/api/TwitterApi.java diff --git a/src/main/java/org/scribe/builder/api/UbuntuOneApi.java b/src/apis/org/scribe/builder/api/UbuntuOneApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/UbuntuOneApi.java rename to src/apis/org/scribe/builder/api/UbuntuOneApi.java diff --git a/src/main/java/org/scribe/builder/api/ViadeoApi.java b/src/apis/org/scribe/builder/api/ViadeoApi.java similarity index 83% rename from src/main/java/org/scribe/builder/api/ViadeoApi.java rename to src/apis/org/scribe/builder/api/ViadeoApi.java index 3094f0f26..70e0a807e 100644 --- a/src/main/java/org/scribe/builder/api/ViadeoApi.java +++ b/src/apis/org/scribe/builder/api/ViadeoApi.java @@ -1,5 +1,6 @@ package org.scribe.builder.api; +import org.apache.commons.lang.StringUtils; import org.scribe.extractors.AccessTokenExtractor; import org.scribe.extractors.JsonTokenExtractor; import org.scribe.model.OAuthConfig; @@ -21,8 +22,8 @@ public String getAccessTokenEndpoint() { public String getAuthorizationUrl(final OAuthConfig config) { Preconditions.checkValidUrl(config.getCallback(), "Must provide a valid url as callback. Viadeo does not support OOB"); - String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( - "redirectUri", OAuthEncoder.encode(config.getCallback())); + String result = StringUtils.replace(AUTHORIZE_URL, "clientId", config.getApiKey()); + StringUtils.replace(result, "redirectUri", OAuthEncoder.encode(config.getCallback())); // Append scope if present if (config.hasScope()) { result = result + SCOPED_PARAMETER + OAuthEncoder.encode(config.getScope()); diff --git a/src/main/java/org/scribe/builder/api/VimeoApi.java b/src/apis/org/scribe/builder/api/VimeoApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/VimeoApi.java rename to src/apis/org/scribe/builder/api/VimeoApi.java diff --git a/src/main/java/org/scribe/builder/api/VkontakteApi.java b/src/apis/org/scribe/builder/api/VkontakteApi.java similarity index 84% rename from src/main/java/org/scribe/builder/api/VkontakteApi.java rename to src/apis/org/scribe/builder/api/VkontakteApi.java index e39573b90..744403098 100644 --- a/src/main/java/org/scribe/builder/api/VkontakteApi.java +++ b/src/apis/org/scribe/builder/api/VkontakteApi.java @@ -1,5 +1,6 @@ package org.scribe.builder.api; +import org.apache.commons.lang.StringUtils; import org.scribe.extractors.AccessTokenExtractor; import org.scribe.extractors.JsonTokenExtractor; import org.scribe.model.OAuthConfig; @@ -21,8 +22,8 @@ public String getAccessTokenEndpoint() { public String getAuthorizationUrl(final OAuthConfig config) { Preconditions.checkValidUrl(config.getCallback(), "Valid url is required for a callback. Vkontakte does not support OOB"); - String result = AUTHORIZE_URL.replace("clientId", config.getApiKey()).replace( - "redirectUri", OAuthEncoder.encode(config.getCallback())); + String result = StringUtils.replace(AUTHORIZE_URL, "clientId", config.getApiKey()); + StringUtils.replace(result, "redirectUri", OAuthEncoder.encode(config.getCallback())); // Append scope if present if (config.hasScope()) { result = result + SCOPED_PARAMETER + OAuthEncoder.encode(config.getScope()); diff --git a/src/main/java/org/scribe/builder/api/XingApi.java b/src/apis/org/scribe/builder/api/XingApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/XingApi.java rename to src/apis/org/scribe/builder/api/XingApi.java diff --git a/src/main/java/org/scribe/builder/api/YahooApi.java b/src/apis/org/scribe/builder/api/YahooApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/YahooApi.java rename to src/apis/org/scribe/builder/api/YahooApi.java diff --git a/src/main/java/org/scribe/builder/api/YammerApi.java b/src/apis/org/scribe/builder/api/YammerApi.java similarity index 100% rename from src/main/java/org/scribe/builder/api/YammerApi.java rename to src/apis/org/scribe/builder/api/YammerApi.java diff --git a/src/main/java/org/scribe/builder/api/ConstantContactApi2.java b/src/main/java/org/scribe/builder/api/ConstantContactApi2.java index 870c5d21d..e87101af2 100644 --- a/src/main/java/org/scribe/builder/api/ConstantContactApi2.java +++ b/src/main/java/org/scribe/builder/api/ConstantContactApi2.java @@ -1,8 +1,7 @@ package org.scribe.builder.api; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import org.apache.commons.lang.StringUtils; +import org.apache.regexp.RE; import org.scribe.exceptions.OAuthException; import org.scribe.extractors.AccessTokenExtractor; import org.scribe.model.OAuthConfig; @@ -19,8 +18,10 @@ public String getAccessTokenEndpoint() { } public String getAuthorizationUrl(final OAuthConfig config) { - return AUTHORIZE_URL.replace("%clientId%", config.getApiKey()).replace("%redirectUri%", + String string = StringUtils.replace(AUTHORIZE_URL, "%clientId%", config.getApiKey()); + string = StringUtils.replace(string, "%redirectUri%", OAuthEncoder.encode(config.getCallback())); + return string; } public Verb getAccessTokenVerb() { @@ -31,17 +32,18 @@ public AccessTokenExtractor getAccessTokenExtractor() { return new AccessTokenExtractor() { public Token extract(final String response) { - Preconditions.checkEmptyString(response, - "Response body is incorrect. Can't extract a token from an empty string"); + Preconditions + .checkEmptyString(response, + "ResponseHttpImpl body is incorrect. Can't extract a token from an empty string"); final String regex = "\"access_token\"\\s*:\\s*\"([^&\"]+)\""; - final Matcher matcher = Pattern.compile(regex).matcher(response); - if (matcher.find()) { - final String token = OAuthEncoder.decode(matcher.group(1)); + final RE re = new RE(regex); + if (re.match(response)) { + final String token = OAuthEncoder.decode(re.getParen(1)); return new Token(token, "", response); } else { throw new OAuthException( - "Response body is incorrect. Can't extract a token from this: '" + "ResponseHttpImpl body is incorrect. Can't extract a token from this: '" + response + "'", null); } } diff --git a/src/main/java/org/scribe/extractors/AccessTokenExtractor.java b/src/main/java/org/scribe/extractors/AccessTokenExtractor.java index 3c0dd34d6..8da755ab8 100644 --- a/src/main/java/org/scribe/extractors/AccessTokenExtractor.java +++ b/src/main/java/org/scribe/extractors/AccessTokenExtractor.java @@ -10,7 +10,7 @@ public interface AccessTokenExtractor { /** - * Extracts the access token from the contents of an Http Response + * Extracts the access token from the contents of an Http ResponseHttpImpl * * @param response the contents of the response * @return OAuth access token diff --git a/src/main/java/org/scribe/extractors/BaseStringExtractorImpl.java b/src/main/java/org/scribe/extractors/BaseStringExtractorImpl.java index 50d7168d9..c358cb13d 100644 --- a/src/main/java/org/scribe/extractors/BaseStringExtractorImpl.java +++ b/src/main/java/org/scribe/extractors/BaseStringExtractorImpl.java @@ -22,7 +22,7 @@ public class BaseStringExtractorImpl implements BaseStringExtractor { public String extract(final OAuthRequest request) { checkPreconditions(request); final String verb = OAuthEncoder.encode(request.getVerb().name()); - final String url = OAuthEncoder.encode(request.getSanitizedUrl()); + final String url = OAuthEncoder.encode(request.getUrl()); final String params = getSortedAndEncodedParams(request); final StringBuffer buffer = new StringBuffer(); buffer.append(verb); diff --git a/src/main/java/org/scribe/extractors/JsonTokenExtractor.java b/src/main/java/org/scribe/extractors/JsonTokenExtractor.java index 801cd6296..214480f0f 100644 --- a/src/main/java/org/scribe/extractors/JsonTokenExtractor.java +++ b/src/main/java/org/scribe/extractors/JsonTokenExtractor.java @@ -1,27 +1,24 @@ package org.scribe.extractors; -import java.util.regex.*; +import org.apache.regexp.RE; +import org.apache.regexp.REUtil; +import org.scribe.exceptions.OAuthException; +import org.scribe.model.Token; +import org.scribe.utils.Preconditions; -import org.scribe.exceptions.*; -import org.scribe.model.*; -import org.scribe.utils.*; +public class JsonTokenExtractor implements AccessTokenExtractor { + private static final String ACCESS_TOKEN_PATTERN = "\"access_token\":\\s*\"(\\S*?)\""; -public class JsonTokenExtractor implements AccessTokenExtractor -{ - private Pattern accessTokenPattern = Pattern.compile("\"access_token\":\\s*\"(\\S*?)\""); + public Token extract(final String response) { - public Token extract(String response) - { - Preconditions.checkEmptyString(response, "Cannot extract a token from a null or empty String"); - Matcher matcher = accessTokenPattern.matcher(response); - if(matcher.find()) - { - return new Token(matcher.group(1), "", response); + Preconditions.checkEmptyString(response, + "Cannot extract a token from a null or empty String"); + final RE accessTokenPattern = REUtil.createRE(ACCESS_TOKEN_PATTERN); + if (accessTokenPattern.match(response)) { + return new Token(accessTokenPattern.getParen(1), "", response); + } else { + throw new OAuthException("Cannot extract an acces token. ResponseHttpImpl was: " + + response); + } } - else - { - throw new OAuthException("Cannot extract an acces token. Response was: " + response); - } - } - } \ No newline at end of file diff --git a/src/main/java/org/scribe/extractors/RequestTokenExtractor.java b/src/main/java/org/scribe/extractors/RequestTokenExtractor.java index 1830212b6..3bc9f4d85 100644 --- a/src/main/java/org/scribe/extractors/RequestTokenExtractor.java +++ b/src/main/java/org/scribe/extractors/RequestTokenExtractor.java @@ -10,7 +10,7 @@ public interface RequestTokenExtractor { /** - * Extracts the request token from the contents of an Http Response + * Extracts the request token from the contents of an Http ResponseHttpImpl * * @param response the contents of the response * @return OAuth access token diff --git a/src/main/java/org/scribe/extractors/TokenExtractor20Impl.java b/src/main/java/org/scribe/extractors/TokenExtractor20Impl.java index 1eb22ad63..257b38b9e 100644 --- a/src/main/java/org/scribe/extractors/TokenExtractor20Impl.java +++ b/src/main/java/org/scribe/extractors/TokenExtractor20Impl.java @@ -1,36 +1,34 @@ package org.scribe.extractors; -import java.util.regex.*; - -import org.scribe.exceptions.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.apache.regexp.RE; +import org.apache.regexp.REUtil; +import org.scribe.exceptions.OAuthException; +import org.scribe.model.Token; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; /** * Default implementation of {@AccessTokenExtractor}. Conforms to OAuth 2.0 * */ -public class TokenExtractor20Impl implements AccessTokenExtractor -{ - private static final String TOKEN_REGEX = "access_token=([^&]+)"; - private static final String EMPTY_SECRET = ""; - - /** - * {@inheritDoc} - */ - public Token extract(String response) - { - Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string"); +public class TokenExtractor20Impl implements AccessTokenExtractor { + private static final String TOKEN_REGEX = "access_token=([^&]+)"; + private static final String EMPTY_SECRET = ""; - Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response); - if (matcher.find()) - { - String token = OAuthEncoder.decode(matcher.group(1)); - return new Token(token, EMPTY_SECRET, response); - } - else - { - throw new OAuthException("Response body is incorrect. Can't extract a token from this: '" + response + "'", null); + /** + * {@inheritDoc} + */ + public Token extract(final String response) { + Preconditions.checkEmptyString(response, + "ResponseHttpImpl body is incorrect. Can't extract a token from an empty string"); + final RE re = REUtil.createRE(TOKEN_REGEX); + if (re.match(response)) { + final String token = OAuthEncoder.decode(re.getParen(1)); + return new Token(token, EMPTY_SECRET, response); + } else { + throw new OAuthException( + "ResponseHttpImpl body is incorrect. Can't extract a token from this: '" + + response + "'", null); + } } - } } diff --git a/src/main/java/org/scribe/extractors/TokenExtractorImpl.java b/src/main/java/org/scribe/extractors/TokenExtractorImpl.java index ba1784b9b..0a6615483 100644 --- a/src/main/java/org/scribe/extractors/TokenExtractorImpl.java +++ b/src/main/java/org/scribe/extractors/TokenExtractorImpl.java @@ -1,10 +1,11 @@ package org.scribe.extractors; -import java.util.regex.*; - -import org.scribe.exceptions.*; -import org.scribe.model.*; -import org.scribe.utils.*; +import org.apache.regexp.RE; +import org.apache.regexp.REUtil; +import org.scribe.exceptions.OAuthException; +import org.scribe.model.Token; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; /** * Default implementation of {@RequestTokenExtractor} and {@AccessTokenExtractor}. Conforms to OAuth 1.0a @@ -13,32 +14,30 @@ * * @author Pablo Fernandez */ -public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExtractor -{ - private static final Pattern TOKEN_REGEX = Pattern.compile("oauth_token=([^&]+)"); - private static final Pattern SECRET_REGEX = Pattern.compile("oauth_token_secret=([^&]*)"); - - /** - * {@inheritDoc} - */ - public Token extract(String response) - { - Preconditions.checkEmptyString(response, "Response body is incorrect. Can't extract a token from an empty string"); - String token = extract(response, TOKEN_REGEX); - String secret = extract(response, SECRET_REGEX); - return new Token(token, secret, response); - } +public class TokenExtractorImpl implements RequestTokenExtractor, AccessTokenExtractor { + private static final String TOKEN_REGEX = "oauth_token=([^&]+)"; + private static final String SECRET_REGEX = "oauth_token_secret=([^&]*)"; - private String extract(String response, Pattern p) - { - Matcher matcher = p.matcher(response); - if (matcher.find() && matcher.groupCount() >= 1) - { - return OAuthEncoder.decode(matcher.group(1)); + /** + * {@inheritDoc} + */ + public Token extract(final String response) { + Preconditions.checkEmptyString(response, + "ResponseHttpImpl body is incorrect. Can't extract a token from an empty string"); + final String token = extract(response, TOKEN_REGEX); + final String secret = extract(response, SECRET_REGEX); + return new Token(token, secret, response); } - else - { - throw new OAuthException("Response body is incorrect. Can't extract token and secret from this: '" + response + "'", null); + + private String extract(final String response, final String p) { + final RE re = REUtil.createRE(p); + + if (re.match(response) && re.getMatchFlags() >= 1) { + return OAuthEncoder.decode(re.getParen(1)); + } else { + throw new OAuthException( + "ResponseHttpImpl body is incorrect. Can't extract token and secret from this: '" + + response + "'", null); + } } - } } diff --git a/src/main/java/org/scribe/model/OAuthRequest.java b/src/main/java/org/scribe/model/OAuthRequest.java index d5ef19620..653763c46 100644 --- a/src/main/java/org/scribe/model/OAuthRequest.java +++ b/src/main/java/org/scribe/model/OAuthRequest.java @@ -1,19 +1,30 @@ package org.scribe.model; +import java.io.IOException; import java.util.HashMap; import java.util.Map; /** - * The representation of an OAuth HttpRequest. + * The representation of an OAuth Request is a Bridge to the request object. The user can provide the underlying request object * - * Adds OAuth-related functionality to the {@link Request} - * - * @author Pablo Fernandez + * @author Duane Musser */ -public class OAuthRequest extends Request { +public class OAuthRequest implements Request { + /** + * + */ + private static final String NOT_INTIALIZED = "Not intialized! Make sure RequestFactortImpl is provided."; private static final String OAUTH_PREFIX = "oauth_"; private final Map/**/oauthParameters; + private Request request; + + public OAuthRequest(final Request request) { + super(); + this.request = request; + oauthParameters = new HashMap/**/(); + } + /** * Default constructor. * @@ -21,7 +32,22 @@ public class OAuthRequest extends Request { * @param url resource URL */ public OAuthRequest(final Verb verb, final String url) { - super(verb, url); + super(); + try { + final Class clazz = OAuthRequest.class.getClassLoader().loadClass( + "org.scribe.model.RequestFactoryImpl"); + final RequestFactory factory = (RequestFactory) clazz.newInstance(); + request = factory.createRequest(verb, url); + } catch (final ClassNotFoundException e) { + e.printStackTrace(); + request = null; + } catch (final InstantiationException e) { + e.printStackTrace(); + request = null; + } catch (final IllegalAccessException e) { + e.printStackTrace(); + request = null; + } oauthParameters = new HashMap/**/(); } @@ -58,4 +84,106 @@ private String checkKey(final String key) { public String toString() { return "@OAuthRequest(" + String.valueOf(getVerb()) + ", " + String.valueOf(getUrl()) + ")"; } + + /** + * @see org.scribe.model.Request#addHeader(java.lang.String, java.lang.String) + */ + public void addHeader(final String key, final String value) { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + request.addHeader(key, value); + } + + /** + * @see org.scribe.model.Request#addBodyParameter(java.lang.String, java.lang.String) + */ + public void addBodyParameter(final String key, final String value) { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + request.addBodyParameter(key, value); + } + + /** + * @see org.scribe.model.Request#addQuerystringParameter(java.lang.String, java.lang.String) + */ + public void addQuerystringParameter(final String key, final String value) { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + request.addQuerystringParameter(key, value); + } + + /** + * @see org.scribe.model.Request#getQueryStringParams() + */ + public ParameterList getQueryStringParams() { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + return request.getQueryStringParams(); + } + + /** + * @see org.scribe.model.Request#getBodyParams() + */ + public ParameterList getBodyParams() { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + return request.getBodyParams(); + } + + /** + * @see org.scribe.model.Request#getUrl() + */ + public String getUrl() { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + return request.getUrl(); + } + + /** + * @see org.scribe.model.Request#getBodyContents() + */ + public String getBodyContents() { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + return request.getBodyContents(); + } + + /** + * @see org.scribe.model.Request#getVerb() + */ + public Verb getVerb() { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + return request.getVerb(); + } + + /** + * @see org.scribe.model.Request#getHeaders() + */ + public Map getHeaders() { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + return request.getHeaders(); + } + + /** + * @throws IOException + * @see org.scribe.model.Request#send() + */ + public Response send() throws IOException { + if (request == null) { + throw new IllegalAccessError(NOT_INTIALIZED); + } + return request.send(); + } + } diff --git a/src/main/java/org/scribe/model/ParameterList.java b/src/main/java/org/scribe/model/ParameterList.java index 5cc23453a..1d1f59f96 100644 --- a/src/main/java/org/scribe/model/ParameterList.java +++ b/src/main/java/org/scribe/model/ParameterList.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Map.Entry; +import org.apache.commons.lang.StringUtils; import org.scribe.utils.OAuthEncoder; import org.scribe.utils.Preconditions; @@ -79,10 +80,10 @@ public void addAll(final ParameterList other) { public void addQuerystring(final String queryString) { if (queryString != null && queryString.length() > 0) { - final String[] vals = queryString.split(PARAM_SEPARATOR); + final String[] vals = StringUtils.split(queryString, PARAM_SEPARATOR); for (int i = 0; i < vals.length; i++) { final String param = vals[i]; - final String pair[] = param.split(PAIR_SEPARATOR); + final String pair[] = StringUtils.split(param, PAIR_SEPARATOR); final String key = OAuthEncoder.decode(pair[0]); final String value = pair.length > 1 ? OAuthEncoder.decode(pair[1]) : EMPTY_STRING; params.add(new Parameter(key, value)); diff --git a/src/main/java/org/scribe/model/Request.java b/src/main/java/org/scribe/model/Request.java index 26d85de02..42c3fcdf6 100644 --- a/src/main/java/org/scribe/model/Request.java +++ b/src/main/java/org/scribe/model/Request.java @@ -1,143 +1,43 @@ +/** + * + */ package org.scribe.model; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import java.util.concurrent.TimeUnit; -import org.scribe.exceptions.OAuthConnectionException; import org.scribe.exceptions.OAuthException; /** - * Represents an HTTP Request object - * - * @author Pablo Fernandez + * @author DMusser + * */ -public class Request { - private static final String CONTENT_LENGTH = "Content-Length"; - private static final String CONTENT_TYPE = "Content-Type"; - private static RequestTuner NOOP = new RequestTuner() { - public void tune(final Request _) { - } - }; - public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded"; - - private final String url; - private final Verb verb; - private final ParameterList querystringParams; - private final ParameterList bodyParams; - private final Map/**/headers; - private String payload = null; - private HttpURLConnection connection; - private String charset; - private byte[] bytePayload = null; - private boolean connectionKeepAlive = false; - private boolean followRedirects = true; - private Long connectTimeout = null; - private Long readTimeout = null; +public interface Request { - /** - * Creates a new Http Request - * - * @param verb Http Verb (GET, POST, etc) - * @param url url with optional querystring parameters. - */ - public Request(final Verb verb, final String url) { - this.verb = verb; - this.url = url; - querystringParams = new ParameterList(); - bodyParams = new ParameterList(); - headers = new HashMap/**/(); - } + public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded"; /** - * Execute the request and return a {@link Response} + * Execute the request and return a {@link ResponseHttpImpl} * - * @return Http Response - * @throws RuntimeException - * if the connection cannot be created. + * @return Response + * @throws IOException */ - public Response send(final RequestTuner tuner) { - try { - createConnection(); - return doSend(tuner); - } catch (final Exception e) { - throw new OAuthConnectionException(e); - } - } - - public Response send() { - return send(NOOP); - } - - private void createConnection() throws IOException { - final String completeUrl = getCompleteUrl(); - if (connection == null) { - System.setProperty("http.keepAlive", connectionKeepAlive ? "true" : "false"); - connection = (HttpURLConnection) new URL(completeUrl).openConnection(); - connection.setInstanceFollowRedirects(followRedirects); - } - } + public Response send() throws IOException; /** * Returns the complete url (host + resource + encoded querystring parameters). * * @return the complete url. */ - public String getCompleteUrl() { - return querystringParams.appendTo(url); - } - - Response doSend(final RequestTuner tuner) throws IOException { - connection.setRequestMethod(verb.name()); - if (connectTimeout != null) { - connection.setConnectTimeout(connectTimeout.intValue()); - } - if (readTimeout != null) { - connection.setReadTimeout(readTimeout.intValue()); - } - addHeaders(connection); - if (verb.equals(Verb.PUT) || verb.equals(Verb.POST)) { - addBody(connection, getByteBodyContents()); - } - tuner.tune(this); - return new Response(connection); - } - - void addHeaders(final HttpURLConnection conn) { - final Iterator i = headers.keySet().iterator(); - while (i.hasNext()) { - final String key = (String) i.next(); - conn.setRequestProperty(key, (String) headers.get(key)); - } - } - - void addBody(final HttpURLConnection conn, final byte[] content) throws IOException { - conn.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.length)); - - // Set default content type if none is set. - if (conn.getRequestProperty(CONTENT_TYPE) == null) { - conn.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); - } - conn.setDoOutput(true); - conn.getOutputStream().write(content); - } + // public String getCompleteUrl(); /** - * Add an HTTP Header to the Request + * Add an HTTP Header to the RequestHttpImpl * * @param key the header name * @param name the header name */ - public void addHeader(final String key, final String value) { - headers.put(key, value); - } + public void addHeader(final String key, final String value); /** * Add a body Parameter (for POST/ PUT Requests) @@ -145,9 +45,7 @@ public void addHeader(final String key, final String value) { * @param key the parameter name * @param name the parameter name */ - public void addBodyParameter(final String key, final String value) { - bodyParams.add(key, value); - } + public void addBodyParameter(final String key, final String value); /** * Add a QueryString parameter @@ -155,9 +53,7 @@ public void addBodyParameter(final String key, final String value) { * @param key the parameter name * @param name the parameter name */ - public void addQuerystringParameter(final String key, final String value) { - querystringParams.add(key, value); - } + public void addQuerystringParameter(final String key, final String value); /** * Add body payload. @@ -169,18 +65,14 @@ public void addQuerystringParameter(final String key, final String value) { * * @param payload the body of the request */ - public void addPayload(final String payload) { - this.payload = payload; - } + // public void addPayload(final String payload); /** * Overloaded version for byte arrays * * @param payload */ - public void addPayload(final byte[] payload) { - bytePayload = (byte[]) payload.clone(); - } + // public void addPayload(final byte[] payload); /** * Get a {@link ParameterList} with the query string parameters. @@ -188,44 +80,28 @@ public void addPayload(final byte[] payload) { * @return a {@link ParameterList} containing the query string parameters. * @throws OAuthException if the request URL is not valid. */ - public ParameterList getQueryStringParams() { - try { - final ParameterList result = new ParameterList(); - final String queryString = new URL(url).getQuery(); - result.addQuerystring(queryString); - result.addAll(querystringParams); - return result; - } catch (final MalformedURLException mue) { - throw new OAuthException("Malformed URL", mue); - } - } + public ParameterList getQueryStringParams(); /** * Obtains a {@link ParameterList} of the body parameters. * * @return a {@link ParameterList}containing the body parameters. */ - public ParameterList getBodyParams() { - return bodyParams; - } + public ParameterList getBodyParams(); /** - * Obtains the URL of the HTTP Request. + * Obtains the URL of the HTTP RequestHttpImpl. * - * @return the original URL of the HTTP Request + * @return the original URL of the HTTP RequestHttpImpl */ - public String getUrl() { - return url; - } + public String getUrl(); /** * Returns the URL without the port and the query string part. * * @return the OAuth-sanitized URL */ - public String getSanitizedUrl() { - return url.replaceAll("\\?.*", "").replace("\\:\\d{4}", ""); - } + // public String getSanitizedUrl(); /** * Returns the body of the request @@ -233,83 +109,35 @@ public String getSanitizedUrl() { * @return form encoded string * @throws OAuthException if the charset chosen is not supported */ - public String getBodyContents() { - try { - return new String(getByteBodyContents(), getCharset()); - } catch (final UnsupportedEncodingException uee) { - throw new OAuthException("Unsupported Charset: " + charset, uee); - } - } - - byte[] getByteBodyContents() { - if (bytePayload != null) { - return bytePayload; - } - final String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString(); - try { - return body.getBytes(getCharset()); - } catch (final UnsupportedEncodingException uee) { - throw new OAuthException("Unsupported Charset: " + getCharset(), uee); - } - } + public String getBodyContents(); /** * Returns the HTTP Verb * * @return the verb */ - public Verb getVerb() { - return verb; - } + public Verb getVerb(); /** * Returns the connection headers as a {@link Map} * * @return map of headers */ - public Map/**/getHeaders() { - return headers; - } + public Map/**/getHeaders(); /** * Returns the connection charset. Defaults to {@link Charset} defaultCharset if not set * * @return charset */ - public String getCharset() { - return charset == null ? Charset.defaultCharset().name() : charset; - } - - /** - * Sets the connect timeout for the underlying {@link HttpURLConnection} - * - * @param duration duration of the timeout - * - * @param unit unit of time (milliseconds, seconds, etc) - */ - public void setConnectTimeout(final int duration, final TimeUnit unit) { - connectTimeout = Long.valueOf(unit.toMillis(duration)); - } - - /** - * Sets the read timeout for the underlying {@link HttpURLConnection} - * - * @param duration duration of the timeout - * - * @param unit unit of time (milliseconds, seconds, etc) - */ - public void setReadTimeout(final int duration, final TimeUnit unit) { - readTimeout = Long.valueOf(unit.toMillis(duration)); - } + // public String getCharset(); /** * Set the charset of the body of the request * * @param charsetName name of the charset of the request */ - public void setCharset(final String charsetName) { - charset = charsetName; - } + // public void setCharset(final String charsetName); /** * Sets whether the underlying Http Connection is persistent or not. @@ -317,9 +145,7 @@ public void setCharset(final String charsetName) { * @see http://download.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html * @param connectionKeepAlive */ - public void setConnectionKeepAlive(final boolean connectionKeepAlive) { - this.connectionKeepAlive = connectionKeepAlive; - } + // public void setConnectionKeepAlive(final boolean connectionKeepAlive); /** * Sets whether the underlying Http Connection follows redirects or not. @@ -329,18 +155,6 @@ public void setConnectionKeepAlive(final boolean connectionKeepAlive) { * @see http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html#setInstanceFollowRedirects(boolean) * @param followRedirects */ - public void setFollowRedirects(final boolean followRedirects) { - this.followRedirects = followRedirects; - } - - /* - * We need this in order to stub the connection object for test cases - */ - void setConnection(final HttpURLConnection connection) { - this.connection = connection; - } + // public void setFollowRedirects(final boolean followRedirects); - public String toString() { - return "@Request(" + String.valueOf(getVerb()) + " " + getUrl() + ")"; - } -} +} \ No newline at end of file diff --git a/src/main/java/org/scribe/model/RequestFactory.java b/src/main/java/org/scribe/model/RequestFactory.java new file mode 100644 index 000000000..ad32360a7 --- /dev/null +++ b/src/main/java/org/scribe/model/RequestFactory.java @@ -0,0 +1,14 @@ +/** + * + */ +package org.scribe.model; + +/** + * @author DMusser + * + */ +public abstract class RequestFactory { + + public abstract Request createRequest(Verb verb, String url); + +} diff --git a/src/main/java/org/scribe/model/RequestHttpImpl.java b/src/main/java/org/scribe/model/RequestHttpImpl.java new file mode 100644 index 000000000..6049e6f39 --- /dev/null +++ b/src/main/java/org/scribe/model/RequestHttpImpl.java @@ -0,0 +1,207 @@ +package org.scribe.model; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.scribe.exceptions.OAuthException; + +/** + * Represents an HTTP RequestHttpImpl object + * + * @author Pablo Fernandez + */ +public class RequestHttpImpl implements Request { + private static final String CONTENT_LENGTH = "Content-Length"; + private static final String CONTENT_TYPE = "Content-Type"; + + private final String url; + private final Verb verb; + private final ParameterList querystringParams; + private final ParameterList bodyParams; + private final Map/**/headers; + private String payload = null; + private String charset; + private byte[] bytePayload = null; + + private final HttpURLConnection connection; + + // private Long connectTimeout = null; + // private Long readTimeout = null; + + /** + * Creates a new Http RequestHttpImpl + * + * @param verb Http Verb (GET, POST, etc) + * @param url url with optional querystring parameters. + */ + public RequestHttpImpl(final HttpURLConnection connection, final Verb verb, final String url) { + super(); + this.connection = connection; + this.verb = verb; + this.url = url; + querystringParams = new ParameterList(); + bodyParams = new ParameterList(); + headers = new HashMap/**/(); + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getCompleteUrl() + */ + public String getCompleteUrl() { + return querystringParams.appendTo(url); + } + + void addHeaders(final HttpURLConnection conn) { + final Iterator i = headers.keySet().iterator(); + while (i.hasNext()) { + final String key = (String) i.next(); + conn.setRequestProperty(key, (String) headers.get(key)); + } + } + + void addBody(final byte[] content) throws IOException { + connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.length)); + + // Set default content type if none is set. + if (connection.getRequestProperty(CONTENT_TYPE) == null) { + connection.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); + } + connection.setDoOutput(true); + connection.getOutputStream().write(content); + } + + public Response send() throws IOException { + final Response response = new ResponseHttpImpl(connection); + return response; + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#addHeader(java.lang.String, java.lang.String) + */ + public void addHeader(final String key, final String value) { + headers.put(key, value); + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#addBodyParameter(java.lang.String, java.lang.String) + */ + public void addBodyParameter(final String key, final String value) { + bodyParams.add(key, value); + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#addQuerystringParameter(java.lang.String, java.lang.String) + */ + public void addQuerystringParameter(final String key, final String value) { + querystringParams.add(key, value); + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#addPayload(java.lang.String) + */ + public void addPayload(final String payload) { + this.payload = payload; + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#addPayload(byte[]) + */ + public void addPayload(final byte[] payload) { + bytePayload = (byte[]) payload.clone(); + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getQueryStringParams() + */ + public ParameterList getQueryStringParams() { + try { + final ParameterList result = new ParameterList(); + final String queryString = new URL(url).getQuery(); + result.addQuerystring(queryString); + result.addAll(querystringParams); + return result; + } catch (final MalformedURLException mue) { + throw new OAuthException("Malformed URL", mue); + } + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getBodyParams() + */ + public ParameterList getBodyParams() { + return bodyParams; + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getUrl() + */ + public String getUrl() { + return url; + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getSanitizedUrl() + */ + public String getSanitizedUrl() { + return StringUtils.replace(StringUtils.replace(url, "\\?.*", ""), "\\:\\d{4}", ""); + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getBodyContents() + */ + public String getBodyContents() { + try { + return new String(getByteBodyContents(), getCharset()); + } catch (final UnsupportedEncodingException uee) { + throw new OAuthException("Unsupported Charset: " + charset, uee); + } + } + + byte[] getByteBodyContents() { + if (bytePayload != null) { + return bytePayload; + } + final String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString(); + try { + return body.getBytes(getCharset()); + } catch (final UnsupportedEncodingException uee) { + throw new OAuthException("Unsupported Charset: " + getCharset(), uee); + } + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getVerb() + */ + public Verb getVerb() { + return verb; + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getHeaders() + */ + public Map/**/getHeaders() { + return headers; + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getCharset() + */ + public String getCharset() { + return charset == null ? Charset.defaultCharset().name() : charset; + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#toString() + */ + public String toString() { + return "@RequestHttpImpl(" + String.valueOf(getVerb()) + " " + getUrl() + ")"; + } +} diff --git a/src/main/java/org/scribe/model/Response.java b/src/main/java/org/scribe/model/Response.java index eb9d25bac..711c28f59 100644 --- a/src/main/java/org/scribe/model/Response.java +++ b/src/main/java/org/scribe/model/Response.java @@ -1,69 +1,25 @@ +/** + * + */ package org.scribe.model; -import java.io.IOException; import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import org.scribe.exceptions.OAuthException; -import org.scribe.utils.StreamUtils; - /** - * Represents an HTTP Response. - * - * @author Pablo Fernandez + * @author DMusser + * */ -public class Response { - - private int code; - private String message; - private String body; - private InputStream stream; - private Map/**/headers; - - Response(final HttpURLConnection connection) throws IOException { - try { - connection.connect(); - code = connection.getResponseCode(); - message = connection.getResponseMessage(); - headers = parseHeaders(connection); - stream = isSuccessful() ? connection.getInputStream() : connection.getErrorStream(); - } catch (final UnknownHostException e) { - throw new OAuthException("The IP address of a host could not be determined.", e); - } - } - - private String parseBodyContents() { - body = StreamUtils.getStreamContents(getStream()); - return body; - } - - private Map/**/parseHeaders(final HttpURLConnection conn) { - final Map/**/headers = new HashMap/**/(); - final Iterator i = conn.getHeaderFields().keySet().iterator(); - while (i.hasNext()) { - final String key = (String) i.next(); - headers.put(key, ((Collection) conn.getHeaderFields().get(key)).toArray()[0]); - } - return headers; - } +public interface Response { - public boolean isSuccessful() { - return getCode() >= 200 && getCode() < 400; - } + public boolean isSuccessful(); /** - * Obtains the HTTP Response body + * Obtains the HTTP ResponseHttpImpl body * * @return response body */ - public String getBody() { - return body != null ? body : parseBodyContents(); - } + public String getBody(); /** * Obtains the meaningful stream of the HttpUrlConnection, either inputStream @@ -71,18 +27,14 @@ public String getBody() { * * @return input stream / error stream */ - public InputStream getStream() { - return stream; - } + public InputStream getStream(); /** * Obtains the HTTP status code * * @return the status code */ - public int getCode() { - return code; - } + public int getCode(); /** * Obtains the HTTP status message. @@ -90,18 +42,14 @@ public int getCode() { * * @return the status message */ - public String getMessage() { - return message; - } + public String getMessage(); /** - * Obtains a {@link Map} containing the HTTP Response Headers + * Obtains a {@link Map} containing the HTTP ResponseHttpImpl Headers * * @return headers */ - public Map/**/getHeaders() { - return headers; - } + public Map/**/getHeaders(); /** * Obtains a single HTTP Header name, or null if undefined @@ -110,8 +58,6 @@ public String getMessage() { * * @return header name or null. */ - public String getHeader(final String name) { - return (String) headers.get(name); - } + public String getHeader(final String name); } \ No newline at end of file diff --git a/src/main/java/org/scribe/model/ResponseHttpImpl.java b/src/main/java/org/scribe/model/ResponseHttpImpl.java new file mode 100644 index 000000000..8d60df56d --- /dev/null +++ b/src/main/java/org/scribe/model/ResponseHttpImpl.java @@ -0,0 +1,104 @@ +package org.scribe.model; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.UnknownHostException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.scribe.exceptions.OAuthException; +import org.scribe.utils.StreamUtils; + +/** + * Represents an HTTP ResponseHttpImpl. + * + * @author Pablo Fernandez + */ +public class ResponseHttpImpl implements Response { + + private int code; + private String message; + private String body; + private InputStream stream; + private Map/**/headers; + + ResponseHttpImpl(final HttpURLConnection connection) throws IOException { + try { + connection.connect(); + code = connection.getResponseCode(); + message = connection.getResponseMessage(); + headers = parseHeaders(connection); + stream = isSuccessful() ? connection.getInputStream() : connection.getErrorStream(); + } catch (final UnknownHostException e) { + throw new OAuthException("The IP address of a host could not be determined.", e); + } + } + + private String parseBodyContents() { + body = StreamUtils.getStreamContents(getStream()); + return body; + } + + private Map/**/parseHeaders(final HttpURLConnection conn) { + final Map/**/headers = new HashMap/**/(); + final Iterator i = conn.getHeaderFields().keySet().iterator(); + while (i.hasNext()) { + final String key = (String) i.next(); + headers.put(key, ((Collection) conn.getHeaderFields().get(key)).toArray()[0]); + } + return headers; + } + + /* (non-Javadoc) + * @see org.scribe.model.Response#isSuccessful() + */ + public boolean isSuccessful() { + return getCode() >= 200 && getCode() < 400; + } + + /* (non-Javadoc) + * @see org.scribe.model.Response#getBody() + */ + public String getBody() { + return body != null ? body : parseBodyContents(); + } + + /* (non-Javadoc) + * @see org.scribe.model.Response#getStream() + */ + public InputStream getStream() { + return stream; + } + + /* (non-Javadoc) + * @see org.scribe.model.Response#getCode() + */ + public int getCode() { + return code; + } + + /* (non-Javadoc) + * @see org.scribe.model.Response#getMessage() + */ + public String getMessage() { + return message; + } + + /* (non-Javadoc) + * @see org.scribe.model.Response#getHeaders() + */ + public Map/**/getHeaders() { + return headers; + } + + /* (non-Javadoc) + * @see org.scribe.model.Response#getHeader(java.lang.String) + */ + public String getHeader(final String name) { + return (String) headers.get(name); + } + +} \ No newline at end of file diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index 57c7e148e..f1a486691 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -1,14 +1,13 @@ package org.scribe.oauth; +import java.io.IOException; import java.util.Iterator; import java.util.Map; -import java.util.concurrent.TimeUnit; import org.scribe.builder.api.DefaultApi10a; import org.scribe.model.OAuthConfig; import org.scribe.model.OAuthConstants; import org.scribe.model.OAuthRequest; -import org.scribe.model.Request; import org.scribe.model.RequestTuner; import org.scribe.model.Response; import org.scribe.model.SignatureType; @@ -39,29 +38,32 @@ public OAuth10aServiceImpl(final DefaultApi10a api, final OAuthConfig config) { this.config = config; } - /** - * {@inheritDoc} - */ - public Token getRequestToken(final int timeout, final TimeUnit unit) { - return getRequestToken(new TimeoutTuner(timeout, unit)); - } - - public Token getRequestToken() { - return getRequestToken(2, TimeUnit.SECONDS); + public Token getRequestToken() throws IOException { + return getRequestToken(null); } - public Token getRequestToken(final RequestTuner tuner) { + public Token getRequestToken(final Map parameters) throws IOException { config.log("obtaining request token from " + api.getRequestTokenEndpoint()); final OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint()); + if (parameters != null && parameters.size() > 0) { + final Iterator i = parameters.keySet().iterator(); + while (i.hasNext()) { + final String key = (String) i.next(); + final String value = (String) parameters.get(key); + if (value != null) { + request.addBodyParameter(key, value); + } + } + } config.log("setting oauth_callback to " + config.getCallback()); request.addOAuthParameter(OAuthConstants.CALLBACK, config.getCallback()); addOAuthParams(request, OAuthConstants.EMPTY_TOKEN); appendSignature(request); config.log("sending request..."); - final Response response = request.send(tuner); + final Response response = request.send(); final String body = response.getBody(); config.log("response status code: " + response.getCode()); @@ -89,17 +91,12 @@ private void addOAuthParams(final OAuthRequest request, final Token token) { /** * {@inheritDoc} */ - public Token getAccessToken(final Token requestToken, final Verifier verifier, - final int timeout, final TimeUnit unit) { - return getAccessToken(requestToken, verifier, new TimeoutTuner(timeout, unit)); - } - public Token getAccessToken(final Token requestToken, final Verifier verifier) { - return getAccessToken(requestToken, verifier, 2, TimeUnit.SECONDS); + return getAccessToken(requestToken, verifier); } public Token getAccessToken(final Token requestToken, final Verifier verifier, - final RequestTuner tuner) { + final RequestTuner tuner) throws IOException { config.log("obtaining access token from " + api.getAccessTokenEndpoint()); final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); @@ -109,22 +106,19 @@ public Token getAccessToken(final Token requestToken, final Verifier verifier, config.log("setting token to: " + requestToken + " and verifier to: " + verifier); addOAuthParams(request, requestToken); appendSignature(request); - final Response response = request.send(tuner); + final Response response = request.send(); return api.getAccessTokenExtractor().extract(response.getBody()); } /** * {@inheritDoc} */ - public Token getAccessToken(final Token requestToken, final int timeout, final TimeUnit unit) { - return getAccessToken(requestToken, new TimeoutTuner(timeout, unit)); - } - public Token getAccessToken(final Token requestToken) { - return getAccessToken(requestToken, 2, TimeUnit.SECONDS); + return getAccessToken(requestToken); } - public Token getAccessToken(final Token requestToken, final RequestTuner tuner) { + public Token getAccessToken(final Token requestToken, final RequestTuner tuner) + throws IOException { config.log("obtaining access token from " + api.getAccessTokenEndpoint()); final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); @@ -133,7 +127,7 @@ public Token getAccessToken(final Token requestToken, final RequestTuner tuner) config.log("setting token to: " + requestToken); addOAuthParams(request, requestToken); appendSignature(request); - final Response response = request.send(tuner); + final Response response = request.send(); return api.getAccessTokenExtractor().extract(response.getBody()); } @@ -141,7 +135,7 @@ public Token getAccessToken(final Token requestToken, final RequestTuner tuner) * {@inheritDoc} */ public void signRequest(final Token token, final OAuthRequest request) { - config.log("signing request: " + request.getCompleteUrl()); + config.log("signing request: " + request.getUrl()); // Do not append the token if empty. This is for two legged OAuth calls. if (!token.isEmpty()) { @@ -194,17 +188,4 @@ private void appendSignature(final OAuthRequest request) { } } - private static class TimeoutTuner extends RequestTuner { - private final int duration; - private final TimeUnit unit; - - public TimeoutTuner(final int duration, final TimeUnit unit) { - this.duration = duration; - this.unit = unit; - } - - public void tune(final Request request) { - request.setReadTimeout(duration, unit); - } - } } diff --git a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java index 9ae5f2646..fb90a48fb 100644 --- a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java @@ -1,5 +1,7 @@ package org.scribe.oauth; +import java.io.IOException; + import org.scribe.builder.api.DefaultApi20; import org.scribe.model.OAuthConfig; import org.scribe.model.OAuthConstants; @@ -27,8 +29,10 @@ public OAuth20ServiceImpl(final DefaultApi20 api, final OAuthConfig config) { /** * {@inheritDoc} + * @throws IOException */ - public Token getAccessToken(final Token requestToken, final Verifier verifier) { + public Token getAccessToken(final Token requestToken, final Verifier verifier) + throws IOException { final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); @@ -73,8 +77,9 @@ public String getAuthorizationUrl(final Token requestToken) { /** * {@inheritDoc} + * @throws IOException */ - public Token getAccessToken(final Token requestToken) { + public Token getAccessToken(final Token requestToken) throws IOException { final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); diff --git a/src/main/java/org/scribe/oauth/OAuthService.java b/src/main/java/org/scribe/oauth/OAuthService.java index cc1f5147c..f219d8b00 100644 --- a/src/main/java/org/scribe/oauth/OAuthService.java +++ b/src/main/java/org/scribe/oauth/OAuthService.java @@ -1,5 +1,7 @@ package org.scribe.oauth; +import java.io.IOException; + import org.scribe.model.OAuthRequest; import org.scribe.model.Token; import org.scribe.model.Verifier; @@ -16,8 +18,9 @@ public interface OAuthService { * Retrieve the request token. * * @return request token + * @throws IOException */ - public Token getRequestToken(); + public Token getRequestToken() throws IOException; /** * Retrieve the access token @@ -25,16 +28,18 @@ public interface OAuthService { * @param requestToken request token (obtained previously) * @param verifier verifier code * @return access token + * @throws IOException */ - public Token getAccessToken(Token requestToken, Verifier verifier); + public Token getAccessToken(Token requestToken, Verifier verifier) throws IOException; /** * Retrieve the access token * * @param requestToken request token (obtained previously) * @return access token + * @throws IOException */ - public Token getAccessToken(Token requestToken); + public Token getAccessToken(Token requestToken) throws IOException; /** * Signs am OAuth request diff --git a/src/main/java/org/scribe/services/DatatypeConverterEncoder.java b/src/main/java/org/scribe/services/DatatypeConverterEncoder.java index 8e7d1a4c9..b99e4a6db 100644 --- a/src/main/java/org/scribe/services/DatatypeConverterEncoder.java +++ b/src/main/java/org/scribe/services/DatatypeConverterEncoder.java @@ -1,18 +1,14 @@ package org.scribe.services; -import javax.xml.bind.*; +import org.apache.commons.codec.binary.Base64; -public class DatatypeConverterEncoder extends Base64Encoder -{ - - public String encode(byte[] bytes) - { - return DatatypeConverter.printBase64Binary(bytes); - } +public class DatatypeConverterEncoder extends Base64Encoder { - - public String getType() - { - return "DatatypeConverter"; - } + public String encode(final byte[] bytes) { + return String.valueOf(Base64.encodeBase64(bytes)); + } + + public String getType() { + return "DatatypeConverter"; + } } diff --git a/src/main/java/org/scribe/services/HMACSha1SignatureService.java b/src/main/java/org/scribe/services/HMACSha1SignatureService.java index 560c2e676..bca26ed44 100644 --- a/src/main/java/org/scribe/services/HMACSha1SignatureService.java +++ b/src/main/java/org/scribe/services/HMACSha1SignatureService.java @@ -1,10 +1,12 @@ package org.scribe.services; -import javax.crypto.*; -import javax.crypto.spec.*; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; -import org.scribe.exceptions.*; -import org.scribe.utils.*; +import org.apache.commons.lang.StringUtils; +import org.scribe.exceptions.OAuthSignatureException; +import org.scribe.utils.OAuthEncoder; +import org.scribe.utils.Preconditions; /** * HMAC-SHA1 implementation of {@SignatureService} @@ -12,50 +14,44 @@ * @author Pablo Fernandez * */ -public class HMACSha1SignatureService implements SignatureService -{ - private static final String EMPTY_STRING = ""; - private static final String CARRIAGE_RETURN = "\r\n"; - private static final String UTF8 = "UTF-8"; - private static final String HMAC_SHA1 = "HmacSHA1"; - private static final String METHOD = "HMAC-SHA1"; +public class HMACSha1SignatureService implements SignatureService { + private static final String EMPTY_STRING = ""; + private static final String CARRIAGE_RETURN = "\r\n"; + private static final String UTF8 = "UTF-8"; + private static final String HMAC_SHA1 = "HmacSHA1"; + private static final String METHOD = "HMAC-SHA1"; - /** - * {@inheritDoc} - */ - public String getSignature(String baseString, String apiSecret, String tokenSecret) - { - try - { - Preconditions.checkEmptyString(baseString, "Base string cant be null or empty string"); - Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string"); - return doSign(baseString, OAuthEncoder.encode(apiSecret) + '&' + OAuthEncoder.encode(tokenSecret)); - } - catch (Exception e) - { - throw new OAuthSignatureException(baseString, e); + /** + * {@inheritDoc} + */ + public String getSignature(final String baseString, final String apiSecret, + final String tokenSecret) { + try { + Preconditions.checkEmptyString(baseString, "Base string cant be null or empty string"); + Preconditions.checkEmptyString(apiSecret, "Api secret cant be null or empty string"); + return doSign(baseString, + OAuthEncoder.encode(apiSecret) + '&' + OAuthEncoder.encode(tokenSecret)); + } catch (final Exception e) { + throw new OAuthSignatureException(baseString, e); + } } - } - private String doSign(String toSign, String keyString) throws Exception - { - SecretKeySpec key = new SecretKeySpec((keyString).getBytes(UTF8), HMAC_SHA1); - Mac mac = Mac.getInstance(HMAC_SHA1); - mac.init(key); - byte[] bytes = mac.doFinal(toSign.getBytes(UTF8)); - return bytesToBase64String(bytes).replace(CARRIAGE_RETURN, EMPTY_STRING); - } + private String doSign(final String toSign, final String keyString) throws Exception { + final SecretKeySpec key = new SecretKeySpec((keyString).getBytes(UTF8), HMAC_SHA1); + final Mac mac = Mac.getInstance(HMAC_SHA1); + mac.init(key); + final byte[] bytes = mac.doFinal(toSign.getBytes(UTF8)); + return StringUtils.replace(bytesToBase64String(bytes), CARRIAGE_RETURN, EMPTY_STRING); + } - private String bytesToBase64String(byte[] bytes) - { - return Base64Encoder.getInstance().encode(bytes); - } + private String bytesToBase64String(final byte[] bytes) { + return Base64Encoder.getInstance().encode(bytes); + } - /** - * {@inheritDoc} - */ - public String getSignatureMethod() - { - return METHOD; - } + /** + * {@inheritDoc} + */ + public String getSignatureMethod() { + return METHOD; + } } diff --git a/src/main/java/org/scribe/utils/OAuthEncoder.java b/src/main/java/org/scribe/utils/OAuthEncoder.java index f0245c560..d4355cfa1 100644 --- a/src/main/java/org/scribe/utils/OAuthEncoder.java +++ b/src/main/java/org/scribe/utils/OAuthEncoder.java @@ -7,8 +7,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; import org.scribe.exceptions.OAuthException; /** @@ -47,7 +47,7 @@ public static String encode(final String plain) { private static String applyRule(final String encoded, final String toReplace, final String replacement) { - return encoded.replaceAll(Pattern.quote(toReplace), replacement); + return StringUtils.replace(encoded, toReplace, replacement); } public static String decode(final String encoded) { diff --git a/src/main/java/org/scribe/utils/Preconditions.java b/src/main/java/org/scribe/utils/Preconditions.java index d4dd1be8c..87ff9096c 100644 --- a/src/main/java/org/scribe/utils/Preconditions.java +++ b/src/main/java/org/scribe/utils/Preconditions.java @@ -1,7 +1,6 @@ package org.scribe.utils; -import java.util.regex.Pattern; - +import org.apache.regexp.REUtil; import org.scribe.model.OAuthConstants; /** @@ -9,80 +8,73 @@ * * @author Pablo Fernandez */ -public class Preconditions -{ - private static final String DEFAULT_MESSAGE = "Received an invalid parameter"; - - // scheme = alpha *( alpha | digit | "+" | "-" | "." ) - private static final Pattern URL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*://\\S+"); +public class Preconditions { + private static final String DEFAULT_MESSAGE = "Received an invalid parameter"; + + // scheme = alpha *( alpha | digit | "+" | "-" | "." ) + private static final String URL_PATTERN = "^[a-zA-Z][a-zA-Z0-9+.-]*://\\S+"; - private Preconditions(){} + private Preconditions() { + } - /** - * Checks that an object is not null. - * - * @param object any object - * @param errorMsg error message - * - * @throws IllegalArgumentException if the object is null - */ - public static void checkNotNull(Object object, String errorMsg) - { - check(object != null, errorMsg); - } + /** + * Checks that an object is not null. + * + * @param object any object + * @param errorMsg error message + * + * @throws IllegalArgumentException if the object is null + */ + public static void checkNotNull(final Object object, final String errorMsg) { + check(object != null, errorMsg); + } - /** - * Checks that a string is not null or empty - * - * @param string any string - * @param errorMsg error message - * - * @throws IllegalArgumentException if the string is null or empty - */ - public static void checkEmptyString(String string, String errorMsg) - { - check(string != null && !string.trim().equals(""), errorMsg); - } + /** + * Checks that a string is not null or empty + * + * @param string any string + * @param errorMsg error message + * + * @throws IllegalArgumentException if the string is null or empty + */ + public static void checkEmptyString(final String string, final String errorMsg) { + check(string != null && !string.trim().equals(""), errorMsg); + } - /** - * Checks that a URL is valid - * - * @param url any string - * @param errorMsg error message - */ - public static void checkValidUrl(String url, String errorMsg) - { - checkEmptyString(url, errorMsg); - check(isUrl(url), errorMsg); - } - - /** - * Checks that a URL is a valid OAuth callback - * - * @param url any string - * @param errorMsg error message - */ - public static void checkValidOAuthCallback(String url, String errorMsg) - { - checkEmptyString(url, errorMsg); - if(url.toLowerCase().compareToIgnoreCase(OAuthConstants.OUT_OF_BAND) != 0) - { - check(isUrl(url), errorMsg); + /** + * Checks that a URL is valid + * + * @param url any string + * @param errorMsg error message + */ + public static void checkValidUrl(final String url, final String errorMsg) { + checkEmptyString(url, errorMsg); + check(isUrl(url), errorMsg); } - } - - private static boolean isUrl(String url) - { - return URL_PATTERN.matcher(url).matches(); - } - - private static void check(boolean requirements, String error) - { - String message = (error == null || error.trim().length() <= 0) ? DEFAULT_MESSAGE : error; - if (!requirements) - { - throw new IllegalArgumentException(message); + + /** + * Checks that a URL is a valid OAuth callback + * + * @param url any string + * @param errorMsg error message + */ + public static void checkValidOAuthCallback(final String url, final String errorMsg) { + checkEmptyString(url, errorMsg); + if (url.toLowerCase().compareToIgnoreCase(OAuthConstants.OUT_OF_BAND) != 0) { + check(isUrl(url), errorMsg); + } } - } - + + private static boolean isUrl(final String url) { + return REUtil.createRE(URL_PATTERN).match(url); + } + + private static void check(final boolean requirements, final String error) { + final String message = (error == null || error.trim().length() <= 0) ? DEFAULT_MESSAGE + : error; + if (!requirements) { + throw new IllegalArgumentException(message); + } + } + } diff --git a/src/main/java/org/scribe/utils/StreamUtils.java b/src/main/java/org/scribe/utils/StreamUtils.java index 30dd8bc54..b6da47ff8 100644 --- a/src/main/java/org/scribe/utils/StreamUtils.java +++ b/src/main/java/org/scribe/utils/StreamUtils.java @@ -1,44 +1,43 @@ package org.scribe.utils; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; /** * Utils to deal with Streams. * * @author Pablo Fernandez */ -public class StreamUtils -{ - private StreamUtils(){} +public class StreamUtils { + private StreamUtils() { + } - /** - * Returns the stream contents as an UTF-8 encoded string - * - * @param is input stream - * @return string contents - */ - public static String getStreamContents(InputStream is) - { - Preconditions.checkNotNull(is, "Cannot get String from a null object"); - try - { - final char[] buffer = new char[0x10000]; - StringBuilder out = new StringBuilder(); - Reader in = new InputStreamReader(is, "UTF-8"); - int read; - do - { - read = in.read(buffer, 0, buffer.length); - if (read > 0) - { - out.append(buffer, 0, read); + /** + * Returns the stream contents as an UTF-8 encoded string + * + * @param is input stream + * @return string contents + */ + public static String getStreamContents(final InputStream is) { + Preconditions.checkNotNull(is, "Cannot get String from a null object"); + try { + final char[] buffer = new char[0x10000]; + final StringBuilder out = new StringBuilder(); + final Reader in = new InputStreamReader(is, "UTF-8"); + int read; + do { + read = in.read(buffer, 0, buffer.length); + if (read > 0) { + out.append(buffer, 0, read); + } + } while (read >= 0); + in.close(); + return out.toString(); + } catch (final IOException ioe) { + ioe.printStackTrace(); + throw new IllegalStateException("Error while reading response body"); } - } while (read >= 0); - in.close(); - return out.toString(); - } catch (IOException ioe) - { - throw new IllegalStateException("Error while reading response body", ioe); } - } } From 0228da2288f1bec3e03ff19f5e03174a73ddd995 Mon Sep 17 00:00:00 2001 From: dphunct Date: Mon, 30 Sep 2013 14:33:59 -0400 Subject: [PATCH 05/11] Update .travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c966b9e63..9b1e4333d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,5 @@ language: java # need to override travis 'install' since it will try gpg sign and fail. -install: mvn clean package -DskipTests=true +#install: mvn clean package -DskipTests=true +install: ant From 13f4efc824651eaf7c53a02d2c2cf043ae17fb6b Mon Sep 17 00:00:00 2001 From: dphunct Date: Mon, 30 Sep 2013 14:37:32 -0400 Subject: [PATCH 06/11] update .travis.yml to use ant to create dist jar --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9b1e4333d..6ca10e807 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,5 +2,4 @@ language: java # need to override travis 'install' since it will try gpg sign and fail. -#install: mvn clean package -DskipTests=true -install: ant +install: ant build From 131a91f87009b8ca12b7db5e65fb3de9b18c24d2 Mon Sep 17 00:00:00 2001 From: Duane Musser Date: Tue, 1 Oct 2013 09:48:33 -0400 Subject: [PATCH 07/11] clean up build; remove extraneous method from Request --- README.textile | 3 +- dist/scribe.jar | Bin 95839 -> 95078 bytes pom.xml | 98 ------------------ .../java/org/scribe/model/OAuthRequest.java | 18 ++-- src/main/java/org/scribe/model/Request.java | 2 +- .../org/scribe/model/RequestHttpImpl.java | 45 ++++---- 6 files changed, 34 insertions(+), 132 deletions(-) delete mode 100644 pom.xml diff --git a/README.textile b/README.textile index efa99cdcb..831d45684 100644 --- a/README.textile +++ b/README.textile @@ -1,6 +1,7 @@ h2. This is a fork of scribe for java 1.4 -I have not changed any functionality. I only updated the code to make it compile with a 1.4 compiler. +I updated the code to make it compile with a 1.4 compiler. +I also abstracted the default java HTTP out so I can rely on a separate HTTP provider in the package. Please see the original product for more information. If you find an issue in my translation of the project, please let me know. thanks! diff --git a/dist/scribe.jar b/dist/scribe.jar index bcf4bcd203ce89c3becd4eed4bbd539118025feb..dbeab31ae943123310a15a0f69dc6b23e1fb68ee 100644 GIT binary patch delta 5933 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 B!i)d_ delta 6368 zcma)Adt6mj_W$mC;hxLkz!gwLK|oZLMAQUce6$k+VGfXAWrcCqE z$xbsp#xcpXRFniCS(=mOjMe!2HTA2;a+;Z@ar*U|nwowy`de$C%jKf}5q!?x>+H4H zcRluFt#d#5#P_4md;<#RSbbE$4$NFPWoN(`YYug3kIL>+l$8hn5zB9Sgh-P8JdrB< zZV{>P79l)E?-nVtzbX>leT1PogekFugn zLgZNdB+E80M6fws5%b^klf?J8$Jr!n>8+FnW^bT>m9AXRdF|36s%Qnj|wZ+akE~TPDuVH#3JbO<*s5X>_YbKUj4dp)%^%yb!;YOQ z9)@nmBWf!VyA(WXhoK@0k16=MiWsc3;}_gN&QeeC>?iGbieG+d$8P5QO2HmGo>q~F z$NVt`d%5Z0<{57Gaq}!UzvN~=H&1YLfSczOJg?xOf)aP%Eu{WYg z!!dO0cW)dM*rVY%zn{QKfhhftN5X<;IV+m$8(TD-!iySCCRpW~#VwApeQ?@l1=k>FhL-dQALZV;8>l*Gv zt%eKujesRFT0=F;1w@<%C(8Bfo0i2^pjbmCH!g0LV}*t)Zfa1jVI|5m)S

!+n=5 zi_>Z41%=2LLy>{0L{9@~J#VA;Ot1HFT4-`#@+chC+c^?6e-_a|5K+09O>LgO=YiO% z`7{;`A8H3v8wNiN!9c>CLnEPt585kpF^_tt7?FG+g!vM|ck{y{Uw>@#0w>R3M7m-~ zdI9OPA_4v=z(PWuOsI>nn8tD?wS=f8k}4z$6qsHO)%Xc+CuAP`DS2ffx(LNm*X##l zGTB<*#UP&tke{qIT4DrwFoJN0j0gK#A~7tW)sz_fA52bXj6f-qO`hkFy|cW$jr8C| zx^VwuFvmX&b$PJY(&eqZ)_c${9`Sl{VXM0w~a_k73lQ1XGVW5nR5@Bv)(H<;hxygIq(RNyIFV>3ExM; z_uo>OPFk<9{@Fu*$$d+{jpVkI+|FCd(YfoDOPg@B(#J^n=Oq02Ersc{yM+@ePz$$( zg!k=_KELQx_o~qUv(4MI=L!8Fp&z~_I$Z>`Ir4N0W>(tGruC5UaS}dx3*iO|ybmc| zMaPpaLkW|)Jt3!WE02;=eB5ocp_}Qb@&*saYC1k}UmOB=$pu`~m+(0cAKHG&H;_}= zh>YcdDGngTp)b5RSZ{bCpzFx48IAzvUD+^s(@{FLNA>G_lawe0;R+)3@g38|Fn!zC zaYnLD1W++>pySf5uKWr5p=XW=RWI9@8y`Zh2)c+uWj~lMERd~3q-8_cGm8Go{?Jwtppthx{OG>g$<4#u=-fQQ4JSaA0xKsNJYwcS ze{+N~p@PT#@dTdq$5WipcH>vv>{0ME5ARjcfoJU4ry>N;+OePC57_Y>_s^?n?Z815 zhj3Uyr;11%VWFdp+QoLgpx|}|$5f0&H#a@ZInK=q1t%4pvg1V+@i=YAOLn}h;tbB( z@rp`zp5x}%toBs}=M}uBVge`l*SWvIp8STWNuVl2!9||;hKe`w7B|1M;}VPi7Z3lp z9dGl?@9lU;!Mh6nN5OktpC4Fb5%2TTb!|UbCT?0Z;}5e%N=yi6@0MnlcLo>m854I$ z7Io#6*D0U#;ttX$9i9?Vj1M$Q3wavn0FAEyB8~FSe2uPzJiYDl5%vWr(CF4J;1oZK z@`;8&;Ie`bHGG6C3jV0!WBf_MpEdjipJ@0iKGna<2$`heZ@8-9?;1WslR%)mn7D1O zt8PVem4^St=K@;q=#m!B>tEoqKCLr$z?b++!`JwSf^Rf@iyD2$t0M`p7?m3SiSIOg z&&9;Q@F^kGIPY>M*SVUL3m47hDR*o5f%EwPG4*f!M}MocIHefZ$oG=Wqk!#gzS5x!s=H`aHl?}CHG(3RK zL< z#AA!}#qW%6#cnRE)tm`X5i#(*&vscs|!YnKH){K@@}Y^_MBlGiwbt*h-^jb}u3BL^6+OY4I<> zj~-h$k^;>X$7Yx%!W5~(EDPz&0_vA0=L(io^Fu7irdZNhYdEtiwXP=32xSR0dDYNBqt-m!4IHZl_wWswTZ45 zoCweC198$8DE9(UJzlCF4Ap~immA~2iEuA3s|cg|M`Ns^?=92IX=E3#hb=zg7%Vrs zS5Jj}gIDZq9?NXz9mrMo8d^%;Cj$ir8@s!DgfIkp|m3w8!;N2BpROtJI%a@4xyk~4y=>G9Zg4iJ;`#wQ{B1* z;g}k@CT0!hhTkfYdTU~?n>jtx%_6Ni`>yv~{g!jv+;d+$HBv5uiTew$xgj1K+ReG7 zqnT{yV2?e8kfQi*q|lSvgK?d6Pa(eO6ebk)U}Es3ZluwkOQ)_IlM{N7__FlMLEjSN zNuK>MYtub6@^mZJQ+uUiJ|jW&8N87~#bFrh2{~QY>>7=AkO{o2=a2^LdDyw@q{ea{ zDtG&2r*>n?+yu6+8yTJRZn91?*t*0Xv`X`0=!#14m}lM<`)N53&;fa#?utXiJxpKQ zozhZ1EQxMQIUsY~md4NxaX&35Zw|Wl-8Lu7cfgkn^u6)&Iv(K_bYD-a{>G-*PVHF}J2nx28d)Dg8BQ$1$}V)Am8(_Zu~z_W~Q_QB2v*4OU3Y!OP%E=v~=N zUfFI;KaLqh1!tMB*-Yn9L-D*(#~WTc5Wn7{F?djDN>WX_dNi~RZL+Q*U6O!P!q#bu3W_gr^~4$17<7c4ee zB{wNlWcf;}DO_Y&1G#ej>ABO|ILc?^RAWOpW#WQ_u%0g>MYbyEO^6d$Oo^~$v047o z)w6e^D3`|e_@#+~(%PQrbTP%$u`ENp;v;28%n<)FWutP%J`?Z4La|hl+_)mqCb`DJ zWg?ADHa=Y@G9?jTD&#M5MoFodC`WdcifNK~r&MG~qO?qe8xzY!ETb9pHbW9mmyu&U z@^LRQ+)1cBQsE>P>)GQJizM-#Q_PXX%yLm|vdYC$Nmwex9g--k5QUOBULlr9!ci$o zC9$f~&AL!2mdlY;mslnV-Q^bl%H>9$zue6_yj=W5+GAfqEH=!wLKI1YCZ_ksJKP_hD0DuKvYHvWhT$_ZNYN+UR!YLjtn;+k}y974gP^MxhPom}p0h+!eG+ z{EX;_^7mk2I0lH3#t#kTG%rQ=*EyCfN)Y^v?l)H-WL#M#LXGJmBEWdISLFwFWc$z| zCM&RB$UDSHsi)D>NOSawfg;T43>P-z5LqPSzLWV+4VQerE)2RZY|;qH{)*Yd6HW1X z@nT3HUm9sl|NL)LsZ`)6rJs>Lsix3}sbX-Skc{$?1_IrYZt|nXi2*n8{Zkz-^uirb`v zwKQP$&!>gTrQmzQa+-&aEfGeWQ-tUR`I_-VZ=4-XBHU+CiNK@9BEraT5}`K3$=T)q E0fHeT>;M1& diff --git a/pom.xml b/pom.xml deleted file mode 100644 index a276ae1bb..000000000 --- a/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - 4.0.0 - org.scribe - scribe - jar - 1.3.5 - Scribe OAuth Library - The best OAuth library out there - http://github.com/fernandezpablo85/scribe-java - - - org.sonatype.oss - oss-parent - 5 - - - - - fernandezpablo85 - Pablo Fernandez - fernandezpablo85@gmail.com - -3 - - - - - - MIT - http://github.com/fernandezpablo85/scribe-java/blob/master/LICENSE.txt - - - - - scm:http://github.com/fernandezpablo85/scribe-java.git - scm:http://github.com/fernandezpablo85/scribe-java.git - http://github.com/fernandezpablo85/scribe-java.git - - - - - junit - junit - 4.8.1 - test - - - commons-codec - commons-codec - 1.4 - compile - true - - - - - - maven-compiler-plugin - 3.0 - - 1.5 - 1.5 - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.4 - - - sign-artifacts - verify - - sign - - - - - - org.codehaus.mojo - findbugs-maven-plugin - 2.5.2 - - - failing-on-high - compile - - check - - - Low - - - - - - - diff --git a/src/main/java/org/scribe/model/OAuthRequest.java b/src/main/java/org/scribe/model/OAuthRequest.java index 653763c46..5c5c36382 100644 --- a/src/main/java/org/scribe/model/OAuthRequest.java +++ b/src/main/java/org/scribe/model/OAuthRequest.java @@ -145,15 +145,15 @@ public String getUrl() { return request.getUrl(); } - /** - * @see org.scribe.model.Request#getBodyContents() - */ - public String getBodyContents() { - if (request == null) { - throw new IllegalAccessError(NOT_INTIALIZED); - } - return request.getBodyContents(); - } + // /** + // * @see org.scribe.model.Request#getBodyContents() + // */ + // public String getBodyContents() { + // if (request == null) { + // throw new IllegalAccessError(NOT_INTIALIZED); + // } + // return request.getBodyContents(); + // } /** * @see org.scribe.model.Request#getVerb() diff --git a/src/main/java/org/scribe/model/Request.java b/src/main/java/org/scribe/model/Request.java index 42c3fcdf6..f63ca0877 100644 --- a/src/main/java/org/scribe/model/Request.java +++ b/src/main/java/org/scribe/model/Request.java @@ -109,7 +109,7 @@ public interface Request { * @return form encoded string * @throws OAuthException if the charset chosen is not supported */ - public String getBodyContents(); + // public String getBodyContents(); /** * Returns the HTTP Verb diff --git a/src/main/java/org/scribe/model/RequestHttpImpl.java b/src/main/java/org/scribe/model/RequestHttpImpl.java index 6049e6f39..4853ee861 100644 --- a/src/main/java/org/scribe/model/RequestHttpImpl.java +++ b/src/main/java/org/scribe/model/RequestHttpImpl.java @@ -1,7 +1,6 @@ package org.scribe.model; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; @@ -154,28 +153,28 @@ public String getSanitizedUrl() { return StringUtils.replace(StringUtils.replace(url, "\\?.*", ""), "\\:\\d{4}", ""); } - /* (non-Javadoc) - * @see org.scribe.model.Request#getBodyContents() - */ - public String getBodyContents() { - try { - return new String(getByteBodyContents(), getCharset()); - } catch (final UnsupportedEncodingException uee) { - throw new OAuthException("Unsupported Charset: " + charset, uee); - } - } - - byte[] getByteBodyContents() { - if (bytePayload != null) { - return bytePayload; - } - final String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString(); - try { - return body.getBytes(getCharset()); - } catch (final UnsupportedEncodingException uee) { - throw new OAuthException("Unsupported Charset: " + getCharset(), uee); - } - } + // /* (non-Javadoc) + // * @see org.scribe.model.Request#getBodyContents() + // */ + // public String getBodyContents() { + // try { + // return new String(getByteBodyContents(), getCharset()); + // } catch (final UnsupportedEncodingException uee) { + // throw new OAuthException("Unsupported Charset: " + charset, uee); + // } + // } + + // byte[] getByteBodyContents() { + // if (bytePayload != null) { + // return bytePayload; + // } + // final String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString(); + // try { + // return body.getBytes(getCharset()); + // } catch (final UnsupportedEncodingException uee) { + // throw new OAuthException("Unsupported Charset: " + getCharset(), uee); + // } + // } /* (non-Javadoc) * @see org.scribe.model.Request#getVerb() From f71299cf3fc81178912bc4f39b488165589e97f9 Mon Sep 17 00:00:00 2001 From: Duane Musser Date: Tue, 1 Oct 2013 10:14:41 -0400 Subject: [PATCH 08/11] fix install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6ca10e807..aafc5b872 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,4 @@ language: java # need to override travis 'install' since it will try gpg sign and fail. -install: ant build +install: true From 5f1515492e8c45731c5848e2e07ba7e1754cf692 Mon Sep 17 00:00:00 2001 From: Duane Musser Date: Tue, 1 Oct 2013 10:33:54 -0400 Subject: [PATCH 09/11] add test target for travis --- build.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.xml b/build.xml index 6c4b01c0a..ef4de3cdd 100644 --- a/build.xml +++ b/build.xml @@ -55,4 +55,6 @@ + + From 89a580f37341929284c4de15120c34e3926f0a12 Mon Sep 17 00:00:00 2001 From: dphunct Date: Tue, 29 Oct 2013 15:07:56 -0400 Subject: [PATCH 10/11] update extractor to parse server info --- dist/scribe.jar | Bin 95078 -> 94458 bytes .../extractors/HeaderExtractorImpl.java | 2 +- .../extractors/TokenExtractor20Impl.java | 28 +++++++------- .../scribe/extractors/TokenExtractorImpl.java | 36 +++++++----------- .../org/scribe/oauth/OAuth10aServiceImpl.java | 36 ++++++------------ 5 files changed, 40 insertions(+), 62 deletions(-) diff --git a/dist/scribe.jar b/dist/scribe.jar index dbeab31ae943123310a15a0f69dc6b23e1fb68ee..9ebea166bfef3852c4cc7b8a637e3fa5e0fcf166 100644 GIT binary patch delta 6396 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 YIqW#TTOZuODb|t>j*pnUNotM%2V^GcYybcN delta 6803 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 1) { - return OAuthEncoder.decode(re.getParen(1)); - } else { - throw new OAuthException( - "ResponseHttpImpl body is incorrect. Can't extract token and secret from this: '" - + response + "'", null); + private static String extract(final String response, final String param) { + final int start = response.indexOf(param + "="); + if (start >= 0) { + int end = response.indexOf("&", start); + if (end < 0) { + end = response.length() - 1; + } + return OAuthEncoder.decode(response.substring(start + param.length() + 1, end)); } + throw new OAuthException( + "ResponseHttpImpl body is incorrect. Can't extract a token from this: '" + response + + "'", null); } + } diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index f1a486691..1b04d3962 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -8,7 +8,6 @@ import org.scribe.model.OAuthConfig; import org.scribe.model.OAuthConstants; import org.scribe.model.OAuthRequest; -import org.scribe.model.RequestTuner; import org.scribe.model.Response; import org.scribe.model.SignatureType; import org.scribe.model.Token; @@ -92,43 +91,30 @@ private void addOAuthParams(final OAuthRequest request, final Token token) { * {@inheritDoc} */ public Token getAccessToken(final Token requestToken, final Verifier verifier) { - return getAccessToken(requestToken, verifier); - } - - public Token getAccessToken(final Token requestToken, final Verifier verifier, - final RequestTuner tuner) throws IOException { config.log("obtaining access token from " + api.getAccessTokenEndpoint()); final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); - request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); - + if (verifier != null) { + request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); + } config.log("setting token to: " + requestToken + " and verifier to: " + verifier); addOAuthParams(request, requestToken); appendSignature(request); - final Response response = request.send(); - return api.getAccessTokenExtractor().extract(response.getBody()); + try { + final Response response = request.send(); + return api.getAccessTokenExtractor().extract(response.getBody()); + } catch (final IOException e) { + e.printStackTrace(); + return null; + } } /** * {@inheritDoc} */ public Token getAccessToken(final Token requestToken) { - return getAccessToken(requestToken); - } - - public Token getAccessToken(final Token requestToken, final RequestTuner tuner) - throws IOException { - config.log("obtaining access token from " + api.getAccessTokenEndpoint()); - final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), - api.getAccessTokenEndpoint()); - request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); - - config.log("setting token to: " + requestToken); - addOAuthParams(request, requestToken); - appendSignature(request); - final Response response = request.send(); - return api.getAccessTokenExtractor().extract(response.getBody()); + return getAccessToken(requestToken, null); } /** From 0457a7215ec0930464a93c5286fb59307bdeedcf Mon Sep 17 00:00:00 2001 From: dphunct Date: Mon, 30 Dec 2013 20:45:55 -0500 Subject: [PATCH 11/11] update tests and code --- dist/scribe.jar | Bin 94458 -> 96039 bytes src/apis/examples/AWeberExample.java | 62 ++++ src/apis/examples/DiggExample.java | 65 +++++ src/apis/examples/FacebookExample.java | 60 ++++ src/apis/examples/FlickrExample.java | 59 ++++ src/apis/examples/Foursquare2Example.java | 59 ++++ src/apis/examples/FoursquareExample.java | 56 ++++ src/apis/examples/FreelancerExample.java | 64 +++++ src/apis/examples/GoogleExample.java | 61 ++++ src/apis/examples/ImgUrExample.java | 58 ++++ src/apis/examples/Kaixin20Example.java | 60 ++++ src/apis/examples/LinkedInExample.java | 57 ++++ .../examples/LinkedInExampleWithScopes.java | 58 ++++ src/apis/examples/LiveExample.java | 59 ++++ .../examples/LoveFilmExample.java | 128 ++++----- .../examples/MeetupExample.java | 124 ++++---- .../examples/NeteaseWeiboExample.java | 136 ++++----- .../examples/Px500Example.java | 118 ++++---- .../examples/RenrenExample.java | 216 +++++++------- .../examples/SinaWeibo2Example.java | 126 ++++---- .../examples/SinaWeiboExample.java | 136 ++++----- .../examples/SkyrockExample.java | 122 ++++---- .../examples/SohuWeiboExample.java | 136 ++++----- .../examples/TrelloExample.java | 120 ++++---- .../examples/TwitterExample.java | 120 ++++---- .../examples/ViadeoExample.java | 128 ++++----- .../examples/VkontakteExample.java | 136 ++++----- .../scribe => apis}/examples/XingExample.java | 118 ++++---- .../examples/YahooExample.java | 120 ++++---- .../org/scribe/builder/ServiceBuilder.java | 13 +- .../scribe/extractors/TokenExtractorImpl.java | 2 +- .../java/org/scribe/model/OAuthConfig.java | 130 +++++---- .../java/org/scribe/model/OAuthRequest.java | 59 ++-- src/main/java/org/scribe/model/Request.java | 270 +++++++----------- .../java/org/scribe/model/RequestFactory.java | 14 - .../org/scribe/model/RequestHttpImpl.java | 85 ++---- .../org/scribe/oauth/OAuth10aServiceImpl.java | 22 +- .../org/scribe/oauth/OAuth20ServiceImpl.java | 8 +- .../scribe/builder/ServiceBuilderTest.java | 143 +++++----- .../org/scribe/examples/AWeberExample.java | 65 ----- .../java/org/scribe/examples/DiggExample.java | 65 ----- .../org/scribe/examples/FacebookExample.java | 64 ----- .../org/scribe/examples/FlickrExample.java | 59 ---- .../scribe/examples/Foursquare2Example.java | 63 ---- .../scribe/examples/FoursquareExample.java | 59 ---- .../scribe/examples/FreelancerExample.java | 66 ----- .../org/scribe/examples/GoogleExample.java | 66 ----- .../org/scribe/examples/ImgUrExample.java | 58 ---- .../org/scribe/examples/Kaixin20Example.java | 63 ---- .../org/scribe/examples/LinkedInExample.java | 59 ---- .../examples/LinkedInExampleWithScopes.java | 59 ---- .../java/org/scribe/examples/LiveExample.java | 64 ----- .../extractors/BaseStringExtractorTest.java | 103 ++++--- .../extractors/HeaderExtractorTest.java | 90 +++--- .../java/org/scribe/model/ConnectionStub.java | 160 +++++------ .../org/scribe/model/OAuthRequestTest.java | 66 +++-- .../org/scribe/model/ParameterListTest.java | 174 ++++++----- .../java/org/scribe/model/RequestTest.java | 251 ++++++++-------- .../java/org/scribe/model/ResponseTest.java | 141 +++++---- .../services/RSASha1SignatureServiceTest.java | 67 ----- .../scribe/services/TimestampServiceTest.java | 92 +++--- .../org/scribe/test/helpers/ObjectMother.java | 36 +-- 62 files changed, 2636 insertions(+), 2862 deletions(-) create mode 100644 src/apis/examples/AWeberExample.java create mode 100644 src/apis/examples/DiggExample.java create mode 100644 src/apis/examples/FacebookExample.java create mode 100644 src/apis/examples/FlickrExample.java create mode 100644 src/apis/examples/Foursquare2Example.java create mode 100644 src/apis/examples/FoursquareExample.java create mode 100644 src/apis/examples/FreelancerExample.java create mode 100644 src/apis/examples/GoogleExample.java create mode 100644 src/apis/examples/ImgUrExample.java create mode 100644 src/apis/examples/Kaixin20Example.java create mode 100644 src/apis/examples/LinkedInExample.java create mode 100644 src/apis/examples/LinkedInExampleWithScopes.java create mode 100644 src/apis/examples/LiveExample.java rename src/{test/java/org/scribe => apis}/examples/LoveFilmExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/MeetupExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/NeteaseWeiboExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/Px500Example.java (97%) rename src/{test/java/org/scribe => apis}/examples/RenrenExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/SinaWeibo2Example.java (97%) rename src/{test/java/org/scribe => apis}/examples/SinaWeiboExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/SkyrockExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/SohuWeiboExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/TrelloExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/TwitterExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/ViadeoExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/VkontakteExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/XingExample.java (97%) rename src/{test/java/org/scribe => apis}/examples/YahooExample.java (97%) delete mode 100644 src/main/java/org/scribe/model/RequestFactory.java delete mode 100644 src/test/java/org/scribe/examples/AWeberExample.java delete mode 100644 src/test/java/org/scribe/examples/DiggExample.java delete mode 100644 src/test/java/org/scribe/examples/FacebookExample.java delete mode 100644 src/test/java/org/scribe/examples/FlickrExample.java delete mode 100644 src/test/java/org/scribe/examples/Foursquare2Example.java delete mode 100644 src/test/java/org/scribe/examples/FoursquareExample.java delete mode 100644 src/test/java/org/scribe/examples/FreelancerExample.java delete mode 100644 src/test/java/org/scribe/examples/GoogleExample.java delete mode 100644 src/test/java/org/scribe/examples/ImgUrExample.java delete mode 100644 src/test/java/org/scribe/examples/Kaixin20Example.java delete mode 100644 src/test/java/org/scribe/examples/LinkedInExample.java delete mode 100644 src/test/java/org/scribe/examples/LinkedInExampleWithScopes.java delete mode 100644 src/test/java/org/scribe/examples/LiveExample.java delete mode 100644 src/test/java/org/scribe/services/RSASha1SignatureServiceTest.java diff --git a/dist/scribe.jar b/dist/scribe.jar index 9ebea166bfef3852c4cc7b8a637e3fa5e0fcf166..2f26e7bf9fdf4d3dd5a9e5ac83267061e75f89e4 100644 GIT binary patch delta 15472 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 CgB1_} delta 14174 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 WdYSGkM09i!718nT;QexRnEnrCpc*&; diff --git a/src/apis/examples/AWeberExample.java b/src/apis/examples/AWeberExample.java new file mode 100644 index 000000000..667efca0b --- /dev/null +++ b/src/apis/examples/AWeberExample.java @@ -0,0 +1,62 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class AWeberExample { + + //To get your consumer key/secret, and view API docs, see https://labs.aweber.com/docs + private static final String ACCOUNT_RESOURCE_URL = "https://api.aweber.com/1.0/accounts/"; + + private static final String CONSUMER_KEY = ""; + private static final String CONSUMER_SECRET = ""; + + public static void main(final String[] args) { + final OAuthService service = new ServiceBuilder().provider(AWeberApi.class) + .apiKey(CONSUMER_KEY).apiSecret(CONSUMER_SECRET).build(); + + final Scanner in = new Scanner(System.in); + + System.out.println("=== AWeber's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, ACCOUNT_RESOURCE_URL); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out + .println("Thats it man! Go and build something awesome with AWeber and Scribe! :)"); + } + +} \ No newline at end of file diff --git a/src/apis/examples/DiggExample.java b/src/apis/examples/DiggExample.java new file mode 100644 index 000000000..63a70f09d --- /dev/null +++ b/src/apis/examples/DiggExample.java @@ -0,0 +1,65 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class DiggExample { + private static final String NETWORK_NAME = "Digg"; + private static final String PROTECTED_RESOURCE_URL = "http://services.digg.com/2.0/comment.digg"; + + public static void main(final String[] args) { + // Replace these with your own api key and secret + final String apiKey = "myKey"; + final String apiSecret = "mySecret"; + final OAuthService service = new ServiceBuilder().provider(DiggApi.class).apiKey(apiKey) + .apiSecret(apiSecret).build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(requestToken); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL); + request.addBodyParameter("comment_id", "20100729223726:4fef610331ee46a3b5cbd740bf71313e"); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} \ No newline at end of file diff --git a/src/apis/examples/FacebookExample.java b/src/apis/examples/FacebookExample.java new file mode 100644 index 000000000..4f28362e5 --- /dev/null +++ b/src/apis/examples/FacebookExample.java @@ -0,0 +1,60 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class FacebookExample { + private static final String NETWORK_NAME = "Facebook"; + private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/me"; + private static final Token EMPTY_TOKEN = null; + + public static void main(final String[] args) { + // Replace these with your own api key and secret + final String apiKey = "your_app_id"; + final String apiSecret = "your_api_secret"; + final OAuthService service = new ServiceBuilder().provider(FacebookApi.class) + .apiKey(apiKey).apiSecret(apiSecret) + .callback("http://www.example.com/oauth_callback/").build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} \ No newline at end of file diff --git a/src/apis/examples/FlickrExample.java b/src/apis/examples/FlickrExample.java new file mode 100644 index 000000000..232d1f67c --- /dev/null +++ b/src/apis/examples/FlickrExample.java @@ -0,0 +1,59 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class FlickrExample { + private static final String PROTECTED_RESOURCE_URL = "http://api.flickr.com/services/rest/"; + + public static void main(final String[] args) { + // Replace these with your own api key and secret + final String apiKey = "your_app_id"; + final String apiSecret = "your_api_secret"; + final OAuthService service = new ServiceBuilder().provider(FlickrApi.class).apiKey(apiKey) + .apiSecret(apiSecret).build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== Flickr's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + final String authorizationUrl = service.getAuthorizationUrl(requestToken); + System.out.println(authorizationUrl + "&perms=read"); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + request.addQuerystringParameter("method", "flickr.test.login"); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } +} diff --git a/src/apis/examples/Foursquare2Example.java b/src/apis/examples/Foursquare2Example.java new file mode 100644 index 000000000..9c3056a90 --- /dev/null +++ b/src/apis/examples/Foursquare2Example.java @@ -0,0 +1,59 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class Foursquare2Example { + private static final String PROTECTED_RESOURCE_URL = "https://api.foursquare.com/v2/users/self/friends?oauth_token="; + private static final Token EMPTY_TOKEN = null; + + public static void main(final String[] args) { + // Replace these with your own api key and secret + final String apiKey = "FEGFXJUFANVVDHVSNUAMUKTTXCP1AJQD53E33XKJ44YP1S4I"; + final String apiSecret = "AYWKUL5SWPNC0CTQ202QXRUG2NLZYXMRA34ZSDW4AUYBG2RC"; + final OAuthService service = new ServiceBuilder().provider(Foursquare2Api.class) + .apiKey(apiKey).apiSecret(apiSecret).callback("http://localhost:9000/").build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== Foursquare2's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL + + accessToken.getToken()); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} diff --git a/src/apis/examples/FoursquareExample.java b/src/apis/examples/FoursquareExample.java new file mode 100644 index 000000000..65b661a95 --- /dev/null +++ b/src/apis/examples/FoursquareExample.java @@ -0,0 +1,56 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class FoursquareExample { + private static final String PROTECTED_RESOURCE_URL = "http://api.foursquare.com/v1/user"; + + public static void main(final String[] args) { + final OAuthService service = new ServiceBuilder().provider(FoursquareApi.class) + .apiKey("FEGFXJUFANVVDHVSNUAMUKTTXCP1AJQD53E33XKJ44YP1S4I") + .apiSecret("AYWKUL5SWPNC0CTQ202QXRUG2NLZYXMRA34ZSDW4AUYBG2RC").build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== Foursquare's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } + +} \ No newline at end of file diff --git a/src/apis/examples/FreelancerExample.java b/src/apis/examples/FreelancerExample.java new file mode 100644 index 000000000..cb522f5c2 --- /dev/null +++ b/src/apis/examples/FreelancerExample.java @@ -0,0 +1,64 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.SignatureType; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class FreelancerExample { + + private static final String NETWORK_NAME = "Freelancer"; + private static final String AUTHORIZE_URL = "http://www.sandbox.freelancer.com/users/api-token/auth.php?oauth_token="; + private static final String PROTECTED_RESOURCE_URL = "http://api.sandbox.freelancer.com/Job/getJobList.json"; + private static final String SCOPE = "http://api.sandbox.freelancer.com"; + + public static void main(final String[] args) { + final OAuthService service = new ServiceBuilder().provider(FreelancerApi.Sandbox.class) + .signatureType(SignatureType.QueryString) + .apiKey("7f5a168a0bfdbd15b4a9ea2a969661c731cdea56") + .apiSecret("7bb8961b94873802f1c5344f671a518e087f5785").scope(SCOPE).build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println("(if your curious it looks like this: " + requestToken + " )"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(AUTHORIZE_URL + requestToken.getToken()); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + request.addHeader("GData-Version", "3.0"); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } +} diff --git a/src/apis/examples/GoogleExample.java b/src/apis/examples/GoogleExample.java new file mode 100644 index 000000000..f2b7264e0 --- /dev/null +++ b/src/apis/examples/GoogleExample.java @@ -0,0 +1,61 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class GoogleExample { + private static final String NETWORK_NAME = "Google"; + private static final String AUTHORIZE_URL = "https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token="; + private static final String PROTECTED_RESOURCE_URL = "https://docs.google.com/feeds/default/private/full/"; + private static final String SCOPE = "https://docs.google.com/feeds/"; + + public static void main(final String[] args) { + final OAuthService service = new ServiceBuilder().provider(GoogleApi.class) + .apiKey("anonymous").apiSecret("anonymous").scope(SCOPE).build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println("(if your curious it looks like this: " + requestToken + " )"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(AUTHORIZE_URL + requestToken.getToken()); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + request.addHeader("GData-Version", "3.0"); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} \ No newline at end of file diff --git a/src/apis/examples/ImgUrExample.java b/src/apis/examples/ImgUrExample.java new file mode 100644 index 000000000..5e784cc85 --- /dev/null +++ b/src/apis/examples/ImgUrExample.java @@ -0,0 +1,58 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class ImgUrExample { + private static final String PROTECTED_RESOURCE_URL = "http://api.imgur.com/2/account.json"; + + public static void main(final String[] args) { + // Replace these with your own api key and secret (you'll need an read/write api key) + final String apiKey = "your_app_id"; + final String apiSecret = "your_api_secret"; + final OAuthService service = new ServiceBuilder().provider(ImgUrApi.class).apiKey(apiKey) + .apiSecret(apiSecret).build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== ImgUr's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + final String authorizationUrl = service.getAuthorizationUrl(requestToken); + System.out.println(authorizationUrl); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } +} diff --git a/src/apis/examples/Kaixin20Example.java b/src/apis/examples/Kaixin20Example.java new file mode 100644 index 000000000..cdef9b0b1 --- /dev/null +++ b/src/apis/examples/Kaixin20Example.java @@ -0,0 +1,60 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class Kaixin20Example { + private static final String NETWORK_NAME = "Kaixin"; + private static final String PROTECTED_RESOURCE_URL = "https://api.kaixin001.com/users/me.json"; + private static final Token EMPTY_TOKEN = null; + + public static void main(final String[] args) { + // Replace these with your own api key and secret + final String apiKey = "your api key"; + final String apiSecret = "your api secret"; + final OAuthService service = new ServiceBuilder().provider(KaixinApi20.class) + .apiKey(apiKey).apiSecret(apiSecret).callback("http://your.domain.com/handle") + .build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verifier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} diff --git a/src/apis/examples/LinkedInExample.java b/src/apis/examples/LinkedInExample.java new file mode 100644 index 000000000..3cf2cba5a --- /dev/null +++ b/src/apis/examples/LinkedInExample.java @@ -0,0 +1,57 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class LinkedInExample { + private static final String PROTECTED_RESOURCE_URL = "http://api.linkedin.com/v1/people/~/connections:(id,last-name)"; + + public static void main(final String[] args) { + final OAuthService service = new ServiceBuilder().provider(LinkedInApi.class) + .apiKey("CiEgwWDkA5BFpNrc0RfGyVuSlOh4tig5kOTZ9q97qcXNrFl7zqk-Ts7DqRGaKDCV") + .apiSecret("dhho4dfoCmiQXrkw4yslork5XWLFnPSuMR-8gscPVjY4jqFFHPYWJKgpFl4uLTM6") + .build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== LinkedIn's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } + +} diff --git a/src/apis/examples/LinkedInExampleWithScopes.java b/src/apis/examples/LinkedInExampleWithScopes.java new file mode 100644 index 000000000..70d7113cf --- /dev/null +++ b/src/apis/examples/LinkedInExampleWithScopes.java @@ -0,0 +1,58 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class LinkedInExampleWithScopes { + private static final String PROTECTED_RESOURCE_URL = "http://api.linkedin.com/v1/people/~/connections:(id,last-name)"; + + public static void main(final String[] args) { + final OAuthService service = new ServiceBuilder() + .provider(LinkedInApi.withScopes("foo", "bar", "baz")) + .apiKey("CiEgwWDkA5BFpNrc0RfGyVuSlOh4tig5kOTZ9q97qcXNrFl7zqk-Ts7DqRGaKDCV") + .apiSecret("dhho4dfoCmiQXrkw4yslork5XWLFnPSuMR-8gscPVjY4jqFFHPYWJKgpFl4uLTM6") + .build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== LinkedIn's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + final Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } + +} diff --git a/src/apis/examples/LiveExample.java b/src/apis/examples/LiveExample.java new file mode 100644 index 000000000..d5683999c --- /dev/null +++ b/src/apis/examples/LiveExample.java @@ -0,0 +1,59 @@ +package org.scribe.examples; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class LiveExample { + private static final String PROTECTED_RESOURCE_URL = "https://api.foursquare.com/v2/users/self/friends?oauth_token="; + private static final Token EMPTY_TOKEN = null; + + public static void main(final String[] args) { + // Replace these with your own api key and secret + final String apiKey = ""; + final String apiSecret = ""; + final OAuthService service = new ServiceBuilder().provider(LiveApi.class).apiKey(apiKey) + .apiSecret(apiSecret).scope("wl.basic").callback("http://localhost:9000/").build(); + final Scanner in = new Scanner(System.in); + + System.out.println("=== Windows Live's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + final Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + final Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL + + accessToken.getToken()); + service.signRequest(accessToken, request); + final Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} diff --git a/src/test/java/org/scribe/examples/LoveFilmExample.java b/src/apis/examples/LoveFilmExample.java similarity index 97% rename from src/test/java/org/scribe/examples/LoveFilmExample.java rename to src/apis/examples/LoveFilmExample.java index 9e800161e..e94057133 100644 --- a/src/test/java/org/scribe/examples/LoveFilmExample.java +++ b/src/apis/examples/LoveFilmExample.java @@ -1,64 +1,64 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class LoveFilmExample -{ - private static final String NETWORK_NAME = "LoveFilm"; - private static final String PROTECTED_RESOURCE_URL = "https://api.lovefilm.com/users"; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your_key"; - String apiSecret = "your_secret"; - OAuthService service = new ServiceBuilder().provider(LoveFilmApi.class).apiKey(apiKey).apiSecret(apiSecret).build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Grab a request token. - System.out.println("Fetching request token."); - Token requestToken = service.getRequestToken(); - System.out.println("Got it ... "); - System.out.println(requestToken.getToken()); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(requestToken); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} +package org.scribe.examples; + +import java.util.*; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class LoveFilmExample +{ + private static final String NETWORK_NAME = "LoveFilm"; + private static final String PROTECTED_RESOURCE_URL = "https://api.lovefilm.com/users"; + + public static void main(String[] args) + { + // Replace these with your own api key and secret + String apiKey = "your_key"; + String apiSecret = "your_secret"; + OAuthService service = new ServiceBuilder().provider(LoveFilmApi.class).apiKey(apiKey).apiSecret(apiSecret).build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Grab a request token. + System.out.println("Fetching request token."); + Token requestToken = service.getRequestToken(); + System.out.println("Got it ... "); + System.out.println(requestToken.getToken()); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + String authorizationUrl = service.getAuthorizationUrl(requestToken); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} diff --git a/src/test/java/org/scribe/examples/MeetupExample.java b/src/apis/examples/MeetupExample.java similarity index 97% rename from src/test/java/org/scribe/examples/MeetupExample.java rename to src/apis/examples/MeetupExample.java index 2185b5c27..1331c4588 100644 --- a/src/test/java/org/scribe/examples/MeetupExample.java +++ b/src/apis/examples/MeetupExample.java @@ -1,62 +1,62 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.ServiceBuilder; -import org.scribe.builder.api.MeetupApi; -import org.scribe.model.OAuthRequest; -import org.scribe.model.Response; -import org.scribe.model.Token; -import org.scribe.model.Verb; -import org.scribe.model.Verifier; -import org.scribe.oauth.OAuthService; - -public class MeetupExample -{ - private static final String PROTECTED_RESOURCE_URL = "http://api.meetup.com/2/member/self"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(MeetupApi.class) - .apiKey("j1khkp0dus323ftve0sdcv6ffe") - .apiSecret("6s6gt6q59gvfjtsvgcmht62gq4") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Meetup's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } -} +package org.scribe.examples; + +import java.util.Scanner; + +import org.scribe.builder.ServiceBuilder; +import org.scribe.builder.api.MeetupApi; +import org.scribe.model.OAuthRequest; +import org.scribe.model.Response; +import org.scribe.model.Token; +import org.scribe.model.Verb; +import org.scribe.model.Verifier; +import org.scribe.oauth.OAuthService; + +public class MeetupExample +{ + private static final String PROTECTED_RESOURCE_URL = "http://api.meetup.com/2/member/self"; + + public static void main(String[] args) + { + OAuthService service = new ServiceBuilder() + .provider(MeetupApi.class) + .apiKey("j1khkp0dus323ftve0sdcv6ffe") + .apiSecret("6s6gt6q59gvfjtsvgcmht62gq4") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== Meetup's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } +} diff --git a/src/test/java/org/scribe/examples/NeteaseWeiboExample.java b/src/apis/examples/NeteaseWeiboExample.java similarity index 97% rename from src/test/java/org/scribe/examples/NeteaseWeiboExample.java rename to src/apis/examples/NeteaseWeiboExample.java index e65335e76..63a64ab91 100644 --- a/src/test/java/org/scribe/examples/NeteaseWeiboExample.java +++ b/src/apis/examples/NeteaseWeiboExample.java @@ -1,68 +1,68 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class NeteaseWeiboExample -{ - private static final String NETWORK_NAME = "NetEase(163.com) Weibo"; - private static final String PROTECTED_RESOURCE_URL = "http://api.t.163.com/account/verify_credentials.json"; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your key"; - String apiSecret = "your secret"; - OAuthService service = new ServiceBuilder() - .provider(NeteaseWeibooApi.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Grab a request token. - System.out.println("Fetching request token."); - Token requestToken = service.getRequestToken(); - System.out.println("Got it ... "); - System.out.println(requestToken.getToken()); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(requestToken); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " - + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } -} +package org.scribe.examples; + +import java.util.*; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class NeteaseWeiboExample +{ + private static final String NETWORK_NAME = "NetEase(163.com) Weibo"; + private static final String PROTECTED_RESOURCE_URL = "http://api.t.163.com/account/verify_credentials.json"; + + public static void main(String[] args) + { + // Replace these with your own api key and secret + String apiKey = "your key"; + String apiSecret = "your secret"; + OAuthService service = new ServiceBuilder() + .provider(NeteaseWeibooApi.class) + .apiKey(apiKey) + .apiSecret(apiSecret) + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Grab a request token. + System.out.println("Fetching request token."); + Token requestToken = service.getRequestToken(); + System.out.println("Got it ... "); + System.out.println(requestToken.getToken()); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + String authorizationUrl = service.getAuthorizationUrl(requestToken); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } +} diff --git a/src/test/java/org/scribe/examples/Px500Example.java b/src/apis/examples/Px500Example.java similarity index 97% rename from src/test/java/org/scribe/examples/Px500Example.java rename to src/apis/examples/Px500Example.java index cdbe44997..8e7710764 100644 --- a/src/test/java/org/scribe/examples/Px500Example.java +++ b/src/apis/examples/Px500Example.java @@ -1,60 +1,60 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class Px500Example -{ - private static final String PROTECTED_RESOURCE_URL = "https://api.500px.com/v1/"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(Px500Api.class) - .apiKey("your-api-key") - .apiSecret("your-api-secret") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== 500Px's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } - +package org.scribe.examples; + +import java.util.Scanner; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class Px500Example +{ + private static final String PROTECTED_RESOURCE_URL = "https://api.500px.com/v1/"; + + public static void main(String[] args) + { + OAuthService service = new ServiceBuilder() + .provider(Px500Api.class) + .apiKey("your-api-key") + .apiSecret("your-api-secret") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== 500Px's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } + } \ No newline at end of file diff --git a/src/test/java/org/scribe/examples/RenrenExample.java b/src/apis/examples/RenrenExample.java similarity index 97% rename from src/test/java/org/scribe/examples/RenrenExample.java rename to src/apis/examples/RenrenExample.java index ae13375b8..e45233687 100644 --- a/src/test/java/org/scribe/examples/RenrenExample.java +++ b/src/apis/examples/RenrenExample.java @@ -1,108 +1,108 @@ -package org.scribe.examples; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; -import java.nio.charset.*; -import java.security.*; -import java.util.*; - -public class RenrenExample -{ - private static final String NETWORK_NAME = "Renren"; - private static final String PROTECTED_RESOURCE_URL = "http://api.renren.com/restserver.do"; - private static final Token EMPTY_TOKEN = null; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your api key"; - String apiSecret = "your api secret"; - OAuthService service = new ServiceBuilder() - .provider(RenrenApi.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .scope("status_update publish_feed") - .callback("http://your.doman.com/oauth/renren") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL); - Map parameters = new HashMap(); - parameters.put("method", "users.getInfo"); - parameters.put("format", "json"); - parameters.put("v", "1.0"); - - List sigString = new ArrayList(parameters.size() + 1); - for (Map.Entry entry : parameters.entrySet()) - { - request.addQuerystringParameter(entry.getKey(), entry.getValue()); - sigString.add(String.format("%s=%s", entry.getKey(), entry.getValue())); - } - sigString.add(String.format("%s=%s", OAuthConstants.ACCESS_TOKEN, accessToken.getToken())); - Collections.sort(sigString); - StringBuilder b = new StringBuilder(); - for (String param : sigString) - { - b.append(param); - } - b.append(apiSecret); - System.out.println("Sig string: " + b.toString()); - request.addQuerystringParameter("sig", md5(b.toString())); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } - - public static String md5(String orgString) - { - try - { - java.security.MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] array = md.digest(orgString.getBytes(Charset.forName("UTF-8"))); - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < array.length; ++i) - { - sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); - } - return sb.toString(); - } - catch (NoSuchAlgorithmException e) - { - e.printStackTrace(); - } - return null; - } - -} +package org.scribe.examples; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; +import java.nio.charset.*; +import java.security.*; +import java.util.*; + +public class RenrenExample +{ + private static final String NETWORK_NAME = "Renren"; + private static final String PROTECTED_RESOURCE_URL = "http://api.renren.com/restserver.do"; + private static final Token EMPTY_TOKEN = null; + + public static void main(String[] args) + { + // Replace these with your own api key and secret + String apiKey = "your api key"; + String apiSecret = "your api secret"; + OAuthService service = new ServiceBuilder() + .provider(RenrenApi.class) + .apiKey(apiKey) + .apiSecret(apiSecret) + .scope("status_update publish_feed") + .callback("http://your.doman.com/oauth/renren") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL); + Map parameters = new HashMap(); + parameters.put("method", "users.getInfo"); + parameters.put("format", "json"); + parameters.put("v", "1.0"); + + List sigString = new ArrayList(parameters.size() + 1); + for (Map.Entry entry : parameters.entrySet()) + { + request.addQuerystringParameter(entry.getKey(), entry.getValue()); + sigString.add(String.format("%s=%s", entry.getKey(), entry.getValue())); + } + sigString.add(String.format("%s=%s", OAuthConstants.ACCESS_TOKEN, accessToken.getToken())); + Collections.sort(sigString); + StringBuilder b = new StringBuilder(); + for (String param : sigString) + { + b.append(param); + } + b.append(apiSecret); + System.out.println("Sig string: " + b.toString()); + request.addQuerystringParameter("sig", md5(b.toString())); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } + + public static String md5(String orgString) + { + try + { + java.security.MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] array = md.digest(orgString.getBytes(Charset.forName("UTF-8"))); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < array.length; ++i) + { + sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString(); + } + catch (NoSuchAlgorithmException e) + { + e.printStackTrace(); + } + return null; + } + +} diff --git a/src/test/java/org/scribe/examples/SinaWeibo2Example.java b/src/apis/examples/SinaWeibo2Example.java similarity index 97% rename from src/test/java/org/scribe/examples/SinaWeibo2Example.java rename to src/apis/examples/SinaWeibo2Example.java index 89b14e117..01f926d73 100644 --- a/src/test/java/org/scribe/examples/SinaWeibo2Example.java +++ b/src/apis/examples/SinaWeibo2Example.java @@ -1,63 +1,63 @@ -package org.scribe.examples; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; -import java.util.*; - -public class SinaWeibo2Example -{ - private static final String NETWORK_NAME = "SinaWeibo"; - private static final String PROTECTED_RESOURCE_URL = "https://api.weibo.com/2/account/get_uid.json"; - private static final Token EMPTY_TOKEN = null; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your_api_key"; - String apiSecret = "your_api_secret"; - OAuthService service = new ServiceBuilder() - .provider(SinaWeiboApi20.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .callback("http://www.dajie.com/oauth/sina") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verifier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} +package org.scribe.examples; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; +import java.util.*; + +public class SinaWeibo2Example +{ + private static final String NETWORK_NAME = "SinaWeibo"; + private static final String PROTECTED_RESOURCE_URL = "https://api.weibo.com/2/account/get_uid.json"; + private static final Token EMPTY_TOKEN = null; + + public static void main(String[] args) + { + // Replace these with your own api key and secret + String apiKey = "your_api_key"; + String apiSecret = "your_api_secret"; + OAuthService service = new ServiceBuilder() + .provider(SinaWeiboApi20.class) + .apiKey(apiKey) + .apiSecret(apiSecret) + .callback("http://www.dajie.com/oauth/sina") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verifier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} diff --git a/src/test/java/org/scribe/examples/SinaWeiboExample.java b/src/apis/examples/SinaWeiboExample.java similarity index 97% rename from src/test/java/org/scribe/examples/SinaWeiboExample.java rename to src/apis/examples/SinaWeiboExample.java index 2dc4b7c04..6b9401635 100644 --- a/src/test/java/org/scribe/examples/SinaWeiboExample.java +++ b/src/apis/examples/SinaWeiboExample.java @@ -1,68 +1,68 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class SinaWeiboExample -{ - private static final String NETWORK_NAME = "SinaWeibo"; - private static final String PROTECTED_RESOURCE_URL = "http://api.t.sina.com.cn/account/verify_credentials.json"; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your key"; - String apiSecret = "your secret"; - OAuthService service = new ServiceBuilder() - .provider(SinaWeiboApi.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Grab a request token. - System.out.println("Fetching request token."); - Token requestToken = service.getRequestToken(); - System.out.println("Got it ... "); - System.out.println(requestToken.getToken()); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(requestToken); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " - + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } -} +package org.scribe.examples; + +import java.util.*; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class SinaWeiboExample +{ + private static final String NETWORK_NAME = "SinaWeibo"; + private static final String PROTECTED_RESOURCE_URL = "http://api.t.sina.com.cn/account/verify_credentials.json"; + + public static void main(String[] args) + { + // Replace these with your own api key and secret + String apiKey = "your key"; + String apiSecret = "your secret"; + OAuthService service = new ServiceBuilder() + .provider(SinaWeiboApi.class) + .apiKey(apiKey) + .apiSecret(apiSecret) + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Grab a request token. + System.out.println("Fetching request token."); + Token requestToken = service.getRequestToken(); + System.out.println("Got it ... "); + System.out.println(requestToken.getToken()); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + String authorizationUrl = service.getAuthorizationUrl(requestToken); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } +} diff --git a/src/test/java/org/scribe/examples/SkyrockExample.java b/src/apis/examples/SkyrockExample.java similarity index 97% rename from src/test/java/org/scribe/examples/SkyrockExample.java rename to src/apis/examples/SkyrockExample.java index 422d067e5..313fbd63f 100644 --- a/src/test/java/org/scribe/examples/SkyrockExample.java +++ b/src/apis/examples/SkyrockExample.java @@ -1,61 +1,61 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class SkyrockExample -{ - private static final String PROTECTED_RESOURCE_URL = "https://api.skyrock.com/v2/user/get.json"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(SkyrockApi.class) - .apiKey("your-api-key") - .apiSecret("your-api-secret") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Skyrock's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } - -} +package org.scribe.examples; + +import java.util.Scanner; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class SkyrockExample +{ + private static final String PROTECTED_RESOURCE_URL = "https://api.skyrock.com/v2/user/get.json"; + + public static void main(String[] args) + { + OAuthService service = new ServiceBuilder() + .provider(SkyrockApi.class) + .apiKey("your-api-key") + .apiSecret("your-api-secret") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== Skyrock's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } + +} diff --git a/src/test/java/org/scribe/examples/SohuWeiboExample.java b/src/apis/examples/SohuWeiboExample.java similarity index 97% rename from src/test/java/org/scribe/examples/SohuWeiboExample.java rename to src/apis/examples/SohuWeiboExample.java index 49dd9fb72..248d0d189 100644 --- a/src/test/java/org/scribe/examples/SohuWeiboExample.java +++ b/src/apis/examples/SohuWeiboExample.java @@ -1,68 +1,68 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class SohuWeiboExample -{ - private static final String NETWORK_NAME = "SohuWeibo"; - private static final String PROTECTED_RESOURCE_URL = "http://api.t.sohu.com/account/verify_credentials.json"; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your_key"; - String apiSecret = "your_secret"; - OAuthService service = new ServiceBuilder() - .provider(SohuWeiboApi.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Grab a request token. - System.out.println("Fetching request token."); - Token requestToken = service.getRequestToken(); - System.out.println("Got it ... "); - System.out.println(requestToken.getToken()); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(requestToken); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " - + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } -} +package org.scribe.examples; + +import java.util.*; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class SohuWeiboExample +{ + private static final String NETWORK_NAME = "SohuWeibo"; + private static final String PROTECTED_RESOURCE_URL = "http://api.t.sohu.com/account/verify_credentials.json"; + + public static void main(String[] args) + { + // Replace these with your own api key and secret + String apiKey = "your_key"; + String apiSecret = "your_secret"; + OAuthService service = new ServiceBuilder() + .provider(SohuWeiboApi.class) + .apiKey(apiKey) + .apiSecret(apiSecret) + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Grab a request token. + System.out.println("Fetching request token."); + Token requestToken = service.getRequestToken(); + System.out.println("Got it ... "); + System.out.println(requestToken.getToken()); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + String authorizationUrl = service.getAuthorizationUrl(requestToken); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } +} diff --git a/src/test/java/org/scribe/examples/TrelloExample.java b/src/apis/examples/TrelloExample.java similarity index 97% rename from src/test/java/org/scribe/examples/TrelloExample.java rename to src/apis/examples/TrelloExample.java index 9888f5e90..5f82676fa 100644 --- a/src/test/java/org/scribe/examples/TrelloExample.java +++ b/src/apis/examples/TrelloExample.java @@ -1,60 +1,60 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class TrelloExample -{ - private static final String API_KEY = "your_api_key"; - private static final String API_SECRET = "your_api_secret"; - private static final String PROTECTED_RESOURCE_URL = "https://trello.com/1/members/me"; - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(TrelloApi.class) - .apiKey(API_KEY) - .apiSecret(API_SECRET) - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Trello's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } - -} +package org.scribe.examples; + +import java.util.Scanner; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class TrelloExample +{ + private static final String API_KEY = "your_api_key"; + private static final String API_SECRET = "your_api_secret"; + private static final String PROTECTED_RESOURCE_URL = "https://trello.com/1/members/me"; + public static void main(String[] args) + { + OAuthService service = new ServiceBuilder() + .provider(TrelloApi.class) + .apiKey(API_KEY) + .apiSecret(API_SECRET) + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== Trello's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } + +} diff --git a/src/test/java/org/scribe/examples/TwitterExample.java b/src/apis/examples/TwitterExample.java similarity index 97% rename from src/test/java/org/scribe/examples/TwitterExample.java rename to src/apis/examples/TwitterExample.java index b68aee087..b93ecbad3 100644 --- a/src/test/java/org/scribe/examples/TwitterExample.java +++ b/src/apis/examples/TwitterExample.java @@ -1,61 +1,61 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class TwitterExample -{ - private static final String PROTECTED_RESOURCE_URL = "http://api.twitter.com/1.1/account/verify_credentials.json"; - - public static void main(String[] args) - { - // If you choose to use a callback, "oauth_verifier" will be the return value by Twitter (request param) - OAuthService service = new ServiceBuilder() - .provider(TwitterApi.class) - .apiKey("6icbcAXyZx67r8uTAUM5Qw") - .apiSecret("SCCAdUUc6LXxiazxH3N0QfpNUvlUy84mZ2XZKiv39s") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Twitter's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL); - request.addBodyParameter("status", "this is sparta! *"); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } - +package org.scribe.examples; + +import java.util.Scanner; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class TwitterExample +{ + private static final String PROTECTED_RESOURCE_URL = "http://api.twitter.com/1.1/account/verify_credentials.json"; + + public static void main(String[] args) + { + // If you choose to use a callback, "oauth_verifier" will be the return value by Twitter (request param) + OAuthService service = new ServiceBuilder() + .provider(TwitterApi.class) + .apiKey("6icbcAXyZx67r8uTAUM5Qw") + .apiSecret("SCCAdUUc6LXxiazxH3N0QfpNUvlUy84mZ2XZKiv39s") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== Twitter's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL); + request.addBodyParameter("status", "this is sparta! *"); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } + } \ No newline at end of file diff --git a/src/test/java/org/scribe/examples/ViadeoExample.java b/src/apis/examples/ViadeoExample.java similarity index 97% rename from src/test/java/org/scribe/examples/ViadeoExample.java rename to src/apis/examples/ViadeoExample.java index ebb438532..0189b9594 100644 --- a/src/test/java/org/scribe/examples/ViadeoExample.java +++ b/src/apis/examples/ViadeoExample.java @@ -1,64 +1,64 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class ViadeoExample -{ - private static final String NETWORK_NAME = "Viadeo"; - private static final String PROTECTED_RESOURCE_URL = "https://api.viadeo.com/me?user_detail=full"; - private static final Token EMPTY_TOKEN = null; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your_app_id"; - String apiSecret = "your_api_secret"; - OAuthService service = new ServiceBuilder() - .provider(ViadeoApi.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .callback("http://www.example.com/oauth_callback/") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} +package org.scribe.examples; + +import java.util.*; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class ViadeoExample +{ + private static final String NETWORK_NAME = "Viadeo"; + private static final String PROTECTED_RESOURCE_URL = "https://api.viadeo.com/me?user_detail=full"; + private static final Token EMPTY_TOKEN = null; + + public static void main(String[] args) + { + // Replace these with your own api key and secret + String apiKey = "your_app_id"; + String apiSecret = "your_api_secret"; + OAuthService service = new ServiceBuilder() + .provider(ViadeoApi.class) + .apiKey(apiKey) + .apiSecret(apiSecret) + .callback("http://www.example.com/oauth_callback/") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} diff --git a/src/test/java/org/scribe/examples/VkontakteExample.java b/src/apis/examples/VkontakteExample.java similarity index 97% rename from src/test/java/org/scribe/examples/VkontakteExample.java rename to src/apis/examples/VkontakteExample.java index f9e4134e7..2d0d51efe 100644 --- a/src/test/java/org/scribe/examples/VkontakteExample.java +++ b/src/apis/examples/VkontakteExample.java @@ -1,68 +1,68 @@ -package org.scribe.examples; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -import java.util.*; - -/** - * @author Boris G. Tsirkin - * @since 20.4.2011 - */ -public class VkontakteExample -{ - private static final String NETWORK_NAME = "Vkontakte.ru"; - private static final String PROTECTED_RESOURCE_URL = "https://api.vkontakte.ru/method/friends.get"; - private static final Token EMPTY_TOKEN = null; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - final String clientId = "your app id"; - final String apiSecret = "your api secret"; - OAuthService service = new ServiceBuilder() - .provider(VkontakteApi.class) - .apiKey(clientId) - .apiSecret(apiSecret) - .scope("friends,wall,offline") // replace with desired scope - .callback("http://your.site.com/callback") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } -} +package org.scribe.examples; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +import java.util.*; + +/** + * @author Boris G. Tsirkin + * @since 20.4.2011 + */ +public class VkontakteExample +{ + private static final String NETWORK_NAME = "Vkontakte.ru"; + private static final String PROTECTED_RESOURCE_URL = "https://api.vkontakte.ru/method/friends.get"; + private static final Token EMPTY_TOKEN = null; + + public static void main(String[] args) + { + // Replace these with your own api key and secret + final String clientId = "your app id"; + final String apiSecret = "your api secret"; + OAuthService service = new ServiceBuilder() + .provider(VkontakteApi.class) + .apiKey(clientId) + .apiSecret(apiSecret) + .scope("friends,wall,offline") // replace with desired scope + .callback("http://your.site.com/callback") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize Scribe here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } +} diff --git a/src/test/java/org/scribe/examples/XingExample.java b/src/apis/examples/XingExample.java similarity index 97% rename from src/test/java/org/scribe/examples/XingExample.java rename to src/apis/examples/XingExample.java index 93d7080c4..bea0c3b6a 100755 --- a/src/test/java/org/scribe/examples/XingExample.java +++ b/src/apis/examples/XingExample.java @@ -1,59 +1,59 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class XingExample -{ - private static final String PROTECTED_RESOURCE_URL = "https://api.xing.com/v1/users/me"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(XingApi.class) - .apiKey("097ccfd3ef25a1cb6d75") - .apiSecret("e43364b2afd5d92f2ec28951a75bd8075f9cc221") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Xing's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } - -} +package org.scribe.examples; + +import java.util.Scanner; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class XingExample +{ + private static final String PROTECTED_RESOURCE_URL = "https://api.xing.com/v1/users/me"; + + public static void main(String[] args) + { + OAuthService service = new ServiceBuilder() + .provider(XingApi.class) + .apiKey("097ccfd3ef25a1cb6d75") + .apiSecret("e43364b2afd5d92f2ec28951a75bd8075f9cc221") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== Xing's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + } + +} diff --git a/src/test/java/org/scribe/examples/YahooExample.java b/src/apis/examples/YahooExample.java similarity index 97% rename from src/test/java/org/scribe/examples/YahooExample.java rename to src/apis/examples/YahooExample.java index 2e3f336f0..95e80c6da 100644 --- a/src/test/java/org/scribe/examples/YahooExample.java +++ b/src/apis/examples/YahooExample.java @@ -1,60 +1,60 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class YahooExample -{ - private static final String PROTECTED_RESOURCE_URL = "http://social.yahooapis.com/v1/user/A6ROU63MXWDCW3Y5MGCYWVHDJI/profile/status?format=json"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(YahooApi.class) - .apiKey("dj0yJmk9TXZDWVpNVVdGaVFmJmQ9WVdrOWMweHZXbkZLTkhVbWNHbzlNVEl5TWprd05qUTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0wMw--") - .apiSecret("262be559f92a2be20c4c039419018f2b48cdfce9") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Yahoo's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} +package org.scribe.examples; + +import java.util.Scanner; + +import org.scribe.builder.*; +import org.scribe.builder.api.*; +import org.scribe.model.*; +import org.scribe.oauth.*; + +public class YahooExample +{ + private static final String PROTECTED_RESOURCE_URL = "http://social.yahooapis.com/v1/user/A6ROU63MXWDCW3Y5MGCYWVHDJI/profile/status?format=json"; + + public static void main(String[] args) + { + OAuthService service = new ServiceBuilder() + .provider(YahooApi.class) + .apiKey("dj0yJmk9TXZDWVpNVVdGaVFmJmQ9WVdrOWMweHZXbkZLTkhVbWNHbzlNVEl5TWprd05qUTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0wMw--") + .apiSecret("262be559f92a2be20c4c039419018f2b48cdfce9") + .build(); + Scanner in = new Scanner(System.in); + + System.out.println("=== Yahoo's OAuth Workflow ==="); + System.out.println(); + + // Obtain the Request Token + System.out.println("Fetching the Request Token..."); + Token requestToken = service.getRequestToken(); + System.out.println("Got the Request Token!"); + System.out.println(); + + System.out.println("Now go and authorize Scribe here:"); + System.out.println(service.getAuthorizationUrl(requestToken)); + System.out.println("And paste the verifier here"); + System.out.print(">>"); + Verifier verifier = new Verifier(in.nextLine()); + System.out.println(); + + // Trade the Request Token and Verfier for the Access Token + System.out.println("Trading the Request Token for an Access Token..."); + Token accessToken = service.getAccessToken(requestToken, verifier); + System.out.println("Got the Access Token!"); + System.out.println("(if your curious it looks like this: " + accessToken + " )"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + Response response = request.send(); + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); + + } +} diff --git a/src/main/java/org/scribe/builder/ServiceBuilder.java b/src/main/java/org/scribe/builder/ServiceBuilder.java index 01cbf1482..343547126 100644 --- a/src/main/java/org/scribe/builder/ServiceBuilder.java +++ b/src/main/java/org/scribe/builder/ServiceBuilder.java @@ -6,6 +6,7 @@ import org.scribe.exceptions.OAuthException; import org.scribe.model.OAuthConfig; import org.scribe.model.OAuthConstants; +import org.scribe.model.OAuthRequestCreatorFactory; import org.scribe.model.SignatureType; import org.scribe.oauth.OAuthService; import org.scribe.utils.Preconditions; @@ -25,6 +26,7 @@ public class ServiceBuilder { private String scope; private SignatureType signatureType; private OutputStream debugStream; + private OAuthRequestCreatorFactory requestCreatorFactory; /** * Default constructor @@ -76,6 +78,12 @@ public ServiceBuilder provider(final Api api) { return this; } + public ServiceBuilder OAuthRequestCreator(final OAuthRequestCreatorFactory requestCreatorFactory) { + Preconditions.checkNotNull(requestCreatorFactory, "requestCreatorFactory cannot be null"); + this.requestCreatorFactory = requestCreatorFactory; + return this; + } + /** * Adds an OAuth callback url * @@ -157,7 +165,8 @@ public OAuthService build() { "You must specify a valid api through the provider() method"); Preconditions.checkEmptyString(apiKey, "You must provide an api key"); Preconditions.checkEmptyString(apiSecret, "You must provide an api secret"); - return api.createService(new OAuthConfig(apiKey, apiSecret, callback, signatureType, scope, - debugStream)); + final OAuthConfig config = new OAuthConfig(apiKey, apiSecret, callback, signatureType, + scope, debugStream, requestCreatorFactory); + return api.createService(config); } } diff --git a/src/main/java/org/scribe/extractors/TokenExtractorImpl.java b/src/main/java/org/scribe/extractors/TokenExtractorImpl.java index 735ab1665..6a7c5a1e5 100644 --- a/src/main/java/org/scribe/extractors/TokenExtractorImpl.java +++ b/src/main/java/org/scribe/extractors/TokenExtractorImpl.java @@ -18,7 +18,7 @@ public Token extract(final String response) { return new Token(token, secret, response); } - private static String extract(final String response, final String param) { + public static String extract(final String response, final String param) { final int start = response.indexOf(param + "="); if (start >= 0) { int end = response.indexOf("&", start); diff --git a/src/main/java/org/scribe/model/OAuthConfig.java b/src/main/java/org/scribe/model/OAuthConfig.java index 374c95894..48cc95474 100644 --- a/src/main/java/org/scribe/model/OAuthConfig.java +++ b/src/main/java/org/scribe/model/OAuthConfig.java @@ -1,79 +1,87 @@ package org.scribe.model; -import java.io.*; +import java.io.OutputStream; /** * Parameter object that groups OAuth config values * * @author Pablo Fernandez */ -public class OAuthConfig -{ - private final String apiKey; - private final String apiSecret; - private final String callback; - private final SignatureType signatureType; - private final String scope; - private final OutputStream debugStream; - - public OAuthConfig(String key, String secret) - { - this(key, secret, null, null, null, null); - } +public class OAuthConfig { + private final String apiKey; + private final String apiSecret; + private final String callback; + private final SignatureType signatureType; + private final String scope; + private final OutputStream debugStream; + private OAuthRequestCreatorFactory requestCreator; - public OAuthConfig(String key, String secret, String callback, SignatureType type, String scope, OutputStream stream) - { - this.apiKey = key; - this.apiSecret = secret; - this.callback = callback; - this.signatureType = type; - this.scope = scope; - this.debugStream = stream; - } + public OAuthConfig(final String key, final String secret) { + this(key, secret, null, null, null, null); + } - public String getApiKey() - { - return apiKey; - } + public OAuthConfig(final String key, final String secret, final String callback, + final SignatureType type, final String scope, final OutputStream stream, + final OAuthRequestCreatorFactory requestCreator) { + this(key, secret, callback, type, scope, stream); + this.requestCreator = requestCreator; + } - public String getApiSecret() - { - return apiSecret; - } + public OAuthConfig(final String key, final String secret, final String callback, + final SignatureType type, final String scope, final OutputStream stream) { + apiKey = key; + apiSecret = secret; + this.callback = callback; + signatureType = type; + this.scope = scope; + debugStream = stream; + } - public String getCallback() - { - return callback; - } + public String getApiKey() { + return apiKey; + } - public SignatureType getSignatureType() - { - return signatureType; - } + public String getApiSecret() { + return apiSecret; + } - public String getScope() - { - return scope; - } + public String getCallback() { + return callback; + } - public boolean hasScope() - { - return scope != null; - } + public SignatureType getSignatureType() { + return signatureType; + } + + public String getScope() { + return scope; + } + + public boolean hasScope() { + return scope != null; + } + + public void log(String message) { + if (debugStream != null) { + message = message + "\n"; + try { + debugStream.write(message.getBytes("UTF8")); + } catch (final Exception e) { + throw new RuntimeException( + "there were problems while writting to the debug stream", e); + } + } + } - public void log(String message) - { - if (debugStream != null) - { - message = message + "\n"; - try - { - debugStream.write(message.getBytes("UTF8")); - } - catch (Exception e) - { - throw new RuntimeException("there were problems while writting to the debug stream", e); - } + /** + * @return + */ + public OAuthRequestCreatorFactory getOAuthRequestCreatorFactory() { + synchronized (this) { + if (requestCreator == null) { + requestCreator = new DefaultOAuthRequestCreatorFactory(); + } + } + return requestCreator; } - } } diff --git a/src/main/java/org/scribe/model/OAuthRequest.java b/src/main/java/org/scribe/model/OAuthRequest.java index 5c5c36382..5f185d39a 100644 --- a/src/main/java/org/scribe/model/OAuthRequest.java +++ b/src/main/java/org/scribe/model/OAuthRequest.java @@ -17,7 +17,7 @@ public class OAuthRequest implements Request { private static final String OAUTH_PREFIX = "oauth_"; private final Map/**/oauthParameters; - private Request request; + private final Request request; public OAuthRequest(final Request request) { super(); @@ -25,32 +25,6 @@ public OAuthRequest(final Request request) { oauthParameters = new HashMap/**/(); } - /** - * Default constructor. - * - * @param verb Http verb/method - * @param url resource URL - */ - public OAuthRequest(final Verb verb, final String url) { - super(); - try { - final Class clazz = OAuthRequest.class.getClassLoader().loadClass( - "org.scribe.model.RequestFactoryImpl"); - final RequestFactory factory = (RequestFactory) clazz.newInstance(); - request = factory.createRequest(verb, url); - } catch (final ClassNotFoundException e) { - e.printStackTrace(); - request = null; - } catch (final InstantiationException e) { - e.printStackTrace(); - request = null; - } catch (final IllegalAccessException e) { - e.printStackTrace(); - request = null; - } - oauthParameters = new HashMap/**/(); - } - /** * Adds an OAuth parameter. * @@ -145,16 +119,6 @@ public String getUrl() { return request.getUrl(); } - // /** - // * @see org.scribe.model.Request#getBodyContents() - // */ - // public String getBodyContents() { - // if (request == null) { - // throw new IllegalAccessError(NOT_INTIALIZED); - // } - // return request.getBodyContents(); - // } - /** * @see org.scribe.model.Request#getVerb() */ @@ -186,4 +150,25 @@ public Response send() throws IOException { return request.send(); } + /* (non-Javadoc) + * @see org.scribe.model.Request#addPayload(java.lang.String) + */ + public void addPayload(final String payload) throws IOException { + request.addPayload(payload); + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#addPayload(byte[]) + */ + public void addPayload(final byte[] payload) throws IOException { + request.addPayload(payload); + } + + /* (non-Javadoc) + * @see org.scribe.model.Request#getPayload() + */ + public String getPayload() { + return request.getPayload(); + } + } diff --git a/src/main/java/org/scribe/model/Request.java b/src/main/java/org/scribe/model/Request.java index f63ca0877..a015233ab 100644 --- a/src/main/java/org/scribe/model/Request.java +++ b/src/main/java/org/scribe/model/Request.java @@ -1,160 +1,112 @@ -/** - * - */ -package org.scribe.model; - -import java.io.IOException; -import java.util.Map; - -import org.scribe.exceptions.OAuthException; - -/** - * @author DMusser - * - */ -public interface Request { - - public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded"; - - /** - * Execute the request and return a {@link ResponseHttpImpl} - * - * @return Response - * @throws IOException - */ - public Response send() throws IOException; - - /** - * Returns the complete url (host + resource + encoded querystring parameters). - * - * @return the complete url. - */ - // public String getCompleteUrl(); - - /** - * Add an HTTP Header to the RequestHttpImpl - * - * @param key the header name - * @param name the header name - */ - public void addHeader(final String key, final String value); - - /** - * Add a body Parameter (for POST/ PUT Requests) - * - * @param key the parameter name - * @param name the parameter name - */ - public void addBodyParameter(final String key, final String value); - - /** - * Add a QueryString parameter - * - * @param key the parameter name - * @param name the parameter name - */ - public void addQuerystringParameter(final String key, final String value); - - /** - * Add body payload. - * - * This method is used when the HTTP body is not a form-url-encoded string, - * but another thing. Like for example XML. - * - * Note: The contents are not part of the OAuth signature - * - * @param payload the body of the request - */ - // public void addPayload(final String payload); - - /** - * Overloaded version for byte arrays - * - * @param payload - */ - // public void addPayload(final byte[] payload); - - /** - * Get a {@link ParameterList} with the query string parameters. - * - * @return a {@link ParameterList} containing the query string parameters. - * @throws OAuthException if the request URL is not valid. - */ - public ParameterList getQueryStringParams(); - - /** - * Obtains a {@link ParameterList} of the body parameters. - * - * @return a {@link ParameterList}containing the body parameters. - */ - public ParameterList getBodyParams(); - - /** - * Obtains the URL of the HTTP RequestHttpImpl. - * - * @return the original URL of the HTTP RequestHttpImpl - */ - public String getUrl(); - - /** - * Returns the URL without the port and the query string part. - * - * @return the OAuth-sanitized URL - */ - // public String getSanitizedUrl(); - - /** - * Returns the body of the request - * - * @return form encoded string - * @throws OAuthException if the charset chosen is not supported - */ - // public String getBodyContents(); - - /** - * Returns the HTTP Verb - * - * @return the verb - */ - public Verb getVerb(); - - /** - * Returns the connection headers as a {@link Map} - * - * @return map of headers - */ - public Map/**/getHeaders(); - - /** - * Returns the connection charset. Defaults to {@link Charset} defaultCharset if not set - * - * @return charset - */ - // public String getCharset(); - - /** - * Set the charset of the body of the request - * - * @param charsetName name of the charset of the request - */ - // public void setCharset(final String charsetName); - - /** - * Sets whether the underlying Http Connection is persistent or not. - * - * @see http://download.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html - * @param connectionKeepAlive - */ - // public void setConnectionKeepAlive(final boolean connectionKeepAlive); - - /** - * Sets whether the underlying Http Connection follows redirects or not. - * - * Defaults to true (follow redirects) - * - * @see http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html#setInstanceFollowRedirects(boolean) - * @param followRedirects - */ - // public void setFollowRedirects(final boolean followRedirects); - +/** + * + */ +package org.scribe.model; + +import java.io.IOException; +import java.util.Map; + +import org.scribe.exceptions.OAuthException; + +/** + * @author DMusser + * + */ +public interface Request { + + public static final String DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded"; + + /** + * Execute the request and return a {@link ResponseHttpImpl} + * + * @return Response + * @throws IOException + */ + public Response send() throws IOException; + + /** + * Add an HTTP Header to the RequestHttpImpl + * + * @param key the header name + * @param name the header name + */ + public void addHeader(final String key, final String value); + + /** + * Add a body Parameter (for POST/ PUT Requests) + * + * @param key the parameter name + * @param name the parameter name + */ + public void addBodyParameter(final String key, final String value); + + /** + * Add a QueryString parameter + * + * @param key the parameter name + * @param name the parameter name + */ + public void addQuerystringParameter(final String key, final String value); + + /** + * Add body payload. + * + * This method is used when the HTTP body is not a form-url-encoded string, + * but another thing. Like for example XML. + * + * Note: The contents are not part of the OAuth signature + * + * @param payload the body of the request + */ + public void addPayload(final String payload) throws IOException; + + /** + * Overloaded version for byte arrays + * + * @param payload + */ + public void addPayload(final byte[] payload) throws IOException; + + /** + * + * @return + */ + public String getPayload(); + + /** + * Get a {@link ParameterList} with the query string parameters. + * + * @return a {@link ParameterList} containing the query string parameters. + * @throws OAuthException if the request URL is not valid. + */ + public ParameterList getQueryStringParams(); + + /** + * Obtains a {@link ParameterList} of the body parameters. + * + * @return a {@link ParameterList}containing the body parameters. + */ + public ParameterList getBodyParams(); + + /** + * Obtains the URL of the HTTP RequestHttpImpl. + * + * @return the original URL of the HTTP RequestHttpImpl + */ + public String getUrl(); + + /** + * Returns the HTTP Verb + * + * @return the verb + */ + public Verb getVerb(); + + /** + * Returns the connection headers as a {@link Map} + * + * @return map of headers + */ + public Map/**/getHeaders(); + } \ No newline at end of file diff --git a/src/main/java/org/scribe/model/RequestFactory.java b/src/main/java/org/scribe/model/RequestFactory.java deleted file mode 100644 index ad32360a7..000000000 --- a/src/main/java/org/scribe/model/RequestFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -/** - * - */ -package org.scribe.model; - -/** - * @author DMusser - * - */ -public abstract class RequestFactory { - - public abstract Request createRequest(Verb verb, String url); - -} diff --git a/src/main/java/org/scribe/model/RequestHttpImpl.java b/src/main/java/org/scribe/model/RequestHttpImpl.java index 4853ee861..6598564a9 100644 --- a/src/main/java/org/scribe/model/RequestHttpImpl.java +++ b/src/main/java/org/scribe/model/RequestHttpImpl.java @@ -14,26 +14,20 @@ /** * Represents an HTTP RequestHttpImpl object - * - * @author Pablo Fernandez */ public class RequestHttpImpl implements Request { + private static final String CONTENT_LENGTH = "Content-Length"; private static final String CONTENT_TYPE = "Content-Type"; - private final String url; private final Verb verb; private final ParameterList querystringParams; private final ParameterList bodyParams; private final Map/**/headers; - private String payload = null; private String charset; - private byte[] bytePayload = null; + private String content = null; - private final HttpURLConnection connection; - - // private Long connectTimeout = null; - // private Long readTimeout = null; + private HttpURLConnection connection; /** * Creates a new Http RequestHttpImpl @@ -41,9 +35,8 @@ public class RequestHttpImpl implements Request { * @param verb Http Verb (GET, POST, etc) * @param url url with optional querystring parameters. */ - public RequestHttpImpl(final HttpURLConnection connection, final Verb verb, final String url) { + public RequestHttpImpl(final Verb verb, final String url) { super(); - this.connection = connection; this.verb = verb; this.url = url; querystringParams = new ParameterList(); @@ -66,20 +59,33 @@ void addHeaders(final HttpURLConnection conn) { } } - void addBody(final byte[] content) throws IOException { - connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.length)); + public void addPayload(final byte[] content) throws IOException { + addPayload(new String(content)); + } + + public void addPayload(final String content) throws IOException { + this.content = content; + } + + public String getPayload() { + return content; + } + + /** + * TODO implement + */ + public Response send() throws IOException { + connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.length())); // Set default content type if none is set. if (connection.getRequestProperty(CONTENT_TYPE) == null) { connection.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); } connection.setDoOutput(true); - connection.getOutputStream().write(content); - } - - public Response send() throws IOException { + // connection.getOutputStream().write(content); final Response response = new ResponseHttpImpl(connection); return response; + // return null; } /* (non-Javadoc) @@ -103,20 +109,6 @@ public void addQuerystringParameter(final String key, final String value) { querystringParams.add(key, value); } - /* (non-Javadoc) - * @see org.scribe.model.Request#addPayload(java.lang.String) - */ - public void addPayload(final String payload) { - this.payload = payload; - } - - /* (non-Javadoc) - * @see org.scribe.model.Request#addPayload(byte[]) - */ - public void addPayload(final byte[] payload) { - bytePayload = (byte[]) payload.clone(); - } - /* (non-Javadoc) * @see org.scribe.model.Request#getQueryStringParams() */ @@ -153,29 +145,6 @@ public String getSanitizedUrl() { return StringUtils.replace(StringUtils.replace(url, "\\?.*", ""), "\\:\\d{4}", ""); } - // /* (non-Javadoc) - // * @see org.scribe.model.Request#getBodyContents() - // */ - // public String getBodyContents() { - // try { - // return new String(getByteBodyContents(), getCharset()); - // } catch (final UnsupportedEncodingException uee) { - // throw new OAuthException("Unsupported Charset: " + charset, uee); - // } - // } - - // byte[] getByteBodyContents() { - // if (bytePayload != null) { - // return bytePayload; - // } - // final String body = (payload != null) ? payload : bodyParams.asFormUrlEncodedString(); - // try { - // return body.getBytes(getCharset()); - // } catch (final UnsupportedEncodingException uee) { - // throw new OAuthException("Unsupported Charset: " + getCharset(), uee); - // } - // } - /* (non-Javadoc) * @see org.scribe.model.Request#getVerb() */ @@ -203,4 +172,12 @@ public String getCharset() { public String toString() { return "@RequestHttpImpl(" + String.valueOf(getVerb()) + " " + getUrl() + ")"; } + + /** + * @return + */ + public String getBodyContents() { + return getPayload(); + } + } diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index 1b04d3962..5e064ff31 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -23,8 +23,8 @@ public class OAuth10aServiceImpl implements OAuthService { private static final String VERSION = "1.0"; - private final OAuthConfig config; - private final DefaultApi10a api; + protected final OAuthConfig config; + protected final DefaultApi10a api; /** * Default constructor @@ -43,16 +43,16 @@ public Token getRequestToken() throws IOException { public Token getRequestToken(final Map parameters) throws IOException { config.log("obtaining request token from " + api.getRequestTokenEndpoint()); - final OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), - api.getRequestTokenEndpoint()); - + final OAuthRequest request = config + .getOAuthRequestCreatorFactory() + .createRequestTokenRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint()); if (parameters != null && parameters.size() > 0) { final Iterator i = parameters.keySet().iterator(); while (i.hasNext()) { final String key = (String) i.next(); final String value = (String) parameters.get(key); if (value != null) { - request.addBodyParameter(key, value); + request.addQuerystringParameter(key, value); } } } @@ -70,7 +70,7 @@ public Token getRequestToken(final Map parameters) throws IOException { return api.getRequestTokenExtractor().extract(body); } - private void addOAuthParams(final OAuthRequest request, final Token token) { + protected void addOAuthParams(final OAuthRequest request, final Token token) { request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService() .getTimestampInSeconds()); request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce()); @@ -92,8 +92,8 @@ private void addOAuthParams(final OAuthRequest request, final Token token) { */ public Token getAccessToken(final Token requestToken, final Verifier verifier) { config.log("obtaining access token from " + api.getAccessTokenEndpoint()); - final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), - api.getAccessTokenEndpoint()); + final OAuthRequest request = config.getOAuthRequestCreatorFactory() + .createAccessTokenRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addOAuthParameter(OAuthConstants.TOKEN, requestToken.getToken()); if (verifier != null) { request.addOAuthParameter(OAuthConstants.VERIFIER, verifier.getValue()); @@ -146,7 +146,7 @@ public String getAuthorizationUrl(final Token requestToken) { return api.getAuthorizationUrl(requestToken); } - private String getSignature(final OAuthRequest request, final Token token) { + protected String getSignature(final OAuthRequest request, final Token token) { config.log("generating signature..."); config.log("using base64 encoder: " + Base64Encoder.type()); final String baseString = api.getBaseStringExtractor().extract(request); @@ -158,7 +158,7 @@ private String getSignature(final OAuthRequest request, final Token token) { return signature; } - private void appendSignature(final OAuthRequest request) { + protected void appendSignature(final OAuthRequest request) { if (SignatureType.Header.equals(config.getSignatureType())) { config.log("using Http Header signature"); diff --git a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java index fb90a48fb..11e1388ce 100644 --- a/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth20ServiceImpl.java @@ -33,8 +33,8 @@ public OAuth20ServiceImpl(final DefaultApi20 api, final OAuthConfig config) { */ public Token getAccessToken(final Token requestToken, final Verifier verifier) throws IOException { - final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), - api.getAccessTokenEndpoint()); + final OAuthRequest request = config.getOAuthRequestCreatorFactory() + .createAccessTokenRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue()); @@ -80,8 +80,8 @@ public String getAuthorizationUrl(final Token requestToken) { * @throws IOException */ public Token getAccessToken(final Token requestToken) throws IOException { - final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), - api.getAccessTokenEndpoint()); + final OAuthRequest request = config.getOAuthRequestCreatorFactory() + .createAccessTokenRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); request.addQuerystringParameter(OAuthConstants.CLIENT_ID, config.getApiKey()); request.addQuerystringParameter(OAuthConstants.CLIENT_SECRET, config.getApiSecret()); request.addQuerystringParameter(OAuthConstants.REDIRECT_URI, config.getCallback()); diff --git a/src/test/java/org/scribe/builder/ServiceBuilderTest.java b/src/test/java/org/scribe/builder/ServiceBuilderTest.java index 8112d79b3..94323848d 100644 --- a/src/test/java/org/scribe/builder/ServiceBuilderTest.java +++ b/src/test/java/org/scribe/builder/ServiceBuilderTest.java @@ -1,73 +1,70 @@ -package org.scribe.builder; - -import static org.junit.Assert.*; - -import org.junit.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class ServiceBuilderTest -{ - private ServiceBuilder builder; - - @Before - public void setup() - { - builder = new ServiceBuilder(); - } - - @Test - public void shouldReturnConfigDefaultValues() - { - builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").build(); - assertEquals(ApiMock.config.getApiKey(), "key"); - assertEquals(ApiMock.config.getApiSecret(), "secret"); - assertEquals(ApiMock.config.getCallback(), OAuthConstants.OUT_OF_BAND); - assertEquals(ApiMock.config.getSignatureType(), SignatureType.Header); - } - - @Test - public void shouldAcceptValidCallbackUrl() - { - builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").callback("http://example.com").build(); - assertEquals(ApiMock.config.getApiKey(), "key"); - assertEquals(ApiMock.config.getApiSecret(), "secret"); - assertEquals(ApiMock.config.getCallback(), "http://example.com"); - } - - @Test - public void shouldAcceptASignatureType() - { - builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").signatureType(SignatureType.QueryString).build(); - assertEquals(ApiMock.config.getApiKey(), "key"); - assertEquals(ApiMock.config.getApiSecret(), "secret"); - assertEquals(ApiMock.config.getSignatureType(), SignatureType.QueryString); - } - - @Test(expected=IllegalArgumentException.class) - public void shouldNotAcceptNullAsCallback() - { - builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").callback(null).build(); - } - - @Test - public void shouldAcceptAnScope() - { - builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").scope("rss-api").build(); - assertEquals(ApiMock.config.getApiKey(), "key"); - assertEquals(ApiMock.config.getApiSecret(), "secret"); - assertEquals(ApiMock.config.getScope(), "rss-api"); - } - - public static class ApiMock implements Api - { - public static OAuthConfig config; - - public OAuthService createService(OAuthConfig config) - { - ApiMock.config = config; - return null; - } - } -} +package org.scribe.builder; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.scribe.builder.ServiceBuilder; +import org.scribe.builder.api.Api; +import org.scribe.model.OAuthConfig; +import org.scribe.model.OAuthConstants; +import org.scribe.model.SignatureType; +import org.scribe.oauth.OAuthService; + +public class ServiceBuilderTest { + private ServiceBuilder builder; + + @Before + public void setup() { + builder = new ServiceBuilder(); + } + + @Test + public void shouldReturnConfigDefaultValues() { + builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").build(); + assertEquals(ApiMock.config.getApiKey(), "key"); + assertEquals(ApiMock.config.getApiSecret(), "secret"); + assertEquals(ApiMock.config.getCallback(), OAuthConstants.OUT_OF_BAND); + assertEquals(ApiMock.config.getSignatureType(), SignatureType.Header); + } + + @Test + public void shouldAcceptValidCallbackUrl() { + builder.provider(ApiMock.class).apiKey("key").apiSecret("secret") + .callback("http://example.com").build(); + assertEquals(ApiMock.config.getApiKey(), "key"); + assertEquals(ApiMock.config.getApiSecret(), "secret"); + assertEquals(ApiMock.config.getCallback(), "http://example.com"); + } + + @Test + public void shouldAcceptASignatureType() { + builder.provider(ApiMock.class).apiKey("key").apiSecret("secret") + .signatureType(SignatureType.QueryString).build(); + assertEquals(ApiMock.config.getApiKey(), "key"); + assertEquals(ApiMock.config.getApiSecret(), "secret"); + assertEquals(ApiMock.config.getSignatureType(), SignatureType.QueryString); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldNotAcceptNullAsCallback() { + builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").callback(null).build(); + } + + @Test + public void shouldAcceptAnScope() { + builder.provider(ApiMock.class).apiKey("key").apiSecret("secret").scope("rss-api").build(); + assertEquals(ApiMock.config.getApiKey(), "key"); + assertEquals(ApiMock.config.getApiSecret(), "secret"); + assertEquals(ApiMock.config.getScope(), "rss-api"); + } + + public static class ApiMock implements Api { + public static OAuthConfig config; + + public OAuthService createService(final OAuthConfig config) { + ApiMock.config = config; + return null; + } + } +} diff --git a/src/test/java/org/scribe/examples/AWeberExample.java b/src/test/java/org/scribe/examples/AWeberExample.java deleted file mode 100644 index 2d86d6130..000000000 --- a/src/test/java/org/scribe/examples/AWeberExample.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class AWeberExample -{ - - //To get your consumer key/secret, and view API docs, see https://labs.aweber.com/docs - private static final String ACCOUNT_RESOURCE_URL = "https://api.aweber.com/1.0/accounts/"; - - private static final String CONSUMER_KEY = ""; - private static final String CONSUMER_SECRET = ""; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(AWeberApi.class) - .apiKey(CONSUMER_KEY) - .apiSecret(CONSUMER_SECRET) - .build(); - - Scanner in = new Scanner(System.in); - - System.out.println("=== AWeber's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, ACCOUNT_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with AWeber and Scribe! :)"); - } - -} \ No newline at end of file diff --git a/src/test/java/org/scribe/examples/DiggExample.java b/src/test/java/org/scribe/examples/DiggExample.java deleted file mode 100644 index 63fea8b6a..000000000 --- a/src/test/java/org/scribe/examples/DiggExample.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class DiggExample -{ - private static final String NETWORK_NAME = "Digg"; - private static final String PROTECTED_RESOURCE_URL = "http://services.digg.com/2.0/comment.digg"; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "myKey"; - String apiSecret = "mySecret"; - OAuthService service = new ServiceBuilder().provider(DiggApi.class).apiKey(apiKey).apiSecret(apiSecret).build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(requestToken); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL); - request.addBodyParameter("comment_id", "20100729223726:4fef610331ee46a3b5cbd740bf71313e"); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} \ No newline at end of file diff --git a/src/test/java/org/scribe/examples/FacebookExample.java b/src/test/java/org/scribe/examples/FacebookExample.java deleted file mode 100644 index d5dc3cb50..000000000 --- a/src/test/java/org/scribe/examples/FacebookExample.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class FacebookExample -{ - private static final String NETWORK_NAME = "Facebook"; - private static final String PROTECTED_RESOURCE_URL = "https://graph.facebook.com/me"; - private static final Token EMPTY_TOKEN = null; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your_app_id"; - String apiSecret = "your_api_secret"; - OAuthService service = new ServiceBuilder() - .provider(FacebookApi.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .callback("http://www.example.com/oauth_callback/") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} \ No newline at end of file diff --git a/src/test/java/org/scribe/examples/FlickrExample.java b/src/test/java/org/scribe/examples/FlickrExample.java deleted file mode 100644 index ac38ad32f..000000000 --- a/src/test/java/org/scribe/examples/FlickrExample.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.scribe.examples; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -import java.util.*; - -public class FlickrExample -{ - private static final String PROTECTED_RESOURCE_URL = "http://api.flickr.com/services/rest/"; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your_app_id"; - String apiSecret = "your_api_secret"; - OAuthService service = new ServiceBuilder().provider(FlickrApi.class).apiKey(apiKey).apiSecret(apiSecret).build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Flickr's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - String authorizationUrl = service.getAuthorizationUrl(requestToken); - System.out.println(authorizationUrl + "&perms=read"); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - request.addQuerystringParameter("method", "flickr.test.login"); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } -} diff --git a/src/test/java/org/scribe/examples/Foursquare2Example.java b/src/test/java/org/scribe/examples/Foursquare2Example.java deleted file mode 100644 index 35495a895..000000000 --- a/src/test/java/org/scribe/examples/Foursquare2Example.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class Foursquare2Example -{ - private static final String PROTECTED_RESOURCE_URL = "https://api.foursquare.com/v2/users/self/friends?oauth_token="; - private static final Token EMPTY_TOKEN = null; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "FEGFXJUFANVVDHVSNUAMUKTTXCP1AJQD53E33XKJ44YP1S4I"; - String apiSecret = "AYWKUL5SWPNC0CTQ202QXRUG2NLZYXMRA34ZSDW4AUYBG2RC"; - OAuthService service = new ServiceBuilder() - .provider(Foursquare2Api.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .callback("http://localhost:9000/") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Foursquare2's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL + accessToken.getToken()); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} diff --git a/src/test/java/org/scribe/examples/FoursquareExample.java b/src/test/java/org/scribe/examples/FoursquareExample.java deleted file mode 100644 index b227488c7..000000000 --- a/src/test/java/org/scribe/examples/FoursquareExample.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class FoursquareExample -{ - private static final String PROTECTED_RESOURCE_URL = "http://api.foursquare.com/v1/user"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(FoursquareApi.class) - .apiKey("FEGFXJUFANVVDHVSNUAMUKTTXCP1AJQD53E33XKJ44YP1S4I") - .apiSecret("AYWKUL5SWPNC0CTQ202QXRUG2NLZYXMRA34ZSDW4AUYBG2RC") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Foursquare's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } - -} \ No newline at end of file diff --git a/src/test/java/org/scribe/examples/FreelancerExample.java b/src/test/java/org/scribe/examples/FreelancerExample.java deleted file mode 100644 index d1d540723..000000000 --- a/src/test/java/org/scribe/examples/FreelancerExample.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.scribe.examples; - -import java.util.*; -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class FreelancerExample -{ - - private static final String NETWORK_NAME = "Freelancer"; - private static final String AUTHORIZE_URL = "http://www.sandbox.freelancer.com/users/api-token/auth.php?oauth_token="; - private static final String PROTECTED_RESOURCE_URL = "http://api.sandbox.freelancer.com/Job/getJobList.json"; - private static final String SCOPE = "http://api.sandbox.freelancer.com"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(FreelancerApi.Sandbox.class) - .signatureType(SignatureType.QueryString) - .apiKey("7f5a168a0bfdbd15b4a9ea2a969661c731cdea56") - .apiSecret("7bb8961b94873802f1c5344f671a518e087f5785") - .scope(SCOPE) - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println("(if your curious it looks like this: " + requestToken + " )"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(AUTHORIZE_URL + requestToken.getToken()); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - request.addHeader("GData-Version", "3.0"); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } -} diff --git a/src/test/java/org/scribe/examples/GoogleExample.java b/src/test/java/org/scribe/examples/GoogleExample.java deleted file mode 100644 index fef1b43c9..000000000 --- a/src/test/java/org/scribe/examples/GoogleExample.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class GoogleExample -{ - private static final String NETWORK_NAME = "Google"; - private static final String AUTHORIZE_URL = "https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token="; - private static final String PROTECTED_RESOURCE_URL = "https://docs.google.com/feeds/default/private/full/"; - private static final String SCOPE = "https://docs.google.com/feeds/"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(GoogleApi.class) - .apiKey("anonymous") - .apiSecret("anonymous") - .scope(SCOPE) - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println("(if your curious it looks like this: " + requestToken + " )"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(AUTHORIZE_URL + requestToken.getToken()); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - request.addHeader("GData-Version", "3.0"); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} \ No newline at end of file diff --git a/src/test/java/org/scribe/examples/ImgUrExample.java b/src/test/java/org/scribe/examples/ImgUrExample.java deleted file mode 100644 index 93fe91cb7..000000000 --- a/src/test/java/org/scribe/examples/ImgUrExample.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.scribe.examples; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -import java.util.*; - -public class ImgUrExample -{ - private static final String PROTECTED_RESOURCE_URL = "http://api.imgur.com/2/account.json"; - - public static void main(String[] args) - { - // Replace these with your own api key and secret (you'll need an read/write api key) - String apiKey = "your_app_id"; - String apiSecret = "your_api_secret"; - OAuthService service = new ServiceBuilder().provider(ImgUrApi.class).apiKey(apiKey).apiSecret(apiSecret).build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== ImgUr's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - String authorizationUrl = service.getAuthorizationUrl(requestToken); - System.out.println(authorizationUrl); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } -} diff --git a/src/test/java/org/scribe/examples/Kaixin20Example.java b/src/test/java/org/scribe/examples/Kaixin20Example.java deleted file mode 100644 index b3e9d66ba..000000000 --- a/src/test/java/org/scribe/examples/Kaixin20Example.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.scribe.examples; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; -import java.util.*; - -public class Kaixin20Example -{ - private static final String NETWORK_NAME = "Kaixin"; - private static final String PROTECTED_RESOURCE_URL = "https://api.kaixin001.com/users/me.json"; - private static final Token EMPTY_TOKEN = null; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = "your api key"; - String apiSecret = "your api secret"; - OAuthService service = new ServiceBuilder() - .provider(KaixinApi20.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .callback("http://your.domain.com/handle") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verifier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} diff --git a/src/test/java/org/scribe/examples/LinkedInExample.java b/src/test/java/org/scribe/examples/LinkedInExample.java deleted file mode 100644 index 703cc8275..000000000 --- a/src/test/java/org/scribe/examples/LinkedInExample.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class LinkedInExample -{ - private static final String PROTECTED_RESOURCE_URL = "http://api.linkedin.com/v1/people/~/connections:(id,last-name)"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(LinkedInApi.class) - .apiKey("CiEgwWDkA5BFpNrc0RfGyVuSlOh4tig5kOTZ9q97qcXNrFl7zqk-Ts7DqRGaKDCV") - .apiSecret("dhho4dfoCmiQXrkw4yslork5XWLFnPSuMR-8gscPVjY4jqFFHPYWJKgpFl4uLTM6") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== LinkedIn's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } - -} diff --git a/src/test/java/org/scribe/examples/LinkedInExampleWithScopes.java b/src/test/java/org/scribe/examples/LinkedInExampleWithScopes.java deleted file mode 100644 index b8e8b2881..000000000 --- a/src/test/java/org/scribe/examples/LinkedInExampleWithScopes.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.scribe.examples; - -import java.util.Scanner; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class LinkedInExampleWithScopes -{ - private static final String PROTECTED_RESOURCE_URL = "http://api.linkedin.com/v1/people/~/connections:(id,last-name)"; - - public static void main(String[] args) - { - OAuthService service = new ServiceBuilder() - .provider(LinkedInApi.withScopes("foo", "bar", "baz")) - .apiKey("CiEgwWDkA5BFpNrc0RfGyVuSlOh4tig5kOTZ9q97qcXNrFl7zqk-Ts7DqRGaKDCV") - .apiSecret("dhho4dfoCmiQXrkw4yslork5XWLFnPSuMR-8gscPVjY4jqFFHPYWJKgpFl4uLTM6") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== LinkedIn's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Request Token - System.out.println("Fetching the Request Token..."); - Token requestToken = service.getRequestToken(); - System.out.println("Got the Request Token!"); - System.out.println(); - - System.out.println("Now go and authorize Scribe here:"); - System.out.println(service.getAuthorizationUrl(requestToken)); - System.out.println("And paste the verifier here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(requestToken, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - } - -} diff --git a/src/test/java/org/scribe/examples/LiveExample.java b/src/test/java/org/scribe/examples/LiveExample.java deleted file mode 100644 index ade5a6ba9..000000000 --- a/src/test/java/org/scribe/examples/LiveExample.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.scribe.examples; - -import java.util.*; - -import org.scribe.builder.*; -import org.scribe.builder.api.*; -import org.scribe.model.*; -import org.scribe.oauth.*; - -public class LiveExample -{ - private static final String PROTECTED_RESOURCE_URL = "https://api.foursquare.com/v2/users/self/friends?oauth_token="; - private static final Token EMPTY_TOKEN = null; - - public static void main(String[] args) - { - // Replace these with your own api key and secret - String apiKey = ""; - String apiSecret = ""; - OAuthService service = new ServiceBuilder() - .provider(LiveApi.class) - .apiKey(apiKey) - .apiSecret(apiSecret) - .scope("wl.basic") - .callback("http://localhost:9000/") - .build(); - Scanner in = new Scanner(System.in); - - System.out.println("=== Windows Live's OAuth Workflow ==="); - System.out.println(); - - // Obtain the Authorization URL - System.out.println("Fetching the Authorization URL..."); - String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN); - System.out.println("Got the Authorization URL!"); - System.out.println("Now go and authorize Scribe here:"); - System.out.println(authorizationUrl); - System.out.println("And paste the authorization code here"); - System.out.print(">>"); - Verifier verifier = new Verifier(in.nextLine()); - System.out.println(); - - // Trade the Request Token and Verfier for the Access Token - System.out.println("Trading the Request Token for an Access Token..."); - Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); - System.out.println("Got the Access Token!"); - System.out.println("(if your curious it looks like this: " + accessToken + " )"); - System.out.println(); - - // Now let's go and ask for a protected resource! - System.out.println("Now we're going to access a protected resource..."); - OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL + accessToken.getToken()); - service.signRequest(accessToken, request); - Response response = request.send(); - System.out.println("Got it! Lets see what we found..."); - System.out.println(); - System.out.println(response.getCode()); - System.out.println(response.getBody()); - - System.out.println(); - System.out.println("Thats it man! Go and build something awesome with Scribe! :)"); - - } -} diff --git a/src/test/java/org/scribe/extractors/BaseStringExtractorTest.java b/src/test/java/org/scribe/extractors/BaseStringExtractorTest.java index edc101d15..e209a7bbf 100644 --- a/src/test/java/org/scribe/extractors/BaseStringExtractorTest.java +++ b/src/test/java/org/scribe/extractors/BaseStringExtractorTest.java @@ -1,52 +1,51 @@ -package org.scribe.extractors; - -import static org.junit.Assert.*; - -import org.junit.*; -import org.scribe.exceptions.*; -import org.scribe.model.*; -import org.scribe.test.helpers.*; - -public class BaseStringExtractorTest -{ - - private BaseStringExtractorImpl extractor; - private OAuthRequest request; - - @Before - public void setup() - { - request = ObjectMother.createSampleOAuthRequest(); - extractor = new BaseStringExtractorImpl(); - } - - @Test - public void shouldExtractBaseStringFromOAuthRequest() - { - String expected = "GET&http%3A%2F%2Fexample.com&oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E%252A%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456"; - String baseString = extractor.extract(request); - assertEquals(expected, baseString); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionIfRquestIsNull() - { - OAuthRequest nullRequest = null; - extractor.extract(nullRequest); - } - - @Test(expected = OAuthParametersMissingException.class) - public void shouldThrowExceptionIfRquestHasNoOAuthParameters() - { - OAuthRequest request = new OAuthRequest(Verb.GET, "http://example.com"); - extractor.extract(request); - } - - @Test - public void shouldProperlyEncodeSpaces() - { - String expected = "GET&http%3A%2F%2Fexample.com&body%3Dthis%2520param%2520has%2520whitespace%26oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E%252A%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456"; - request.addBodyParameter("body", "this param has whitespace"); - assertEquals(expected, extractor.extract(request)); - } -} +package org.scribe.extractors; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.scribe.exceptions.OAuthParametersMissingException; +import org.scribe.extractors.BaseStringExtractorImpl; +import org.scribe.model.OAuthRequest; +import org.scribe.model.RequestHttpImpl; +import org.scribe.model.Verb; +import org.scribe.test.helpers.ObjectMother; + +public class BaseStringExtractorTest { + + private BaseStringExtractorImpl extractor; + private OAuthRequest request; + + @Before + public void setup() { + request = ObjectMother.createSampleOAuthRequest(); + extractor = new BaseStringExtractorImpl(); + } + + @Test + public void shouldExtractBaseStringFromOAuthRequest() { + final String expected = "GET&http%3A%2F%2Fexample.com&oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E%252A%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456"; + final String baseString = extractor.extract(request); + assertEquals(expected, baseString); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowExceptionIfRquestIsNull() { + final OAuthRequest nullRequest = null; + extractor.extract(nullRequest); + } + + @Test(expected = OAuthParametersMissingException.class) + public void shouldThrowExceptionIfRquestHasNoOAuthParameters() { + final RequestHttpImpl httpRequest = new RequestHttpImpl(Verb.GET, "http://example.com"); + final OAuthRequest request = new OAuthRequest(httpRequest); + extractor.extract(request); + } + + @Test + public void shouldProperlyEncodeSpaces() { + final String expected = "GET&http%3A%2F%2Fexample.com&body%3Dthis%2520param%2520has%2520whitespace%26oauth_callback%3Dhttp%253A%252F%252Fexample%252Fcallback%26oauth_consumer_key%3DAS%2523%2524%255E%252A%2540%2526%26oauth_signature%3DOAuth-Signature%26oauth_timestamp%3D123456"; + request.addBodyParameter("body", "this param has whitespace"); + assertEquals(expected, extractor.extract(request)); + } +} diff --git a/src/test/java/org/scribe/extractors/HeaderExtractorTest.java b/src/test/java/org/scribe/extractors/HeaderExtractorTest.java index bdc727cd8..932253a46 100644 --- a/src/test/java/org/scribe/extractors/HeaderExtractorTest.java +++ b/src/test/java/org/scribe/extractors/HeaderExtractorTest.java @@ -1,45 +1,45 @@ -package org.scribe.extractors; - -import static org.junit.Assert.*; - -import org.junit.*; -import org.scribe.exceptions.*; -import org.scribe.model.*; -import org.scribe.test.helpers.*; - -public class HeaderExtractorTest -{ - - private HeaderExtractorImpl extractor; - private OAuthRequest request; - - @Before - public void setup() - { - request = ObjectMother.createSampleOAuthRequest(); - extractor = new HeaderExtractorImpl(); - } - - @Test - public void shouldExtractStandardHeader() - { - String expected = "OAuth oauth_callback=\"http%3A%2F%2Fexample%2Fcallback\", " + "oauth_signature=\"OAuth-Signature\", " - + "oauth_consumer_key=\"AS%23%24%5E%2A%40%26\", " + "oauth_timestamp=\"123456\""; - String header = extractor.extract(request); - assertEquals(expected, header); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldExceptionIfRequestIsNull() - { - OAuthRequest nullRequest = null; - extractor.extract(nullRequest); - } - - @Test(expected = OAuthParametersMissingException.class) - public void shouldExceptionIfRequestHasNoOAuthParams() - { - OAuthRequest emptyRequest = new OAuthRequest(Verb.GET, "http://example.com"); - extractor.extract(emptyRequest); - } -} +package org.scribe.extractors; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.scribe.exceptions.OAuthParametersMissingException; +import org.scribe.model.OAuthRequest; +import org.scribe.model.RequestHttpImpl; +import org.scribe.model.Verb; +import org.scribe.test.helpers.ObjectMother; + +public class HeaderExtractorTest { + + private HeaderExtractorImpl extractor; + private OAuthRequest request; + + @Before + public void setup() { + request = ObjectMother.createSampleOAuthRequest(); + extractor = new HeaderExtractorImpl(); + } + + @Test + public void shouldExtractStandardHeader() { + final String expected = "OAuth oauth_callback=\"http%3A%2F%2Fexample%2Fcallback\", " + + "oauth_signature=\"OAuth-Signature\", " + + "oauth_consumer_key=\"AS%23%24%5E%2A%40%26\", " + "oauth_timestamp=\"123456\""; + final String header = extractor.extract(request); + assertEquals(expected, header); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldExceptionIfRequestIsNull() { + final OAuthRequest nullRequest = null; + extractor.extract(nullRequest); + } + + @Test(expected = OAuthParametersMissingException.class) + public void shouldExceptionIfRequestHasNoOAuthParams() { + final RequestHttpImpl httpRequest = new RequestHttpImpl(Verb.GET, "http://example.com"); + final OAuthRequest emptyRequest = new OAuthRequest(httpRequest); + extractor.extract(emptyRequest); + } +} diff --git a/src/test/java/org/scribe/model/ConnectionStub.java b/src/test/java/org/scribe/model/ConnectionStub.java index 7e9331397..3eaac8b88 100644 --- a/src/test/java/org/scribe/model/ConnectionStub.java +++ b/src/test/java/org/scribe/model/ConnectionStub.java @@ -1,86 +1,74 @@ -package org.scribe.model; - -import java.io.*; -import java.net.*; -import java.util.*; - -public class ConnectionStub extends HttpURLConnection -{ - - private Map headers = new HashMap(); - private Map> responseHeaders = new HashMap>(); - private int inputStreamCalled = 0; - - public ConnectionStub() throws Exception - { - super(new URL("http://example.com")); - } - - @Override - public void setRequestProperty(String key, String value) - { - headers.put(key, value); - } - - @Override - public String getRequestProperty(String s) - { - return headers.get(s); - } - - public Map getHeaders() - { - return headers; - } - - @Override - public int getResponseCode() throws IOException - { - return 200; - } - - @Override - public InputStream getInputStream() throws IOException - { - inputStreamCalled++; - return new ByteArrayInputStream("contents".getBytes()); - } - - public int getTimesCalledInpuStream() - { - return inputStreamCalled; - } - - @Override - public OutputStream getOutputStream() throws IOException - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - baos.write("contents".getBytes()); - return baos; - } - - @Override - public Map> getHeaderFields() - { - return responseHeaders; - } - - public void addResponseHeader(String key, String value) - { - responseHeaders.put(key, Arrays.asList(value)); - } - - public void connect() throws IOException - { - } - - public void disconnect() - { - } - - public boolean usingProxy() - { - return false; - } - -} +package org.scribe.model; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ConnectionStub extends HttpURLConnection { + + private final Map headers = new HashMap(); + private final Map> responseHeaders = new HashMap>(); + private int inputStreamCalled = 0; + + public ConnectionStub() throws Exception { + super(new URL("http://example.com")); + } + + public void setRequestProperty(final String key, final String value) { + headers.put(key, value); + } + + public String getRequestProperty(final String s) { + return headers.get(s); + } + + public Map getHeaders() { + return headers; + } + + public int getResponseCode() throws IOException { + return 200; + } + + public InputStream getInputStream() throws IOException { + inputStreamCalled++; + return new ByteArrayInputStream("contents".getBytes()); + } + + public int getTimesCalledInpuStream() { + return inputStreamCalled; + } + + public OutputStream getOutputStream() throws IOException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write("contents".getBytes()); + return baos; + } + + public Map> getHeaderFields() { + return responseHeaders; + } + + public void addResponseHeader(final String key, final String value) { + responseHeaders.put(key, Arrays.asList(value)); + } + + public void connect() throws IOException { + } + + public void disconnect() { + } + + public boolean usingProxy() { + return false; + } + +} diff --git a/src/test/java/org/scribe/model/OAuthRequestTest.java b/src/test/java/org/scribe/model/OAuthRequestTest.java index 1ea2f2fb9..3114f9397 100644 --- a/src/test/java/org/scribe/model/OAuthRequestTest.java +++ b/src/test/java/org/scribe/model/OAuthRequestTest.java @@ -1,34 +1,32 @@ -package org.scribe.model; - -import static org.junit.Assert.*; - -import org.junit.*; - -public class OAuthRequestTest -{ - - private OAuthRequest request; - - @Before - public void setup() - { - request = new OAuthRequest(Verb.GET, "http://example.com"); - } - - @Test - public void shouldAddOAuthParamters() - { - request.addOAuthParameter(OAuthConstants.TOKEN, "token"); - request.addOAuthParameter(OAuthConstants.NONCE, "nonce"); - request.addOAuthParameter(OAuthConstants.TIMESTAMP, "ts"); - request.addOAuthParameter(OAuthConstants.SCOPE, "feeds"); - - assertEquals(4, request.getOauthParameters().size()); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionIfParameterIsNotOAuth() - { - request.addOAuthParameter("otherParam", "value"); - } -} +package org.scribe.model; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +public class OAuthRequestTest { + + private OAuthRequest request; + + @Before + public void setup() { + final RequestHttpImpl httpRequest = new RequestHttpImpl(Verb.GET, "http://example.com"); + request = new OAuthRequest(httpRequest); + } + + @Test + public void shouldAddOAuthParamters() { + request.addOAuthParameter(OAuthConstants.TOKEN, "token"); + request.addOAuthParameter(OAuthConstants.NONCE, "nonce"); + request.addOAuthParameter(OAuthConstants.TIMESTAMP, "ts"); + request.addOAuthParameter(OAuthConstants.SCOPE, "feeds"); + + assertEquals(4, request.getOauthParameters().size()); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowExceptionIfParameterIsNotOAuth() { + request.addOAuthParameter("otherParam", "value"); + } +} diff --git a/src/test/java/org/scribe/model/ParameterListTest.java b/src/test/java/org/scribe/model/ParameterListTest.java index 657e8e218..a16b70c5e 100644 --- a/src/test/java/org/scribe/model/ParameterListTest.java +++ b/src/test/java/org/scribe/model/ParameterListTest.java @@ -1,91 +1,83 @@ -package org.scribe.model; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; - -/** - * @author: Pablo Fernandez - */ -public class ParameterListTest -{ - private ParameterList params; - - @Before - public void setup() - { - this.params = new ParameterList(); - } - - @Test(expected = IllegalArgumentException.class) - public void shouldThrowExceptionWhenAppendingNullMapToQuerystring() - { - String url = null; - params.appendTo(url); - } - - @Test - public void shouldAppendNothingToQuerystringIfGivenEmptyMap() - { - String url = "http://www.example.com"; - Assert.assertEquals(url, params.appendTo(url)); - } - - @Test - public void shouldAppendParametersToSimpleUrl() - { - String url = "http://www.example.com"; - String expectedUrl = "http://www.example.com?param1=value1¶m2=value%20with%20spaces"; - - params.add("param1", "value1"); - params.add("param2", "value with spaces"); - - url = params.appendTo(url); - Assert.assertEquals(url, expectedUrl); - } - - @Test - public void shouldAppendParametersToUrlWithQuerystring() - { - String url = "http://www.example.com?already=present"; - String expectedUrl = "http://www.example.com?already=present¶m1=value1¶m2=value%20with%20spaces"; - - params.add("param1", "value1"); - params.add("param2", "value with spaces"); - - url = params.appendTo(url); - Assert.assertEquals(url, expectedUrl); - } - - @Test - public void shouldProperlySortParameters() - { - params.add("param1", "v1"); - params.add("param6", "v2"); - params.add("a_param", "v3"); - params.add("param2", "v4"); - Assert.assertEquals("a_param=v3¶m1=v1¶m2=v4¶m6=v2", params.sort().asFormUrlEncodedString()); - } - - @Test - public void shouldProperlySortParametersWithTheSameName() - { - params.add("param1", "v1"); - params.add("param6", "v2"); - params.add("a_param", "v3"); - params.add("param1", "v4"); - Assert.assertEquals("a_param=v3¶m1=v1¶m1=v4¶m6=v2", params.sort().asFormUrlEncodedString()); - } - - @Test - public void shouldNotModifyTheOriginalParameterList() - { - params.add("param1", "v1"); - params.add("param6", "v2"); - - assertNotSame(params, params.sort()); - } -} +package org.scribe.model; + +import static org.junit.Assert.assertNotSame; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * @author: Pablo Fernandez + */ +public class ParameterListTest { + private ParameterList params; + + @Before + public void setup() { + params = new ParameterList(); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowExceptionWhenAppendingNullMapToQuerystring() { + final String url = null; + params.appendTo(url); + } + + @Test + public void shouldAppendNothingToQuerystringIfGivenEmptyMap() { + final String url = "http://www.example.com"; + Assert.assertEquals(url, params.appendTo(url)); + } + + @Test + public void shouldAppendParametersToSimpleUrl() { + String url = "http://www.example.com"; + final String expectedUrl = "http://www.example.com?param1=value1¶m2=value%20with%20spaces"; + + params.add("param1", "value1"); + params.add("param2", "value with spaces"); + + url = params.appendTo(url); + Assert.assertEquals(url, expectedUrl); + } + + @Test + public void shouldAppendParametersToUrlWithQuerystring() { + String url = "http://www.example.com?already=present"; + final String expectedUrl = "http://www.example.com?already=present¶m1=value1¶m2=value%20with%20spaces"; + + params.add("param1", "value1"); + params.add("param2", "value with spaces"); + + url = params.appendTo(url); + Assert.assertEquals(url, expectedUrl); + } + + @Test + public void shouldProperlySortParameters() { + params.add("param1", "v1"); + params.add("param6", "v2"); + params.add("a_param", "v3"); + params.add("param2", "v4"); + Assert.assertEquals("a_param=v3¶m1=v1¶m2=v4¶m6=v2", params.sort() + .asFormUrlEncodedString()); + } + + @Test + public void shouldProperlySortParametersWithTheSameName() { + params.add("param1", "v1"); + params.add("param6", "v2"); + params.add("a_param", "v3"); + params.add("param1", "v4"); + Assert.assertEquals("a_param=v3¶m1=v1¶m1=v4¶m6=v2", params.sort() + .asFormUrlEncodedString()); + } + + @Test + public void shouldNotModifyTheOriginalParameterList() { + params.add("param1", "v1"); + params.add("param6", "v2"); + + assertNotSame(params, params.sort()); + } +} diff --git a/src/test/java/org/scribe/model/RequestTest.java b/src/test/java/org/scribe/model/RequestTest.java index c473e779c..e8690a6ff 100644 --- a/src/test/java/org/scribe/model/RequestTest.java +++ b/src/test/java/org/scribe/model/RequestTest.java @@ -1,128 +1,125 @@ -package org.scribe.model; - -import static org.junit.Assert.*; - -import org.junit.*; - -public class RequestTest -{ - private Request getRequest; - private Request postRequest; - private ConnectionStub connection; - - @Before - public void setup() throws Exception - { - connection = new ConnectionStub(); - postRequest = new Request(Verb.POST, "http://example.com"); - postRequest.addBodyParameter("param", "value"); - postRequest.addBodyParameter("param with spaces", "value with spaces"); - postRequest.setConnection(connection); - getRequest = new Request(Verb.GET, "http://example.com?qsparam=value&other+param=value+with+spaces"); - getRequest.setConnection(connection); - } - - @Test - public void shouldSetRequestVerb() - { - getRequest.send(); - assertEquals("GET", connection.getRequestMethod()); - } - - @Test - public void shouldGetQueryStringParameters() - { - assertEquals(2, getRequest.getQueryStringParams().size()); - assertEquals(0, postRequest.getQueryStringParams().size()); - assertTrue(getRequest.getQueryStringParams().contains(new Parameter("qsparam", "value"))); - } - - @Test - public void shouldAddRequestHeaders() - { - getRequest.addHeader("Header", "1"); - getRequest.addHeader("Header2", "2"); - getRequest.send(); - assertEquals(2, getRequest.getHeaders().size()); - assertEquals(2, connection.getHeaders().size()); - } - - @Test - public void shouldSetBodyParamsAndAddContentLength() - { - assertEquals("param=value¶m%20with%20spaces=value%20with%20spaces", postRequest.getBodyContents()); - postRequest.send(); - assertTrue(connection.getHeaders().containsKey("Content-Length")); - } - - @Test - public void shouldSetPayloadAndHeaders() - { - postRequest.addPayload("PAYLOAD"); - postRequest.send(); - assertEquals("PAYLOAD", postRequest.getBodyContents()); - assertTrue(connection.getHeaders().containsKey("Content-Length")); - } - - @Test - public void shouldAllowAddingQuerystringParametersAfterCreation() - { - Request request = new Request(Verb.GET, "http://example.com?one=val"); - request.addQuerystringParameter("two", "other val"); - request.addQuerystringParameter("more", "params"); - assertEquals(3, request.getQueryStringParams().size()); - } - - @Test - public void shouldReturnTheCompleteUrl() - { - Request request = new Request(Verb.GET, "http://example.com?one=val"); - request.addQuerystringParameter("two", "other val"); - request.addQuerystringParameter("more", "params"); - assertEquals("http://example.com?one=val&two=other%20val&more=params", request.getCompleteUrl()); - } - - @Test - public void shouldHandleQueryStringSpaceEncodingProperly() - { - assertTrue(getRequest.getQueryStringParams().contains(new Parameter("other param","value with spaces"))); - } - - @Test - public void shouldAutomaticallyAddContentTypeForPostRequestsWithBytePayload() - { - postRequest.addPayload("PAYLOAD".getBytes()); - postRequest.send(); - assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type")); - } - - @Test - public void shouldAutomaticallyAddContentTypeForPostRequestsWithStringPayload() - { - postRequest.addPayload("PAYLOAD"); - postRequest.send(); - assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type")); - } - - @Test - public void shouldAutomaticallyAddContentTypeForPostRequestsWithBodyParameters() - { - postRequest.send(); - assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type")); - } - - @Test - public void shouldBeAbleToOverrideItsContentType() - { - postRequest.addHeader("Content-Type", "my-content-type"); - postRequest.send(); - assertEquals("my-content-type", connection.getHeaders().get("Content-Type")); - } - - @Test - public void shouldNotAddContentTypeForGetRequests() - { - getRequest.send(); - assertFalse(connection.getHeaders().containsKey("Content-Type")); - } +package org.scribe.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +public class RequestTest { + private RequestHttpImpl getRequest; + private RequestHttpImpl postRequest; + private ConnectionStub connection; + + @Before + public void setup() throws Exception { + connection = new ConnectionStub(); + postRequest = new RequestHttpImpl(Verb.POST, "http://example.com"); + postRequest.addBodyParameter("param", "value"); + postRequest.addBodyParameter("param with spaces", "value with spaces"); + // postRequest.setConnection(connection); + getRequest = new RequestHttpImpl(Verb.GET, + "http://example.com?qsparam=value&other+param=value+with+spaces"); + // getRequest.setConnection(connection); + } + + @Test + public void shouldSetRequestVerb() throws IOException { + getRequest.send(); + assertEquals("GET", connection.getRequestMethod()); + } + + @Test + public void shouldGetQueryStringParameters() { + assertEquals(2, getRequest.getQueryStringParams().size()); + assertEquals(0, postRequest.getQueryStringParams().size()); + assertTrue(getRequest.getQueryStringParams().contains(new Parameter("qsparam", "value"))); + } + + @Test + public void shouldAddRequestHeaders() throws IOException { + getRequest.addHeader("Header", "1"); + getRequest.addHeader("Header2", "2"); + getRequest.send(); + assertEquals(2, getRequest.getHeaders().size()); + assertEquals(2, connection.getHeaders().size()); + } + + @Test + public void shouldSetBodyParamsAndAddContentLength() throws IOException { + assertEquals("param=value¶m%20with%20spaces=value%20with%20spaces", + postRequest.getBodyContents()); + postRequest.send(); + assertTrue(connection.getHeaders().containsKey("Content-Length")); + } + + @Test + public void shouldSetPayloadAndHeaders() throws IOException { + postRequest.addPayload("PAYLOAD"); + postRequest.send(); + assertEquals("PAYLOAD", postRequest.getBodyContents()); + assertTrue(connection.getHeaders().containsKey("Content-Length")); + } + + @Test + public void shouldAllowAddingQuerystringParametersAfterCreation() { + final Request request = new RequestHttpImpl(Verb.GET, "http://example.com?one=val"); + request.addQuerystringParameter("two", "other val"); + request.addQuerystringParameter("more", "params"); + assertEquals(3, request.getQueryStringParams().size()); + } + + @Test + public void shouldReturnTheCompleteUrl() { + final RequestHttpImpl request = new RequestHttpImpl(Verb.GET, "http://example.com?one=val"); + request.addQuerystringParameter("two", "other val"); + request.addQuerystringParameter("more", "params"); + assertEquals("http://example.com?one=val&two=other%20val&more=params", + request.getCompleteUrl()); + } + + @Test + public void shouldHandleQueryStringSpaceEncodingProperly() { + assertTrue(getRequest.getQueryStringParams().contains( + new Parameter("other param", "value with spaces"))); + } + + @Test + public void shouldAutomaticallyAddContentTypeForPostRequestsWithBytePayload() + throws IOException { + postRequest.addPayload("PAYLOAD".getBytes()); + postRequest.send(); + assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type")); + } + + @Test + public void shouldAutomaticallyAddContentTypeForPostRequestsWithStringPayload() + throws IOException { + postRequest.addPayload("PAYLOAD"); + postRequest.send(); + assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type")); + } + + @Test + public void shouldAutomaticallyAddContentTypeForPostRequestsWithBodyParameters() + throws IOException { + postRequest.send(); + assertEquals(Request.DEFAULT_CONTENT_TYPE, connection.getHeaders().get("Content-Type")); + } + + @Test + public void shouldBeAbleToOverrideItsContentType() throws IOException { + postRequest.addHeader("Content-Type", "my-content-type"); + postRequest.send(); + assertEquals("my-content-type", connection.getHeaders().get("Content-Type")); + } + + @Test + public void shouldNotAddContentTypeForGetRequests() throws IOException { + getRequest.send(); + assertFalse(connection.getHeaders().containsKey("Content-Type")); + } } \ No newline at end of file diff --git a/src/test/java/org/scribe/model/ResponseTest.java b/src/test/java/org/scribe/model/ResponseTest.java index a58fc0355..ca52b9832 100644 --- a/src/test/java/org/scribe/model/ResponseTest.java +++ b/src/test/java/org/scribe/model/ResponseTest.java @@ -1,75 +1,66 @@ -package org.scribe.model; - -import static org.junit.Assert.*; - -import java.io.*; - -import org.junit.*; - -public class ResponseTest -{ - - private Response response; - private ConnectionStub connection; - - @Before - public void setup() throws Exception - { - connection = new ConnectionStub(); - connection.addResponseHeader("one", "one"); - connection.addResponseHeader("two", "two"); - response = new Response(connection); - } - - @Test - public void shouldPopulateResponseHeaders() - { - assertEquals(2, response.getHeaders().size()); - assertEquals("one", response.getHeader("one")); - } - - @Test - public void shouldParseBodyContents() - { - assertEquals("contents", response.getBody()); - assertEquals(1, connection.getTimesCalledInpuStream()); - } - - @Test - public void shouldParseBodyContentsOnlyOnce() - { - assertEquals("contents", response.getBody()); - assertEquals("contents", response.getBody()); - assertEquals("contents", response.getBody()); - assertEquals(1, connection.getTimesCalledInpuStream()); - } - - @Test - public void shouldHandleAConnectionWithErrors() throws Exception - { - Response errResponse = new Response(new FaultyConnection()); - assertEquals(400, errResponse.getCode()); - assertEquals("errors", errResponse.getBody()); - } - - private static class FaultyConnection extends ConnectionStub - { - - public FaultyConnection() throws Exception - { - super(); - } - - @Override - public InputStream getErrorStream() - { - return new ByteArrayInputStream("errors".getBytes()); - } - - @Override - public int getResponseCode() throws IOException - { - return 400; - } - } -} +package org.scribe.model; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Before; +import org.junit.Test; + +public class ResponseTest { + + private Response response; + private ConnectionStub connection; + + @Before + public void setup() throws Exception { + connection = new ConnectionStub(); + connection.addResponseHeader("one", "one"); + connection.addResponseHeader("two", "two"); + response = new ResponseHttpImpl(connection); + } + + @Test + public void shouldPopulateResponseHeaders() { + assertEquals(2, response.getHeaders().size()); + assertEquals("one", response.getHeader("one")); + } + + @Test + public void shouldParseBodyContents() { + assertEquals("contents", response.getBody()); + assertEquals(1, connection.getTimesCalledInpuStream()); + } + + @Test + public void shouldParseBodyContentsOnlyOnce() { + assertEquals("contents", response.getBody()); + assertEquals("contents", response.getBody()); + assertEquals("contents", response.getBody()); + assertEquals(1, connection.getTimesCalledInpuStream()); + } + + @Test + public void shouldHandleAConnectionWithErrors() throws Exception { + final Response errResponse = new ResponseHttpImpl(new FaultyConnection()); + assertEquals(400, errResponse.getCode()); + assertEquals("errors", errResponse.getBody()); + } + + private static class FaultyConnection extends ConnectionStub { + + public FaultyConnection() throws Exception { + super(); + } + + public InputStream getErrorStream() { + return new ByteArrayInputStream("errors".getBytes()); + } + + public int getResponseCode() throws IOException { + return 400; + } + } +} diff --git a/src/test/java/org/scribe/services/RSASha1SignatureServiceTest.java b/src/test/java/org/scribe/services/RSASha1SignatureServiceTest.java deleted file mode 100644 index 2e78e8492..000000000 --- a/src/test/java/org/scribe/services/RSASha1SignatureServiceTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.scribe.services; - -import static org.junit.Assert.*; - -import org.junit.*; - -import javax.xml.bind.DatatypeConverter; -import java.security.*; -import java.security.spec.*; - -public class RSASha1SignatureServiceTest -{ - - RSASha1SignatureService service = new RSASha1SignatureService(getPrivateKey()); - - @Test - public void shouldReturnSignatureMethodString() - { - String expected = "RSA-SHA1"; - assertEquals(expected, service.getSignatureMethod()); - } - - @Test - public void shouldReturnSignature() - { - String apiSecret = "api secret"; - String tokenSecret = "token secret"; - String baseString = "base string"; - String signature = "LUNRzQAlpdNyM9mLXm96Va6g/qVNnEAb7p7K1KM0g8IopOFQJPoOO7cvppgt7w3QyhijWJnCmvqXaaIAGrqvdyr3fIzBULh8D/iZQUNLMi08GCOA34P81XBvsc7A5uJjPDsGhJg2MzoVJ8nWJhU/lMMk4c92S1WGskeoDofRwpo="; - assertEquals(signature, service.getSignature(baseString, apiSecret, tokenSecret)); - } - - /** - *Created primary key using openssl. - * - * openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj '/C=GB/ST=/L=Manchester/CN=www.example.com' -keyout myrsakey.pem -out /tmp/myrsacert.pem - * openssl pkcs8 -in myrsakey.pem -topk8 -nocrypt -out myrsakey.pk8 - */ - private static PrivateKey getPrivateKey() - { - String str = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMPQ5BCMxlUq2TYy\n"+ - "iRIoEUsz6HGTJhHuasS2nx1Se4Co3lxwxyubVdFj8AuhHNJSmJvjlpbTsGOjLZpr\n"+ - "HyDEDdJmf1Fensh1MhUnBZ4a7uLrZrKzFHHJdamX9pxapB89vLeHlCot9hVXdrZH\n"+ - "nNtg6FdmRKH/8gbs8iDyIayFvzYDAgMBAAECgYA+c9MpTBy9cQsR9BAvkEPjvkx2\n"+ - "XL4ZnfbDgpNA4Nuu7yzsQrPjPomiXMNkkiAFHH67yVxwAlgRjyuuQlgNNTpKvyQt\n"+ - "XcHxffnU0820VmE23M+L7jg2TlB3+rUnEDmDvCoyjlwGDR6lNb7t7Fgg2iR+iaov\n"+ - "0iVzz+l9w0slRlyGsQJBAPWXW2m3NmFgqfDxtw8fsKC2y8o17/cnPjozRGtWb8LQ\n"+ - "g3VCb8kbOFHOYNGazq3M7+wD1qILF2h/HecgK9eQrZ0CQQDMHXoJMfKKbrFrTKgE\n"+ - "zyggO1gtuT5OXYeFewMEb5AbDI2FfSc2YP7SHij8iQ2HdukBrbTmi6qxh3HmIR58\n"+ - "I/AfAkEA0Y9vr0tombsUB8cZv0v5OYoBZvCTbMANtzfb4AOHpiKqqbohDOevLQ7/\n"+ - "SpvgVCmVaDz2PptcRAyEBZ5MCssneQJAB2pmvaDH7Ambfod5bztLfOhLCtY5EkXJ\n"+ - "n6rZcDbRaHorRhdG7m3VtDKOUKZ2DF7glkQGV33phKukErVPUzlHBwJAScD9TqaG\n"+ - "wJ3juUsVtujV23SnH43iMggXT7m82STpPGam1hPfmqu2Z0niePFo927ogQ7H1EMJ\n"+ - "UHgqXmuvk2X/Ww=="; - - try - { - KeyFactory fac = KeyFactory.getInstance("RSA"); - PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(DatatypeConverter.parseBase64Binary(str)); - return fac.generatePrivate(privKeySpec); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } -} diff --git a/src/test/java/org/scribe/services/TimestampServiceTest.java b/src/test/java/org/scribe/services/TimestampServiceTest.java index 352b962ca..dc5456868 100644 --- a/src/test/java/org/scribe/services/TimestampServiceTest.java +++ b/src/test/java/org/scribe/services/TimestampServiceTest.java @@ -1,50 +1,42 @@ -package org.scribe.services; - -import static org.junit.Assert.*; - -import org.junit.*; - -public class TimestampServiceTest -{ - - private TimestampServiceImpl service; - private TimestampServiceImpl.Timer timerStub; - - @Before - public void setup() - { - service = new TimestampServiceImpl(); - timerStub = new TimerStub(); - service.setTimer(timerStub); - } - - @Test - public void shouldReturnTimestampInSeconds() - { - String expected = "1000"; - assertEquals(expected, service.getTimestampInSeconds()); - } - - @Test - public void shouldReturnNonce() - { - String expected = "1042"; - assertEquals(expected, service.getNonce()); - } - - private static class TimerStub extends TimestampServiceImpl.Timer - { - - @Override - public Long getMilis() - { - return 1000000L; - } - - @Override - public Integer getRandomInteger() - { - return 42; - } - } -} +package org.scribe.services; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +public class TimestampServiceTest { + + private TimestampServiceImpl service; + private TimestampServiceImpl.Timer timerStub; + + @Before + public void setup() { + service = new TimestampServiceImpl(); + timerStub = new TimerStub(); + service.setTimer(timerStub); + } + + @Test + public void shouldReturnTimestampInSeconds() { + final String expected = "1000"; + assertEquals(expected, service.getTimestampInSeconds()); + } + + @Test + public void shouldReturnNonce() { + final String expected = "1042"; + assertEquals(expected, service.getNonce()); + } + + private static class TimerStub extends TimestampServiceImpl.Timer { + + public long getMilis() { + return 1000000L; + } + + public int getRandomInteger() { + return 42; + } + } +} diff --git a/src/test/java/org/scribe/test/helpers/ObjectMother.java b/src/test/java/org/scribe/test/helpers/ObjectMother.java index a69a3c13a..3e5bd7eef 100644 --- a/src/test/java/org/scribe/test/helpers/ObjectMother.java +++ b/src/test/java/org/scribe/test/helpers/ObjectMother.java @@ -1,17 +1,19 @@ -package org.scribe.test.helpers; - -import org.scribe.model.*; - -public class ObjectMother -{ - - public static OAuthRequest createSampleOAuthRequest() - { - OAuthRequest request = new OAuthRequest(Verb.GET, "http://example.com"); - request.addOAuthParameter(OAuthConstants.TIMESTAMP, "123456"); - request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, "AS#$^*@&"); - request.addOAuthParameter(OAuthConstants.CALLBACK, "http://example/callback"); - request.addOAuthParameter(OAuthConstants.SIGNATURE, "OAuth-Signature"); - return request; - } -} +package org.scribe.test.helpers; + +import org.scribe.model.OAuthConstants; +import org.scribe.model.OAuthRequest; +import org.scribe.model.RequestHttpImpl; +import org.scribe.model.Verb; + +public class ObjectMother { + + public static OAuthRequest createSampleOAuthRequest() { + final RequestHttpImpl httpRequest = new RequestHttpImpl(Verb.GET, "http://example.com"); + final OAuthRequest request = new OAuthRequest(httpRequest); + request.addOAuthParameter(OAuthConstants.TIMESTAMP, "123456"); + request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, "AS#$^*@&"); + request.addOAuthParameter(OAuthConstants.CALLBACK, "http://example/callback"); + request.addOAuthParameter(OAuthConstants.SIGNATURE, "OAuth-Signature"); + return request; + } +}