diff --git a/README.textile b/README.textile index 5bad822..f88eaca 100644 --- a/README.textile +++ b/README.textile @@ -76,6 +76,8 @@ h1. Questions? Feel free to drop me an email, but there's already a "StackOvferflow":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 (since 1.3.0), to get additional info. To do this simply call the @.debug()@ method on the @ServiceBuilder@. + h1. About me "LinkedIn profile":http://www.linkedin.com/in/fernandezpablo85 diff --git a/src/main/java/org/scribe/builder/ServiceBuilder.java b/src/main/java/org/scribe/builder/ServiceBuilder.java index 10d0802..b6d3c2c 100644 --- a/src/main/java/org/scribe/builder/ServiceBuilder.java +++ b/src/main/java/org/scribe/builder/ServiceBuilder.java @@ -1,5 +1,6 @@ package org.scribe.builder; +import java.io.*; import org.scribe.builder.api.*; import org.scribe.exceptions.*; import org.scribe.model.*; @@ -21,6 +22,7 @@ public class ServiceBuilder private Api api; private String scope; private SignatureType signatureType; + private OutputStream debugStream; /** * Default constructor @@ -28,6 +30,8 @@ public class ServiceBuilder public ServiceBuilder() { this.callback = OAuthConstants.OUT_OF_BAND; + this.signatureType = SignatureType.Header; + this.debugStream = null; } /** @@ -136,6 +140,19 @@ public class ServiceBuilder this.signatureType = type; return this; } + + public ServiceBuilder debugStream(OutputStream stream) + { + Preconditions.checkNotNull(stream, "debug stream can't be null"); + this.debugStream = stream; + return this; + } + + public ServiceBuilder debug() + { + this.debugStream(System.out); + return this; + } /** * Returns the fully configured {@link OAuthService} @@ -147,6 +164,6 @@ public class ServiceBuilder 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)); + return api.createService(new OAuthConfig(apiKey, apiSecret, callback, signatureType, scope, debugStream)); } } diff --git a/src/main/java/org/scribe/model/OAuthConfig.java b/src/main/java/org/scribe/model/OAuthConfig.java index 314d2d9..a6f0522 100644 --- a/src/main/java/org/scribe/model/OAuthConfig.java +++ b/src/main/java/org/scribe/model/OAuthConfig.java @@ -1,5 +1,7 @@ package org.scribe.model; +import java.io.*; + /** * Parameter object that groups OAuth config values * @@ -12,19 +14,21 @@ public class OAuthConfig 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); + this(key, secret, null, null, null, null); } - public OAuthConfig(String key, String secret, String callback, SignatureType type, String scope) + public OAuthConfig(String key, String secret, String callback, SignatureType type, String scope, OutputStream stream) { this.apiKey = key; this.apiSecret = secret; - this.callback = callback != null ? callback : OAuthConstants.OUT_OF_BAND; - this.signatureType = (type != null) ? type : SignatureType.Header; + this.callback = callback; + this.signatureType = type; this.scope = scope; + this.debugStream = stream; } public String getApiKey() @@ -56,4 +60,20 @@ public class OAuthConfig { return scope != null; } -} \ No newline at end of file + + public void log(String message) + { + if (debugStream != null) + { + message = message + "\n"; + try + { + debugStream.write(message.getBytes("UTF8")); + } + catch (Exception e) + { + // do nothing. + } + } + } +} diff --git a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java index 91e7b71..b847b2d 100644 --- a/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java +++ b/src/main/java/org/scribe/oauth/OAuth10aServiceImpl.java @@ -4,6 +4,7 @@ import java.util.*; import org.scribe.builder.api.*; import org.scribe.model.*; +import org.scribe.utils.*; /** * OAuth 1.0a implementation of {@link OAuthService} @@ -34,12 +35,21 @@ public class OAuth10aServiceImpl implements OAuthService */ public Token getRequestToken() { + 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); - addSignature(request); + appendSignature(request); + + config.log("sending request..."); Response response = request.send(); - return api.getRequestTokenExtractor().extract(response.getBody()); + 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) @@ -51,6 +61,8 @@ public class OAuth10aServiceImpl implements OAuthService 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())); } /** @@ -58,11 +70,14 @@ public class OAuth10aServiceImpl implements OAuthService */ public Token getAccessToken(Token requestToken, Verifier verifier) { + 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); - addSignature(request); + appendSignature(request); Response response = request.send(); return api.getAccessTokenExtractor().extract(response.getBody()); } @@ -72,9 +87,12 @@ public class OAuth10aServiceImpl implements OAuthService */ public void signRequest(Token token, OAuthRequest request) { + config.log("signing request: " + request.getCompleteUrl()); request.addOAuthParameter(OAuthConstants.TOKEN, token.getToken()); + + config.log("setting token to: " + token); addOAuthParams(request, token); - addSignature(request); + appendSignature(request); } /** @@ -95,19 +113,28 @@ public class OAuth10aServiceImpl implements OAuthService private String getSignature(OAuthRequest request, Token token) { + config.log("generating signature..."); String baseString = api.getBaseStringExtractor().extract(request); - return api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret()); + 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 addSignature(OAuthRequest request) + 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()); diff --git a/src/main/java/org/scribe/utils/MapUtils.java b/src/main/java/org/scribe/utils/MapUtils.java new file mode 100644 index 0000000..9e461b8 --- /dev/null +++ b/src/main/java/org/scribe/utils/MapUtils.java @@ -0,0 +1,22 @@ +package org.scribe.utils; + +import java.util.Map; + +/** + * @author: Pablo Fernandez + */ +public class MapUtils +{ + public static String toString(Map map) + { + if (map == null) return ""; + if (map.isEmpty()) return "{}"; + + StringBuilder result = new StringBuilder(); + for(Map.Entry entry : map.entrySet()) + { + result.append(String.format(", %s -> %s ", entry.getKey().toString(), entry.getValue().toString())); + } + return "{" + result.substring(1) + "}"; + } +} diff --git a/src/test/java/org/scribe/builder/ServiceBuilderTest.java b/src/test/java/org/scribe/builder/ServiceBuilderTest.java index fca633b..75a6061 100644 --- a/src/test/java/org/scribe/builder/ServiceBuilderTest.java +++ b/src/test/java/org/scribe/builder/ServiceBuilderTest.java @@ -63,8 +63,7 @@ public class ServiceBuilderTest public static class ApiMock implements Api { public static OAuthConfig config; - - @Override + public OAuthService createService(OAuthConfig config) { ApiMock.config = config; diff --git a/src/test/java/org/scribe/model/OAuthConfigTest.java b/src/test/java/org/scribe/model/OAuthConfigTest.java deleted file mode 100644 index 973d401..0000000 --- a/src/test/java/org/scribe/model/OAuthConfigTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.scribe.model; - -import static org.junit.Assert.*; - -import org.junit.*; - -public class OAuthConfigTest -{ - - @Test - public void shouldReturnDefaultValuesIfNotSet() - { - OAuthConfig config = new OAuthConfig("key", "secret"); - assertEquals(OAuthConstants.OUT_OF_BAND, config.getCallback()); - assertEquals(SignatureType.Header, config.getSignatureType()); - assertFalse(config.hasScope()); - } - - @Test - public void shouldOverrideDefaultsIfSet() - { - OAuthConfig config = new OAuthConfig("key", "secret", "http://callback", SignatureType.Header, "scope"); - assertEquals("http://callback", config.getCallback()); - assertEquals("key", config.getApiKey()); - assertEquals("secret", config.getApiSecret()); - } - -} diff --git a/src/test/java/org/scribe/utils/MapUtilsTest.java b/src/test/java/org/scribe/utils/MapUtilsTest.java new file mode 100644 index 0000000..f44a0f5 --- /dev/null +++ b/src/test/java/org/scribe/utils/MapUtilsTest.java @@ -0,0 +1,35 @@ +package org.scribe.utils; + +import java.util.*; +import org.junit.*; + +/** + * @author: Pablo Fernandez + */ +public class MapUtilsTest +{ + + @Test + public void shouldPrettyPrintMap() + { + Map map = new HashMap(); + map.put(1, "one"); + map.put(2, "two"); + map.put(3, "three"); + map.put(4, "four"); + Assert.assertEquals("{ 1 -> one , 2 -> two , 3 -> three , 4 -> four }", MapUtils.toString(map)); + } + + @Test + public void shouldHandleEmptyMap() + { + Map map = new HashMap(); + Assert.assertEquals("{}", MapUtils.toString(map)); + } + + @Test + public void shouldHandleNullInputs() + { + Assert.assertEquals("", MapUtils.toString(null)); + } +}