Issue 114: first support for twitter

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2033 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-10-31 19:35:14 +00:00
parent 3d030cfac0
commit 67612d0f0c
24 changed files with 1997 additions and 28 deletions

View File

@ -51,6 +51,7 @@ import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.inject.AbstractModule;
import com.google.inject.ImplementedBy;
import com.google.inject.Provides;
import com.google.inject.Scopes;
@ -74,22 +75,6 @@ public class ParserModule extends AbstractModule {
}
}
static class DateTimeAdapter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
private final static DateService dateService = new DateService();
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(dateService.iso8601DateFormat(src));
}
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String toParse = json.getAsJsonPrimitive().getAsString();
DateTime toReturn = dateService.jodaIso8601DateParse(toParse);
return toReturn;
}
}
static class InetAddressAdapter implements JsonSerializer<InetAddress>,
JsonDeserializer<InetAddress> {
public JsonElement serialize(InetAddress src, Type typeOfSrc, JsonSerializationContext context) {
@ -127,11 +112,60 @@ public class ParserModule extends AbstractModule {
@Provides
@Singleton
Gson provideGson() {
Gson provideGson(DateTimeAdapter adapter) {
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(InetAddress.class, new InetAddressAdapter());
gson.registerTypeAdapter(DateTime.class, new DateTimeAdapter());
gson.registerTypeAdapter(DateTime.class, adapter);
return gson.create();
}
@ImplementedBy(Iso8601DateTimeAdapter.class)
public static interface DateTimeAdapter extends JsonSerializer<DateTime>,
JsonDeserializer<DateTime> {
}
@Singleton
public static class Iso8601DateTimeAdapter implements DateTimeAdapter {
private final DateService dateService;
@Inject
private Iso8601DateTimeAdapter(DateService dateService) {
this.dateService = dateService;
}
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(dateService.iso8601DateFormat(src));
}
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String toParse = json.getAsJsonPrimitive().getAsString();
DateTime toReturn = dateService.jodaIso8601DateParse(toParse);
return toReturn;
}
}
@Singleton
public static class CDateTimeAdapter implements DateTimeAdapter {
private final DateService dateService;
@Inject
private CDateTimeAdapter(DateService dateService) {
this.dateService = dateService;
}
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(dateService.cDateFormat(src));
}
public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String toParse = json.getAsJsonPrimitive().getAsString();
DateTime toReturn = dateService.cDateParse(toParse);
return toReturn;
}
}
}

View File

