Skip to content

Commit

Permalink
get binary data posting working, through some hacky code, move some v…
Browse files Browse the repository at this point in the history
…alidation around, finish up testing
  • Loading branch information
sdouglass committed Nov 22, 2011
1 parent 7ac7b46 commit 0663f5e
Show file tree
Hide file tree
Showing 14 changed files with 534 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public interface BlogPostOperations {

void edit(ModifyPost post);

void reblog(ModifyReblogPost reblogPost);
void reblog(ReblogPost reblogPost);

void delete(long id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ public MultiValueMap<String, String> toParameterMap() {
map.add("external_url", externalUrl);
} else if (data != null) {
map.add("data", convertResourceToString(data));
} else {
throw new IllegalArgumentException("external_url and data cannot both be null");
}

if (caption != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ public MultiValueMap<String, String> toParameterMap() {
String bytesString = convertResourceToString(resource);
map.add("data[" + i + "]", bytesString);
}
} else {
throw new IllegalArgumentException("source and data cannot both be null");
}

if (caption != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@

import org.springframework.core.io.Resource;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.util.*;

import java.io.*;
import java.net.URLEncoder;
import java.util.*;

/**
* @author sam
* @version $Id$
*/
@SuppressWarnings("unused")
public abstract class ModifyPost {

private Long id;
Expand Down Expand Up @@ -135,33 +134,16 @@ public MultiValueMap<String, String> toParameterMap() {
return map;
}

// TODO figure out how to do this the way Tumblr expects
String convertResourceToString(Resource resource) {
try {
// Reader reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), "UTF8"));
// String bytesString = FileCopyUtils.copyToString(reader);
byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
// bytes = Base64.encode(bytes);
String bytesString = new String(bytes);
// bytesString = bytesString.replaceAll("/", "%2F");
// StringBuilder sb = new StringBuilder();
// for (byte b : bytes) {
// sb.append(Integer.toHexString((int) (b & 0xff)));
// }
// return sb.toString();
// return new String(bytes);
System.err.println("bytesString");
System.err.println(bytesString);
System.err.println("url encoded");
System.err.println(URLEncoder.encode(bytesString, "UTF-8"));
System.err.println("oauth encoded");
System.err.println(oauthEncode(bytesString));
return bytesString;
return new String(bytes, "LATIN1");
} catch (IOException e) {
throw new RuntimeException(e);
}
}

// from Spring Social Core SigningSupport, would reuse but these methods are private and the class has package access
private static final BitSet UNRESERVED;

static {
Expand Down Expand Up @@ -189,7 +171,8 @@ String convertResourceToString(Resource resource) {
private static String oauthEncode(String param) {
try {
// See http://tools.ietf.org/html/rfc5849#section-3.6
byte[] bytes = encode(param.getBytes("UTF-8"), UNRESERVED);
// however, Tumblr appears to use LATIN1, not UTF-8, for binary data
byte[] bytes = encode(param.getBytes("LATIN1"), UNRESERVED);
return new String(bytes, "US-ASCII");
} catch (Exception shouldntHappen) {
throw new IllegalStateException(shouldntHappen);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ public MultiValueMap<String, String> toParameterMap() {
map.add("embed", embed);
} else if (data != null) {
map.add("data", convertResourceToString(data));
} else {
throw new IllegalArgumentException("embed and data cannot both be null");
}

if (caption != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
* @author sam
* @version $Id$
*/
public class ModifyReblogPost extends ModifyPost {
public class ReblogPost extends ModifyPost {

private String reblogKey;
private String comment;

public ModifyReblogPost() {
public ReblogPost() {
super(PostType.REBLOG);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package org.springframework.social.tumblr.api.impl;

import org.springframework.social.tumblr.api.BlogPostOperations;
import org.springframework.social.tumblr.api.ModifyPost;
import org.springframework.social.tumblr.api.ModifyReblogPost;
import org.springframework.social.tumblr.api.*;
import org.springframework.social.tumblr.api.impl.json.TumblrResponse;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
Expand All @@ -18,6 +16,56 @@ public BlogPostTemplate(RestTemplate restTemplate, boolean isAuthorized, String
}

public void create(ModifyPost post) {
if (post == null) {
throw new IllegalArgumentException("post must not be null");
}
if (post.getType() == null) {
throw new IllegalArgumentException("type must not be null");
}
switch (post.getType()) {
case TEXT:
ModifyTextPost textPost = (ModifyTextPost) post;
if (textPost.getBody() == null) {
throw new IllegalArgumentException("body must not be null for text posts");
}
break;
case PHOTO:
ModifyPhotoPost photoPost = (ModifyPhotoPost) post;
if (photoPost.getData() == null && photoPost.getSource() == null) {
throw new IllegalArgumentException("data or source must not be null for photo posts");
}
break;
case QUOTE:
ModifyQuotePost quotePost = (ModifyQuotePost) post;
if (quotePost.getQuote() == null) {
throw new IllegalArgumentException("quote must not be null for quote posts");
}
break;
case LINK:
ModifyLinkPost linkPost = (ModifyLinkPost) post;
if (linkPost.getUrl() == null) {
throw new IllegalArgumentException("url must not be null for link posts");
}
break;
case CHAT:
ModifyChatPost chatPost = (ModifyChatPost) post;
if (chatPost.getConversation() == null) {
throw new IllegalArgumentException("conversation must not be null for chat posts");
}
break;
case AUDIO:
ModifyAudioPost audioPost = (ModifyAudioPost) post;
if (audioPost.getData() == null && audioPost.getExternalUrl() == null) {
throw new IllegalArgumentException("data or external url must not be null for audio posts");
}
break;
case VIDEO:
ModifyVideoPost videoPost = (ModifyVideoPost) post;
if (videoPost.getData() == null && videoPost.getEmbed() == null) {
throw new IllegalArgumentException("data or embed must not be null for video posts");
}
break;
}
requireAuthorization();
MultiValueMap<String, String> map = post.toParameterMap();
// get the response
Expand All @@ -39,7 +87,16 @@ public void edit(ModifyPost post) {
getRestTemplate().postForObject(buildUri("post/edit"), map, TumblrResponse.class);
}

public void reblog(ModifyReblogPost post) {
public void reblog(ReblogPost post) {
if (post == null) {
throw new IllegalArgumentException("post must not be null");
}
if (post.getId() == null) {
throw new IllegalArgumentException("post id must not be null");
}
if (post.getReblogKey() == null) {
throw new IllegalArgumentException("reblog key must not be null");
}
requireAuthorization();
MultiValueMap<String, String> map = post.toParameterMap();
// need to strip type? can't send type? don't know...???
Expand All @@ -50,7 +107,7 @@ public void reblog(ModifyReblogPost post) {

public void delete(long id) {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("id", id);
map.add("id", Long.toString(id));
// don't care about response
getRestTemplate().postForObject(buildUri("post/delete"), map, TumblrResponse.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public BlogPostsTemplate(RestTemplate restTemplate, boolean isAuthorized, String

public Posts search(PostsQuery query) {
requireApiKey();
if (query == null) {
query = new PostsQuery();
}
return getRestTemplate().getForObject(buildUri("posts", "api_key", getApiKey()).toString(), Posts.class, query.toParameterMap());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public BlogInfo info() {
}

public String avatar(AvatarSize size) {
if (size == null) {
throw new IllegalArgumentException("size must not be null");
}
HttpHeaders headers = getRestTemplate().headForHeaders(buildUri("avatar/" + size.getDimension()));
return headers.getLocation().toString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.springframework.social.tumblr.api.impl;

/**
* Bean for OAuth credentials. Copy of Spring Socials' OAuth1Credentials, which is not public.
*
* @author sam
* @version $Id$
*/
public class TumblrOAuth1Credentials {
private final String consumerKey;

private final String consumerSecret;

private final String accessToken;

private final String accessTokenSecret;

public TumblrOAuth1Credentials(String consumerKey, String consumerSecret, String accessToken, String accessTokenSecret) {
this.consumerKey = consumerKey;
this.consumerSecret = consumerSecret;
this.accessToken = accessToken;
this.accessTokenSecret = accessTokenSecret;
}

public String getConsumerKey() {
return consumerKey;
}

public String getConsumerSecret() {
return consumerSecret;
}

public String getAccessToken() {
return accessToken;
}

public String getAccessTokenSecret() {
return accessTokenSecret;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.springframework.social.tumblr.api.impl;

import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.social.support.HttpRequestDecorator;

import java.io.IOException;

/**
* Copy of Spring Social's OAuth1RequestInterceptor, which is not public. Uses a
* custom version of Spring Social's also not-public SigningSupport class.
*
* @author sam
* @version $Id$
*/
public class TumblrOAuth1RequestInterceptor implements ClientHttpRequestInterceptor {

private final TumblrSigningSupport signingUtils;
private final TumblrTemplate tumblrTemplate;

public TumblrOAuth1RequestInterceptor(TumblrTemplate tumblrTemplate) {
this.tumblrTemplate = tumblrTemplate;
this.signingUtils = new TumblrSigningSupport();
}

public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpRequest protectedResourceRequest = new HttpRequestDecorator(request);
protectedResourceRequest.getHeaders().add("Authorization", getAuthorizationHeaderValue(request, body));
return execution.execute(protectedResourceRequest, body);
}

// internal helpers

private String getAuthorizationHeaderValue(HttpRequest request, byte[] body) {
return signingUtils.buildAuthorizationHeaderValue(request, body, tumblrTemplate.getCredentials());
}
}
Loading

0 comments on commit 0663f5e

Please sign in to comment.