Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Use a request factory wrapper to put 'x-li-format' header in requests…
… when used with Spring 3.0 that doesn't support request intercepters.
  • Loading branch information
habuma committed Jan 4, 2012
1 parent 58d8284 commit fdf1574
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 76 deletions.
Expand Up @@ -11,7 +11,7 @@

import org.springframework.social.linkedin.api.ApiStandardProfileRequest;
import org.springframework.social.linkedin.api.CommunicationOperations;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.RestOperations;

/**
* Class that implements communication API for sending messages and invitations
Expand All @@ -20,10 +20,10 @@
*
*/
public class CommunicationTemplate implements CommunicationOperations {
private final RestTemplate restTemplate;
private final RestOperations restOperations;

public CommunicationTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
public CommunicationTemplate(RestOperations restOperations) {
this.restOperations = restOperations;
}

public void sendMessage(String subject, String body, List<String> recipientIds) {
Expand All @@ -33,7 +33,7 @@ public void sendMessage(String subject, String body, List<String> recipientIds)
mailboxItem.put("subject", subject);
mailboxItem.put("body", body);

restTemplate.postForLocation(MESSAGING_URL, mailboxItem);
restOperations.postForLocation(MESSAGING_URL, mailboxItem);
}

public void sendMessage(String subject, String body, String... recipientIds) {
Expand All @@ -49,7 +49,7 @@ public void connectTo(String subject, String body, String recipientId, ApiStanda
String[] nameValue = apiStandardProfileRequest.getValue().split(":");
mailboxItem.put("itemContent", new ItemContent(nameValue[0], nameValue[1]));

restTemplate.postForLocation(MESSAGING_URL, mailboxItem);
restOperations.postForLocation(MESSAGING_URL, mailboxItem);
}

public void connectTo(String subject, String body, String email, String firstName, String lastName) {
Expand All @@ -60,7 +60,7 @@ public void connectTo(String subject, String body, String email, String firstNam
mailboxItem.put("body", body);
mailboxItem.put("itemContent", new ItemContent());

restTemplate.postForLocation(MESSAGING_URL, mailboxItem);
restOperations.postForLocation(MESSAGING_URL, mailboxItem);
}


Expand Down
Expand Up @@ -10,33 +10,33 @@
import org.springframework.social.linkedin.api.CompanyOperations;
import org.springframework.social.linkedin.api.ProductResult;
import org.springframework.social.linkedin.api.SearchResultCompany;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.RestOperations;

/**
* Class that implements Company API for searching for and getting Companies
* @author Robert Drysdale
*
*/
public class CompanyTemplate extends AbstractTemplate implements CompanyOperations {
private final RestTemplate restTemplate;
private final RestOperations restOperations;
private final ObjectMapper objectMapper;

public CompanyTemplate(RestTemplate restTemplate, ObjectMapper objectMapper) {
this.restTemplate = restTemplate;
public CompanyTemplate(RestOperations RestOperations, ObjectMapper objectMapper) {
this.restOperations = RestOperations;
this.objectMapper = objectMapper;
}

public Company getCompany(int id) {
return restTemplate.getForObject(COMPANY_URL, Company.class, "/" + id, "");
return restOperations.getForObject(COMPANY_URL, Company.class, "/" + id, "");
}

public Company getCompanyByUniversalName(String name) {
return restTemplate.getForObject(COMPANY_URL, Company.class, "/universal-name=" + name, "");
return restOperations.getForObject(COMPANY_URL, Company.class, "/universal-name=" + name, "");
}

public List<Company> getCompaniesByEmailDomain(String domain) {
String[] params = new String[] { "", "email-domain=" + domain};
JsonNode node = restTemplate.getForObject(expand(COMPANY_URL, params, false), JsonNode.class);
JsonNode node = restOperations.getForObject(expand(COMPANY_URL, params, false), JsonNode.class);

try {
return objectMapper.readValue(node.path("values"), new TypeReference<List<Company>>(){});
Expand All @@ -47,7 +47,7 @@ public List<Company> getCompaniesByEmailDomain(String domain) {
}

public SearchResultCompany search(String keywords) {
JsonNode node = restTemplate.getForObject(COMPANY_SEARCH_URL, JsonNode.class, keywords);
JsonNode node = restOperations.getForObject(COMPANY_SEARCH_URL, JsonNode.class, keywords);
try {
return objectMapper.readValue(node.path("companies"), new TypeReference<SearchResultCompany>(){});
}
Expand All @@ -57,7 +57,7 @@ public SearchResultCompany search(String keywords) {
}

public List<Company> getFollowing() {
JsonNode node = restTemplate.getForObject(COMPANY_FOLLOW_URL, JsonNode.class);
JsonNode node = restOperations.getForObject(COMPANY_FOLLOW_URL, JsonNode.class);
try {
return objectMapper.readValue(node.path("values"), new TypeReference<List<Company>>(){});
}
Expand All @@ -67,7 +67,7 @@ public List<Company> getFollowing() {
}

public List<Company> getSuggestionsToFollow() {
JsonNode node = restTemplate.getForObject(COMPANY_SUGGESTIONS_TO_FOLLOW, JsonNode.class);
JsonNode node = restOperations.getForObject(COMPANY_SUGGESTIONS_TO_FOLLOW, JsonNode.class);
try {
return objectMapper.readValue(node.path("values"), new TypeReference<List<Company>>(){});
}
Expand All @@ -77,15 +77,15 @@ public List<Company> getSuggestionsToFollow() {
}

public void startFollowingCompany(int id) {
restTemplate.postForLocation(COMPANY_FOLLOW_START_STOP_URL, Collections.singletonMap("id", id));
restOperations.postForLocation(COMPANY_FOLLOW_START_STOP_URL, Collections.singletonMap("id", id));
}

public void stopFollowingCompany(int id) {
restTemplate.delete(COMPANY_FOLLOW_START_STOP_URL, id);
restOperations.delete(COMPANY_FOLLOW_START_STOP_URL, id);
}

public ProductResult getProducts(int companyId, int start, int count) {
return restTemplate.getForObject(PRODUCTS_URL, ProductResult.class, companyId, start, count);
return restOperations.getForObject(PRODUCTS_URL, ProductResult.class, companyId, start, count);
}

public static final String BASE_URL = "https://api.linkedin.com/v1/";
Expand Down
@@ -1,14 +1,14 @@
package org.springframework.social.linkedin.api.impl;

import static org.springframework.social.linkedin.api.impl.LinkedInTemplate.BASE_URL;
import static org.springframework.social.linkedin.api.impl.LinkedInTemplate.*;

import java.util.List;

import org.springframework.social.linkedin.api.ConnectionOperations;
import org.springframework.social.linkedin.api.LinkedInConnections;
import org.springframework.social.linkedin.api.LinkedInProfile;
import org.springframework.social.linkedin.api.NetworkStatistics;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.RestOperations;

/**
* Class that implements Connection API
Expand All @@ -17,19 +17,19 @@
*
*/
public class ConnectionTemplate implements ConnectionOperations {
private final RestTemplate restTemplate;
private final RestOperations restOperations;

public ConnectionTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
public ConnectionTemplate(RestOperations restOperations) {
this.restOperations = restOperations;
}

public List<LinkedInProfile> getConnections() {
LinkedInConnections connections = restTemplate.getForObject(CONNECTIONS_URL, LinkedInConnections.class);
LinkedInConnections connections = restOperations.getForObject(CONNECTIONS_URL, LinkedInConnections.class);
return connections.getConnections();
}

public NetworkStatistics getNetworkStatistics(){
return restTemplate.getForObject(STATISTICS_URL, NetworkStatistics.class);
return restOperations.getForObject(STATISTICS_URL, NetworkStatistics.class);
}

static final String CONNECTIONS_URL = BASE_URL + "~/connections?format=json";
Expand Down
Expand Up @@ -11,7 +11,7 @@
import org.springframework.social.linkedin.api.JobOperations;
import org.springframework.social.linkedin.api.JobSearchParameters;
import org.springframework.social.linkedin.api.SearchResultJob;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.RestOperations;

/**
* Class that implements Job API
Expand All @@ -20,11 +20,11 @@
*
*/
public class JobTemplate extends AbstractTemplate implements JobOperations {
private final RestTemplate restTemplate;
private final RestOperations restOperations;
private final ObjectMapper objectMapper;

public JobTemplate(RestTemplate restTemplate, ObjectMapper objectMapper ) {
this.restTemplate = restTemplate;
public JobTemplate(RestOperations restOperations, ObjectMapper objectMapper ) {
this.restOperations = restOperations;
this.objectMapper = objectMapper;
}

Expand All @@ -41,7 +41,7 @@ public SearchResultJob searchJobs(JobSearchParameters parameters) {
parameters.getSort()
};

JsonNode node = restTemplate.getForObject(expand(SEARCH_URL, params, true), JsonNode.class);
JsonNode node = restOperations.getForObject(expand(SEARCH_URL, params, true), JsonNode.class);

try {
return objectMapper.readValue(node.path("jobs"), new TypeReference<SearchResultJob>() {});
Expand All @@ -52,23 +52,23 @@ public SearchResultJob searchJobs(JobSearchParameters parameters) {
}

public Job getJob(int id) {
return restTemplate.getForObject(JOB_URL, Job.class, id);
return restOperations.getForObject(JOB_URL, Job.class, id);
}

public void bookmarkJob(int id) {
Map<String, Map<String,Integer>> jobDetails = new HashMap<String,Map<String,Integer>>();
Map<String,Integer>idDetails = new HashMap<String,Integer>();
jobDetails.put("job", idDetails);
idDetails.put("id", id);
restTemplate.postForLocation(BOOKMARK_URL, jobDetails);
restOperations.postForLocation(BOOKMARK_URL, jobDetails);
}

public void unbookmarkJob(int id) {
restTemplate.delete(UNBOOKMARK_URL, id);
restOperations.delete(UNBOOKMARK_URL, id);
}

public SearchResultJob getSuggestions(int start, int count) {
JsonNode node = restTemplate.getForObject(expand(SUGGESTED_URL, new Object[] {start,count}, false), JsonNode.class);
JsonNode node = restOperations.getForObject(expand(SUGGESTED_URL, new Object[] {start,count}, false), JsonNode.class);

try {
return objectMapper.readValue(node.path("jobs"), new TypeReference<SearchResultJob>() {});
Expand All @@ -79,7 +79,7 @@ public SearchResultJob getSuggestions(int start, int count) {
}

public JobBookmarkResult getBookmarks(int start, int count) {
return restTemplate.getForObject(expand(BOOKMARKS_URL, new Object[] {start,count}, false), JobBookmarkResult.class);
return restOperations.getForObject(expand(BOOKMARKS_URL, new Object[] {start,count}, false), JobBookmarkResult.class);

}

Expand Down
@@ -0,0 +1,80 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.social.linkedin.api.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;

/**
* @author Craig Walls
*/
class JsonFormatHeaderRequestFactory implements ClientHttpRequestFactory {

private final ClientHttpRequestFactory delegate;

public JsonFormatHeaderRequestFactory(ClientHttpRequestFactory delegate) {
this.delegate = delegate;
}

public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
return new JsonFormatWrappedRequest(delegate.createRequest(uri, httpMethod));
}

private static class JsonFormatWrappedRequest implements ClientHttpRequest {

private final ClientHttpRequest delegate;

private ByteArrayOutputStream bodyOutputStream;

public JsonFormatWrappedRequest(ClientHttpRequest delegate) {
this.delegate = delegate;
this.bodyOutputStream = new ByteArrayOutputStream();
}

public ClientHttpResponse execute() throws IOException {
byte[] bufferedOutput = bodyOutputStream.toByteArray();
delegate.getBody().write(bufferedOutput);
delegate.getHeaders().set("x-li-format", "json");
return delegate.execute();
}

public URI getURI() {
return delegate.getURI();
}

public HttpMethod getMethod() {
return delegate.getMethod();
}

public HttpHeaders getHeaders() {
return delegate.getHeaders();
}

public OutputStream getBody() throws IOException {
return bodyOutputStream;
}

}

}
Expand Up @@ -24,6 +24,7 @@
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.HttpMessageConverter;
Expand All @@ -38,6 +39,8 @@
import org.springframework.social.linkedin.api.impl.json.LinkedInModule;
import org.springframework.social.oauth1.AbstractOAuth1ApiBinding;
import org.springframework.social.support.HttpRequestDecorator;
import org.springframework.util.ClassUtils;
import org.springframework.web.client.RestTemplate;

/**
* This is the central class for interacting with LinkedIn.
Expand Down Expand Up @@ -113,9 +116,17 @@ private void registerLinkedInJsonModule() {
* which suggests its expecting xml rather than json.
* API appears to ignore Content-Type header
*/
private void registerJsonFormatInterceptor() {
List<ClientHttpRequestInterceptor> interceptors = getRestTemplate().getInterceptors();
interceptors.add(new JsonFormatInterceptor());
private void registerJsonFormatInterceptor() {
RestTemplate restTemplate = getRestTemplate();
if (interceptorsSupported) {
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
interceptors.add(new JsonFormatInterceptor());
} else {
// for Spring 3.0.x where interceptors aren't supported
ClientHttpRequestFactory originalRequestFactory = restTemplate.getRequestFactory();
JsonFormatHeaderRequestFactory newRequestFactory = new JsonFormatHeaderRequestFactory(originalRequestFactory);
restTemplate.setRequestFactory(newRequestFactory);
}
}

private void initSubApis() {
Expand All @@ -141,6 +152,8 @@ private void initSubApis() {

private ObjectMapper objectMapper;

private static boolean interceptorsSupported = ClassUtils.isPresent("org.springframework.http.client.ClientHttpRequestInterceptor", LinkedInTemplate.class.getClassLoader());

static final String BASE_URL = "https://api.linkedin.com/v1/people/";

private static final class JsonFormatInterceptor implements ClientHttpRequestInterceptor {
Expand Down

0 comments on commit fdf1574

Please sign in to comment.