@ -67,6 +67,18 @@ public class DateService {
private static final SimpleDateFormat rfc822SimpleDateFormat = new SimpleDateFormat(
"EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
private static final DateTimeFormatter rfc822DateTimeFormatter = DateTimeFormat.forPattern(
"EEE, dd MMM yyyy HH:mm:ss 'GMT'").withLocale(Locale.US).withZone(
DateTimeZone.forID("GMT"));
@GuardedBy("this")
private static final SimpleDateFormat cSimpleDateFormat = new SimpleDateFormat(
"EEE MMM dd HH:mm:ss '+0000' yyyy", Locale.US);
private static final DateTimeFormatter cDateTimeFormatter = DateTimeFormat.forPattern(
"EEE MMM dd HH:mm:ss '+0000' yyyy").withLocale(Locale.US).withZone(
DateTimeZone.forID("GMT"));
private static final DateTimeFormatter iso8601SecondsDateTimeFormatter = DateTimeFormat
.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").withLocale(Locale.US).withZone(
DateTimeZone.forID("GMT"));
@ -75,20 +87,39 @@ public class DateService {
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withLocale(Locale.US).withZone(
DateTimeZone.forID("GMT"));
private static final DateTimeFormatter rfc822DateTimeFormatter = DateTimeFormat.forPattern(
"EEE, dd MMM yyyy HH:mm:ss 'GMT'").withLocale(Locale.US).withZone(
DateTimeZone.forID("GMT"));
static {
iso8601SimpleDateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
iso8601SecondsSimpleDateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
rfc822SimpleDateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
cSimpleDateFormat.setTimeZone(new SimpleTimeZone(0, "GMT"));
}
public final DateTime fromSeconds(long seconds) {
return new DateTime(seconds * 1000);
}
public final String cDateFormat(DateTime dateTime) {
return cDateTimeFormatter.print(dateTime);
}
public final String cDateFormat(Date date) {
return cDateFormat(new DateTime(date));
}
public final String cDateFormat() {
return cDateFormat(new DateTime());
}
public final DateTime cDateParse(String toParse) {
synchronized (cSimpleDateFormat) {
try {
return new DateTime(cSimpleDateFormat.parse(toParse));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
public final String rfc822DateFormat(DateTime dateTime) {
return rfc822DateTimeFormatter.print(dateTime);
}

View File

@ -59,12 +59,15 @@ public class DateServiceTest extends PerformanceTest {
public final String iso8601DateString;
public final String iso8601SecondsDateString;
public final String rfc822DateString;
public final String cDateString;
public final DateTime date;
TestData(String iso8601, String iso8601Seconds, String rfc822, DateTime dateTime) {
TestData(String iso8601, String iso8601Seconds, String rfc822, String cDateString, DateTime dateTime) {
this.iso8601DateString = iso8601;
this.iso8601SecondsDateString = iso8601Seconds;
this.rfc822DateString = rfc822;
this.cDateString= cDateString;
this.date = dateTime;
}
}
@ -73,15 +76,15 @@ public class DateServiceTest extends PerformanceTest {
// Constant time test values, each TestData item must contain matching times!
testData = new TestData[] {
new TestData("2009-03-12T02:00:07.000Z", "2009-03-12T02:00:07Z",
"Thu, 12 Mar 2009 02:00:07 GMT", new DateTime(1236823207000l)),
"Thu, 12 Mar 2009 02:00:07 GMT", "Thu Mar 12 02:00:07 +0000 2009", new DateTime(1236823207000l)),
new TestData("2009-03-14T04:00:07.000Z", "2009-03-14T04:00:07Z",
"Sat, 14 Mar 2009 04:00:07 GMT", new DateTime(1237003207000l)),
"Sat, 14 Mar 2009 04:00:07 GMT", "Thu Mar 14 04:00:07 +0000 2009",new DateTime(1237003207000l)),
new TestData("2009-03-16T06:00:07.000Z", "2009-03-16T06:00:07Z",
"Mon, 16 Mar 2009 06:00:07 GMT", new DateTime(1237183207000l)),
"Mon, 16 Mar 2009 06:00:07 GMT", "Thu Mar 16 06:00:07 +0000 2009",new DateTime(1237183207000l)),
new TestData("2009-03-18T08:00:07.000Z", "2009-03-18T08:00:07Z",
"Wed, 18 Mar 2009 08:00:07 GMT", new DateTime(1237363207000l)),
"Wed, 18 Mar 2009 08:00:07 GMT", "Thu Mar 18 08:00:07 +0000 2009",new DateTime(1237363207000l)),
new TestData("2009-03-20T10:00:07.000Z", "2009-03-20T10:00:07Z",
"Fri, 20 Mar 2009 10:00:07 GMT", new DateTime(1237543207000l)) };
"Fri, 20 Mar 2009 10:00:07 GMT", "Thu Mar 20 10:00:07 +0000 2009",new DateTime(1237543207000l)) };
}
@Test
@ -96,6 +99,12 @@ public class DateServiceTest extends PerformanceTest {
assertEquals(dsDate, testData[0].date);
}
@Test
public void testCDateParse() throws ExecutionException, InterruptedException {
DateTime dsDate = dateService.cDateParse(testData[0].cDateString);
assertEquals(dsDate, testData[0].date);
}
@Test
public void testRfc822DateParse() throws ExecutionException, InterruptedException {
DateTime dsDate = dateService.rfc822DateParse(testData[0].rfc822DateString);
@ -114,6 +123,12 @@ public class DateServiceTest extends PerformanceTest {
assertEquals(dsString, testData[0].iso8601SecondsDateString);
}
@Test
public void testCDateFormat() throws ExecutionException, InterruptedException {
String dsString = dateService.cDateFormat(testData[0].date);
assertEquals(dsString, testData[0].cDateString);
}
@Test
public void testRfc822DateFormat() throws ExecutionException, InterruptedException {
String dsString = dateService.rfc822DateFormat(testData[0].date);
@ -139,6 +154,13 @@ public class DateServiceTest extends PerformanceTest {
dateService.rfc822DateFormat();
}
@Test
void testCDateFormatResponseTime() throws ExecutionException, InterruptedException {
for (int i = 0; i < LOOP_COUNT; i++)
dateService.cDateFormat();
}
@Test
void testFormatIso8601DateCorrectnessInParallel() throws Throwable {
List<Runnable> tasks = new ArrayList<Runnable>(testData.length);

View File

@ -49,6 +49,7 @@
<module>nirvanix</module>
<module>vcloudx</module>
<module>atmosonline</module>
<module>twitter</module>
</modules>
<build>
<plugins>

48
twitter/core/pom.xml Normal file
View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
$HeadURL$
$Revision$
$Date$
Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
====================================================================
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.html
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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-twitter-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-twitter</artifactId>
<name>jclouds twitter core</name>
<packaging>jar</packaging>
<description>jclouds core components to access twitter</description>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk//twitter/core</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk//twitter/core</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk//twitter/core</url>
</scm>
</project>

View File

@ -0,0 +1,44 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* Related to a Twitter resource.
*
* @author Adrian Cole
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface Twitter {
}

View File

@ -0,0 +1,55 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter;
import java.util.SortedSet;
import java.util.concurrent.Future;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.twitter.domain.Status;
import org.jclouds.twitter.functions.ParseStatusesFromJsonResponse;
/**
* Provides access to Twitter via their REST API.
* <p/>
*
* @see <a href= "http://apiwiki.twitter.com/Twitter-REST-API-Method" />
* @author Adrian Cole
*/
@Endpoint(Twitter.class)
@RequestFilters(BasicAuthentication.class)
public interface TwitterClient {
@GET
@ResponseParser(ParseStatusesFromJsonResponse.class)
@Path("/statuses/mentions.json")
Future<SortedSet<Status>> getMyMentions();
}

View File

@ -0,0 +1,61 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Properties;
import org.jclouds.rest.RestContextBuilder;
import org.jclouds.twitter.config.TwitterContextModule;
import org.jclouds.twitter.config.TwitterRestClientModule;
import org.jclouds.twitter.reference.TwitterConstants;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
*
* @author Adrian Cole
*/
public class TwitterContextBuilder extends RestContextBuilder<TwitterClient> {
public TwitterContextBuilder(Properties props) {
super(new TypeLiteral<TwitterClient>() {
}, props);
checkNotNull(properties.getProperty(TwitterConstants.PROPERTY_TWITTER_USER));
checkNotNull(properties.getProperty(TwitterConstants.PROPERTY_TWITTER_PASSWORD));
}
protected void addClientModule(List<Module> modules) {
modules.add(new TwitterRestClientModule());
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new TwitterContextModule());
}
}

View File

@ -0,0 +1,60 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter;
import java.util.Properties;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rest.RestContext;
import com.google.inject.Module;
/**
* Creates {@link RestContext<TwitterClient>} instances based on the most commonly requested
* arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole
* @see RestContext<TwitterClient>
*/
public class TwitterContextFactory {
public static RestContext<TwitterClient> createContext(String user, String key,
Module... modules) {
return new TwitterContextBuilder(new TwitterPropertiesBuilder(user, key).build())
.withModules(modules).buildContext();
}
public static RestContext<TwitterClient> createContext(Properties properties, Module... modules) {
return new TwitterContextBuilder(new TwitterPropertiesBuilder(properties).build())
.withModules(modules).buildContext();
}
}

View File

@ -0,0 +1,69 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.twitter.reference.TwitterConstants.PROPERTY_TWITTER_ENDPOINT;
import static org.jclouds.twitter.reference.TwitterConstants.PROPERTY_TWITTER_PASSWORD;
import static org.jclouds.twitter.reference.TwitterConstants.PROPERTY_TWITTER_USER;
import java.net.URI;
import java.util.Properties;
import org.jclouds.http.HttpPropertiesBuilder;
/**
* Builds properties used in Twitter Clients
*
* @author Adrian Cole
*/
public class TwitterPropertiesBuilder extends HttpPropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_TWITTER_ENDPOINT, "http://twitter.com");
return properties;
}
public TwitterPropertiesBuilder(Properties properties) {
super(properties);
}
public TwitterPropertiesBuilder(String id, String secret) {
super();
withCredentials(id, secret);
}
public TwitterPropertiesBuilder withCredentials(String id, String secret) {
properties.setProperty(PROPERTY_TWITTER_USER, checkNotNull(id, "user"));
properties.setProperty(PROPERTY_TWITTER_PASSWORD, checkNotNull(secret, "key"));
return this;
}
public TwitterPropertiesBuilder withEndpoint(URI endpoint) {
properties.setProperty(PROPERTY_TWITTER_ENDPOINT, checkNotNull(endpoint, "endpoint")
.toString());
return this;
}
}

View File

@ -0,0 +1,61 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter.config;
import java.net.URI;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.http.functions.config.ParserModule.CDateTimeAdapter;
import org.jclouds.http.functions.config.ParserModule.DateTimeAdapter;
import org.jclouds.lifecycle.Closer;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl;
import org.jclouds.twitter.Twitter;
import org.jclouds.twitter.TwitterClient;
import org.jclouds.twitter.reference.TwitterConstants;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* Configures the Twitter connection, including logging and http transport.
*
* @author Adrian Cole
*/
public class TwitterContextModule extends AbstractModule {
@Override
protected void configure() {
bind(DateTimeAdapter.class).to(CDateTimeAdapter.class);
}
@Provides
@Singleton
RestContext<TwitterClient> provideContext(Closer closer, TwitterClient defaultApi, @Twitter URI endPoint,
@Named(TwitterConstants.PROPERTY_TWITTER_USER) String account) {
return new RestContextImpl<TwitterClient>(closer, defaultApi, endPoint, account);
}
}

View File

@ -0,0 +1,88 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter.config;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.twitter.Twitter;
import org.jclouds.twitter.TwitterClient;
import org.jclouds.twitter.reference.TwitterConstants;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* Configures the Twitter connection.
*
* @author Adrian Cole
*/
@RequiresHttp
@ConfiguresRestClient
public class TwitterRestClientModule extends AbstractModule {
@Override
protected void configure() {
bindErrorHandlers();
bindRetryHandlers();
}
@Provides
@Singleton
public BasicAuthentication provideBasicAuthentication(
@Named(TwitterConstants.PROPERTY_TWITTER_USER) String user,
@Named(TwitterConstants.PROPERTY_TWITTER_PASSWORD) String password)
throws UnsupportedEncodingException {
return new BasicAuthentication(user, password);
}
@Provides
@Singleton
protected TwitterClient provideClient(RestClientFactory factory) {
return factory.create(TwitterClient.class);
}
@Provides
@Singleton
@Twitter
protected URI provideURI(@Named(TwitterConstants.PROPERTY_TWITTER_ENDPOINT) String endpoint) {
return URI.create(endpoint);
}
protected void bindErrorHandlers() {
// TODO
}
protected void bindRetryHandlers() {
// TODO
}
}

View File

@ -0,0 +1,190 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com;
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter.domain;
import org.joda.time.DateTime;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*
*/
public class Status implements Comparable<Status> {
@SerializedName("created_at")
private DateTime createdAt;
private boolean favorited;
private String geo;
private long id;
@SerializedName("in_reply_to_screen_name")
private String inReplyToScreenName;
@SerializedName("in_reply_to_status_id")
private Integer inReplyToStatusId;
@SerializedName("in_reply_to_user_id")
private Integer inReplyToUserId;
private String source;
private String text;
private boolean truncated;
private User user;
public Status() {
}
public Status(DateTime createdAt, boolean favorited, String geo, long id,
String inReplyToScreenName, Integer inReplyToStatusId, Integer inReplyToUserId, String source,
String text, boolean truncated, User user) {
this.createdAt = createdAt;
this.favorited = favorited;
this.geo = geo;
this.id = id;
this.inReplyToScreenName = inReplyToScreenName;
this.inReplyToStatusId = inReplyToStatusId;
this.inReplyToUserId = inReplyToUserId;
this.source = source;
this.text = text;
this.truncated = truncated;
this.user = user;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Status other = (Status) obj;
if (id != other.id)
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}
public DateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(DateTime createdAt) {
this.createdAt = createdAt;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public boolean isTruncated() {
return truncated;
}
public void setTruncated(boolean truncated) {
this.truncated = truncated;
}
public Integer getInReplyToStatusId() {
return inReplyToStatusId;
}
public void setInReplyToStatusId(Integer inReplyToStatusId) {
this.inReplyToStatusId = inReplyToStatusId;
}
public Integer getInReplyToUserId() {
return inReplyToUserId;
}
public void setInReplyToUserId(Integer inReplyToUserId) {
this.inReplyToUserId = inReplyToUserId;
}
public boolean isFavorited() {
return favorited;
}
public void setFavorited(boolean favorited) {
this.favorited = favorited;
}
public String getInReplyToScreenName() {
return inReplyToScreenName;
}
public void setInReplyToScreenName(String inReplyToScreenName) {
this.inReplyToScreenName = inReplyToScreenName;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public int compareTo(Status o) {
return (int) ((this == o) ? 0 : id - id);
}
public void setGeo(String geo) {
this.geo = geo;
}
public String getGeo() {
return geo;
}
}

View File

@ -0,0 +1,364 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com;
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter.domain;
import java.net.URI;
import org.joda.time.DateTime;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*
*/
public class User implements Comparable<User> {
@SerializedName("created_at")
private DateTime createdAt;
private String description;
@SerializedName("favourites_count")
private int favouritesCount;
@SerializedName("followers_count")
private int followersCount;
private boolean following;
@SerializedName("friends_count")
private int friendsCount;
@SerializedName("geo_enabled")
private boolean geoEnabled;
private long id;
private String location;
private String name;
private boolean notifications;
@SerializedName("profile_background_color")
private String profileBackgroundColor;
@SerializedName("profile_background_image_url")
private URI profileBackgroundImageUrl;
@SerializedName("profile_background_tile")
private boolean profileBackgroundTile;
@SerializedName("profile_image_url")
private URI profileImageUrl;
@SerializedName("profile_link_color")
private String profileLinkColor;
@SerializedName("profile_sidebar_border_color")
private String profileSidebarBorderColor;
@SerializedName("profile_sidebar_fill_color")
private String profileSidebarFillColor;
@SerializedName("profile_text_color")
private String profileTextColor;
@SerializedName("protected")
private boolean isProtected;
@SerializedName("screen_name")
private String screenName;
@SerializedName("statuses_count")
private int statusesCount;
@SerializedName("time_zone")
private String timeZone;
private URI url;
@SerializedName("utc_offset")
private int utcOffset;
private boolean verified;
public User() {
}
public User(DateTime createdAt, String description, int favouritesCount, int followersCount,
boolean following, int friendsCount, boolean geoEnabled, long id, String location,
String name, boolean notifications, String profileBackgroundColor,
URI profileBackgroundImageUrl, boolean profileBackgroundTile, URI profileImageUrl,
String profileLinkColor, String profileSidebarBorderColor,
String profileSidebarFillColor, String profileTextColor, boolean isProtected,
String screenName, int statusesCount, String timeZone, URI url, int utcOffset,
boolean verified) {
this.createdAt = createdAt;
this.description = description;
this.favouritesCount = favouritesCount;
this.followersCount = followersCount;
this.following = following;
this.friendsCount = friendsCount;
this.setGeoEnabled(geoEnabled);
this.id = id;
this.location = location;
this.name = name;
this.notifications = notifications;
this.profileBackgroundColor = profileBackgroundColor;
this.profileBackgroundImageUrl = profileBackgroundImageUrl;
this.profileBackgroundTile = profileBackgroundTile;
this.profileImageUrl = profileImageUrl;
this.profileLinkColor = profileLinkColor;
this.profileSidebarBorderColor = profileSidebarBorderColor;
this.profileSidebarFillColor = profileSidebarFillColor;
this.profileTextColor = profileTextColor;
this.isProtected = isProtected;
this.screenName = screenName;
this.statusesCount = statusesCount;
this.timeZone = timeZone;
this.url = url;
this.utcOffset = utcOffset;
this.verified = verified;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getScreenName() {
return screenName;
}
public void setScreenName(String screenName) {
this.screenName = screenName;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public URI getProfileImageUrl() {
return profileImageUrl;
}
public void setProfileImageUrl(URI profileImageUrl) {
this.profileImageUrl = profileImageUrl;
}
public URI getUrl() {
return url;
}
public void setUrl(URI url) {
this.url = url;
}
public boolean isProtected() {
return isProtected;
}
public void setProtected(boolean isProtected) {
this.isProtected = isProtected;
}
public int getFollowersCount() {
return followersCount;
}
public void setFollowersCount(int followersCount) {
this.followersCount = followersCount;
}
public String getProfileBackgroundColor() {
return profileBackgroundColor;
}
public void setProfileBackgroundColor(String profileBackgroundColor) {
this.profileBackgroundColor = profileBackgroundColor;
}
public String getProfileTextColor() {
return profileTextColor;
}
public void setProfileTextColor(String profileTextColor) {
this.profileTextColor = profileTextColor;
}
public String getProfileLinkColor() {
return profileLinkColor;
}
public void setProfileLinkColor(String profileLinkColor) {
this.profileLinkColor = profileLinkColor;
}
public String getProfileSidebarFillColor() {
return profileSidebarFillColor;
}
public void setProfileSidebarFillColor(String profileSidebarFillColor) {
this.profileSidebarFillColor = profileSidebarFillColor;
}
public String getProfileSidebarBorderColor() {
return profileSidebarBorderColor;
}
public void setProfileSidebarBorderColor(String profileSidebarBorderColor) {
this.profileSidebarBorderColor = profileSidebarBorderColor;
}
public int getFriendsCount() {
return friendsCount;
}
public void setFriendsCount(int friendsCount) {
this.friendsCount = friendsCount;
}
public DateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(DateTime createdAt) {
this.createdAt = createdAt;
}
public int getFavouritesCount() {
return favouritesCount;
}
public void setFavouritesCount(int favouritesCount) {
this.favouritesCount = favouritesCount;
}
public int getUtcOffset() {
return utcOffset;
}
public void setUtcOffset(int utcOffset) {
this.utcOffset = utcOffset;
}
public String getTimeZone() {
return timeZone;
}
public void setTimeZone(String timeZone) {
this.timeZone = timeZone;
}
public URI getProfileBackgroundImageUrl() {
return profileBackgroundImageUrl;
}
public void setProfileBackgroundImageUrl(URI profileBackgroundImageUrl) {
this.profileBackgroundImageUrl = profileBackgroundImageUrl;
}
public boolean isProfileBackgroundTile() {
return profileBackgroundTile;
}
public void setProfileBackgroundTile(boolean profileBackgroundTile) {
this.profileBackgroundTile = profileBackgroundTile;
}
public int getStatusesCount() {
return statusesCount;
}
public void setStatusesCount(int statusesCount) {
this.statusesCount = statusesCount;
}
public boolean isNotifications() {
return notifications;
}
public void setNotifications(boolean notifications) {
this.notifications = notifications;
}
public boolean isFollowing() {
return following;
}
public void setFollowing(boolean following) {
this.following = following;
}
public boolean isVerified() {
return verified;
}
public void setVerified(boolean verified) {
this.verified = verified;
}
public int compareTo(User o) {
if (screenName == null)
return -1;
return (this == o) ? 0 : screenName.compareTo(o.screenName);
}
public void setGeoEnabled(boolean geoEnabled) {
this.geoEnabled = geoEnabled;
}
public boolean isGeoEnabled() {
return geoEnabled;
}
}

View File

@ -0,0 +1,40 @@
package org.jclouds.twitter.functions;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.SortedSet;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.twitter.domain.Status;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* This parses {@link Status} from a gson string.
*
* @author Adrian Cole
*/
@Singleton
public class ParseStatusesFromJsonResponse extends ParseJson<SortedSet<Status>> {
@Inject
public ParseStatusesFromJsonResponse(Gson gson) {
super(gson);
}
public SortedSet<Status> apply(InputStream stream) {
Type setType = new TypeToken<SortedSet<Status>>() {
}.getType();
try {
return gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}
}
}

View File

@ -0,0 +1,35 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter.reference;
/**
* Configuration properties and constants used in Twitter connections.
*
* @author Adrian Cole
*/
public interface TwitterConstants {
public static final String PROPERTY_TWITTER_ENDPOINT = "jclouds.twitter.endpoint";
public static final String PROPERTY_TWITTER_USER = "jclouds.twitter.user";
public static final String PROPERTY_TWITTER_PASSWORD = "jclouds.twitter.password";
}

View File

@ -0,0 +1,63 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.twitter.domain.Status;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code TwitterClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "twitter.TwitterClientLiveTest")
public class TwitterClientLiveTest {
private TwitterClient connection;
@BeforeGroups(groups = { "live" })
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException {
String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
connection = TwitterContextFactory.createContext(user, password, new Log4JLoggingModule())
.getApi();
}
@Test
public void testGetMyMentions() throws Exception {
SortedSet<Status> response = connection.getMyMentions().get(1, TimeUnit.SECONDS);
assert(response.size() >0);
}
}

View File

@ -0,0 +1,108 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URI;
import javax.inject.Singleton;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.logging.Logger;
import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.twitter.functions.ParseStatusesFromJsonResponse;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code TwitterClient}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "twitter.TwitterClientTest")
public class TwitterClientTest extends RestClientTest<TwitterClient> {
public void testGetMyMentions() throws SecurityException, NoSuchMethodException, IOException {
Method method = TwitterClient.class.getMethod("getMyMentions");
GeneratedHttpRequest<TwitterClient> httpMethod = processor.createRequest(method);
assertRequestLineEquals(httpMethod, "GET http://localhost/tweettest/statuses/mentions.json HTTP/1.1");
assertHeadersEqual(httpMethod, "");
assertEntityEquals(httpMethod, null);
assertResponseParserClassEquals(method, httpMethod, ParseStatusesFromJsonResponse.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(httpMethod);
}
@Override
protected void checkFilters(GeneratedHttpRequest<TwitterClient> httpMethod) {
assertEquals(httpMethod.getFilters().size(), 1);
assertEquals(httpMethod.getFilters().get(0).getClass(), BasicAuthentication.class);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<TwitterClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<TwitterClient>>() {
};
}
@Override
protected Module createModule() {
return new AbstractModule() {
@Override
protected void configure() {
bind(URI.class).annotatedWith(Twitter.class).toInstance(
URI.create("http://localhost/tweettest"));
bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() {
public Logger getLogger(String category) {
return Logger.NULL;
}
});
}
@SuppressWarnings("unused")
@Provides
@Singleton
public BasicAuthentication provideBasicAuthentication()
throws UnsupportedEncodingException {
return new BasicAuthentication("foo", "bar");
}
};
}
}

View File

@ -0,0 +1,98 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl;
import org.jclouds.twitter.config.TwitterRestClientModule;
import org.jclouds.twitter.reference.TwitterConstants;
import org.testng.annotations.Test;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of modules configured in TwitterContextBuilderT
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudfiles.TwitterContextBuilderTest")
public class TwitterContextBuilderTest {
public void testNewBuilder() {
TwitterContextBuilder builder = newBuilder();
assertEquals(builder.getProperties().getProperty(TwitterConstants.PROPERTY_TWITTER_ENDPOINT),
"http://twitter.com");
assertEquals(builder.getProperties().getProperty(TwitterConstants.PROPERTY_TWITTER_USER),
"id");
assertEquals(builder.getProperties().getProperty(TwitterConstants.PROPERTY_TWITTER_PASSWORD),
"secret");
}
public void testBuildContext() {
RestContext<TwitterClient> context = newBuilder().buildContext();
assertEquals(context.getClass(), RestContextImpl.class);
assertEquals(context.getAccount(), "id");
assertEquals(context.getEndPoint(), URI.create("http://twitter.com"));
}
public void testBuildInjector() {
Injector i = newBuilder().buildInjector();
assert i.getInstance(Key.get(new TypeLiteral<RestContext<TwitterClient>>() {
})) != null; // TODO: test all things taken from context
assert i.getInstance(BasicAuthentication.class) != null;
}
protected void testAddContextModule() {
List<Module> modules = new ArrayList<Module>();
TwitterContextBuilder builder = newBuilder();
builder.addContextModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), TwitterRestClientModule.class);
}
private TwitterContextBuilder newBuilder() {
TwitterContextBuilder builder = new TwitterContextBuilder(new TwitterPropertiesBuilder("id",
"secret").build());
return builder;
}
protected void addClientModule() {
List<Module> modules = new ArrayList<Module>();
TwitterContextBuilder builder = newBuilder();
builder.addClientModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), TwitterRestClientModule.class);
}
}

View File

@ -0,0 +1,107 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jclouds.twitter.config;
import static org.testng.Assert.assertEquals;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.http.functions.config.ParserModule.CDateTimeAdapter;
import org.jclouds.http.functions.config.ParserModule.DateTimeAdapter;
import org.jclouds.http.handlers.CloseContentAndSetExceptionErrorHandler;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.http.handlers.RedirectionRetryHandler;
import org.jclouds.logging.Logger;
import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.twitter.reference.TwitterConstants;
import org.jclouds.util.Jsr330;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "twitter.TwitterContextModule")
public class TwitterContextModuleTest {
Injector createInjector() {
return Guice.createInjector(new TwitterRestClientModule(), new TwitterContextModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Jsr330.named(TwitterConstants.PROPERTY_TWITTER_USER)).to(
"user");
bindConstant().annotatedWith(Jsr330.named(TwitterConstants.PROPERTY_TWITTER_PASSWORD))
.to("key");
bindConstant().annotatedWith(Jsr330.named(TwitterConstants.PROPERTY_TWITTER_ENDPOINT))
.to("http://localhost");
bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() {
public Logger getLogger(String category) {
return Logger.NULL;
}
});
super.configure();
}
}, new ParserModule(), new JavaUrlHttpCommandExecutorServiceModule(),
new ExecutorServiceModule(new WithinThreadExecutorService()));
}
@Test
void testServerErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getServerErrorHandler().getClass(),
CloseContentAndSetExceptionErrorHandler.class);
}
@Test
void testDateTimeAdapter() {
assertEquals(this.createInjector().getInstance(DateTimeAdapter.class).getClass(),
CDateTimeAdapter.class);
}
@Test
void testClientErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getClientErrorHandler().getClass(),
CloseContentAndSetExceptionErrorHandler.class);
}
@Test
void testClientRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getClientErrorRetryHandler(), HttpRetryHandler.NEVER_RETRY);
}
@Test
void testRedirectionRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getRedirectionRetryHandler().getClass(), RedirectionRetryHandler.class);
}
}

View File

@ -0,0 +1,125 @@
package org.jclouds.twitter.functions;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.SortedSet;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.twitter.domain.Status;
import org.jclouds.twitter.domain.User;
import org.jclouds.util.DateService;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSortedSet;
import com.google.gson.Gson;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseStatusesFromJsonResponse}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "twitter.ParseStatusesFromJsonResponseTest")
public class ParseStatusesFromJsonResponseTest {
Injector i = Guice.createInjector(new ParserModule() {
@Override
protected void configure() {
bind(DateTimeAdapter.class).to(CDateTimeAdapter.class);
super.configure();
}
});
DateService dateService = new DateService();
public void testApplyInputStreamDetails() throws UnknownHostException {
InputStream is = getClass().getResourceAsStream("/test_mentions.json");
SortedSet<Status> expects = ImmutableSortedSet
.of(
new Status(
dateService.cDateParse("Sat Oct 31 09:35:27 +0000 2009"),
false,
null,
5310690603l,
null,
null,
null,
"<a href=\"http://www.tweetdeck.com/\" rel=\"nofollow\">TweetDeck</a>",
"RT @jclouds: live multi #cloud demo of jclouds connecting to 3 storage clouds from google appengine http://is.gd/4IXMh",
false,
new User(
dateService.cDateParse("Tue Apr 28 15:29:42 +0000 2009"),
"Some random guy who seems to care about cloud collisions at siliconANGLE.com",
245,
572,
false,
325,
false,
36093693,
"San Francisco ",
"James Watters",
false,
"C6E2EE",
URI
.create("http://a1.twimg.com/profile_background_images/24067016/17361976.jpg"),
true,
URI
.create("http://a3.twimg.com/profile_images/445071063/tiktaalik-transitional-fossil_normal.png"),
"1F98C7",
"C6E2EE",
"DAECF4",
"663B12",
false,
"wattersjames",
1964,
"Pacific Time (US & Canada)",
URI
.create("http://siliconangle.net/ver2/author/jwatters/"),
-28800, false)),
new Status(
dateService.cDateParse("Sat Oct 31 01:45:14 +0000 2009"),
false,
null,
5303839785l,
null,
null,
null,
"<a href=\"http://www.tweetdeck.com/\" rel=\"nofollow\">TweetDeck</a>",
"RT @jclouds: come find out about #cloud storage and how to access it from #java in palo alto this Tuesday: http://is.gd/4IFA9",
false,
new User(
dateService.cDateParse("Sat Apr 26 06:13:08 +0000 2008"),
"Jack of All Trades: Dad to anZel and Arden, VMware, vCloud, Security, Compliance, Former Developer",
0,
474,
false,
199,
false,
14540593,
"Bay Area, CA",
"Jian Zhen",
false,
"C6E2EE",
URI
.create("http://s.twimg.com/a/1256778767/images/themes/theme2/bg.gif"),
false,
URI
.create("http://a3.twimg.com/profile_images/64445411/30b8b19_bigger_normal.jpg"),
"1F98C7", "C6E2EE", "DAECF4", "663B12", false, "zhenjl",
1981, "Pacific Time (US & Canada)", URI
.create("http://zhen.org"), -28800, false))
);
ParseStatusesFromJsonResponse parser = new ParseStatusesFromJsonResponse(i
.getInstance(Gson.class));
SortedSet<Status> response = parser.apply(is);
assertEquals(response, expects);
}
}

View File

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
====================================================================
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
====================================================================
-->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--
For more configuration infromation and examples see the Apache Log4j
website: http://logging.apache.org/log4j/
-->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="false">
<!-- A time/date based rolling appender -->
<appender name="WIREFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-wire.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
-->
</layout>
</appender>
<!-- A time/date based rolling appender -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds.log" />
<param name="Append" value="true" />
<!-- Rollover at midnight each day -->
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="Threshold" value="TRACE" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
%m%n"/>
-->
</layout>
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<appender name="ASYNCWIRE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="WIREFILE" />
</appender>
<!-- ================ -->
<!-- Limit categories -->
<!-- ================ -->
<category name="org.jclouds">
<priority value="DEBUG" />
<appender-ref ref="ASYNC" />
</category>
<category name="jclouds.http.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category><!--
<category name="jclouds.http.wire">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
--><!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -0,0 +1,77 @@
[ { "created_at" : "Sat Oct 31 09:35:27 +0000 2009",
"favorited" : false,
"geo" : null,
"id" : 5310690603,
"in_reply_to_screen_name" : null,
"in_reply_to_status_id" : null,
"in_reply_to_user_id" : null,
"source" : "<a href=\"http://www.tweetdeck.com/\" rel=\"nofollow\">TweetDeck</a>",
"text" : "RT @jclouds: live multi #cloud demo of jclouds connecting to 3 storage clouds from google appengine http://is.gd/4IXMh",
"truncated" : false,
"user" : { "created_at" : "Tue Apr 28 15:29:42 +0000 2009",
"description" : "Some random guy who seems to care about cloud collisions at siliconANGLE.com",
"favourites_count" : 245,
"followers_count" : 572,
"following" : false,
"friends_count" : 325,
"geo_enabled" : false,
"id" : 36093693,
"location" : "San Francisco ",
"name" : "James Watters",
"notifications" : false,
"profile_background_color" : "C6E2EE",
"profile_background_image_url" : "http://a1.twimg.com/profile_background_images/24067016/17361976.jpg",
"profile_background_tile" : true,
"profile_image_url" : "http://a3.twimg.com/profile_images/445071063/tiktaalik-transitional-fossil_normal.png",
"profile_link_color" : "1F98C7",
"profile_sidebar_border_color" : "C6E2EE",
"profile_sidebar_fill_color" : "DAECF4",
"profile_text_color" : "663B12",
"protected" : false,
"screen_name" : "wattersjames",
"statuses_count" : 1964,
"time_zone" : "Pacific Time (US & Canada)",
"url" : "http://siliconangle.net/ver2/author/jwatters/",
"utc_offset" : -28800,
"verified" : false
}
},
{ "created_at" : "Sat Oct 31 01:45:14 +0000 2009",
"favorited" : false,
"geo" : null,
"id" : 5303839785,
"in_reply_to_screen_name" : null,
"in_reply_to_status_id" : null,
"in_reply_to_user_id" : null,
"source" : "<a href=\"http://www.tweetdeck.com/\" rel=\"nofollow\">TweetDeck</a>",
"text" : "RT @jclouds: come find out about #cloud storage and how to access it from #java in palo alto this Tuesday: http://is.gd/4IFA9",
"truncated" : false,
"user" : { "created_at" : "Sat Apr 26 06:13:08 +0000 2008",
"description" : "Jack of All Trades: Dad to anZel and Arden, VMware, vCloud, Security, Compliance, Former Developer",
"favourites_count" : 0,
"followers_count" : 474,
"following" : false,
"friends_count" : 199,
"geo_enabled" : false,
"id" : 14540593,
"location" : "Bay Area, CA",
"name" : "Jian Zhen",
"notifications" : false,
"profile_background_color" : "C6E2EE",
"profile_background_image_url" : "http://s.twimg.com/a/1256778767/images/themes/theme2/bg.gif",
"profile_background_tile" : false,
"profile_image_url" : "http://a3.twimg.com/profile_images/64445411/30b8b19_bigger_normal.jpg",
"profile_link_color" : "1F98C7",
"profile_sidebar_border_color" : "C6E2EE",
"profile_sidebar_fill_color" : "DAECF4",
"profile_text_color" : "663B12",
"protected" : false,
"screen_name" : "zhenjl",
"statuses_count" : 1981,
"time_zone" : "Pacific Time (US & Canada)",
"url" : "http://zhen.org",
"utc_offset" : -28800,
"verified" : false
}
}
]

73
twitter/pom.xml Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
$HeadURL$
$Revision$
$Date$
Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
====================================================================
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.html
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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>jclouds-project</artifactId>
<groupId>org.jclouds</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jclouds-twitter-project</artifactId>
<packaging>pom</packaging>
<name>jclouds twitter</name>
<modules>
<module>core</module>
</modules>
<properties>
<jclouds.test.user>${jclouds.twitter.user}</jclouds.test.user>
<jclouds.test.key>${jclouds.twitter.password}</jclouds.test.key>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>