fixed base archetype and removed twitter client

This commit is contained in:
Adrian Cole 2010-09-18 16:12:38 -07:00
parent 2ae3cdcc34
commit af394c46a6
47 changed files with 390 additions and 2003 deletions

View File

@ -39,8 +39,8 @@ our blobstore api supports: s3, rackspace, azure, atmos online, att synaptic,
* note * the pom dependency org.jclouds/jclouds-allblobstore gives you access to * note * the pom dependency org.jclouds/jclouds-allblobstore gives you access to
to all of these providers to all of these providers
we also have rest clients for: chef, opscodeplatform, twitter, as well a number of features we also have support for: ibmdev, mezeo, nirvanix, boxdotnet, as well a number of features
in the sandbox the sandbox
If you want access to all jclouds components, include the maven dependency org.jclouds/jclouds-all If you want access to all jclouds components, include the maven dependency org.jclouds/jclouds-all

View File

@ -39,10 +39,5 @@
<artifactId>jclouds-allblobstore</artifactId> <artifactId>jclouds-allblobstore</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-twitter</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -32,8 +32,8 @@
</requiredProperty> </requiredProperty>
<requiredProperty key="providerName" /> <requiredProperty key="providerName" />
<requiredProperty key="providerEndpoint" /> <requiredProperty key="providerEndpoint" />
<requiredProperty key="providerAccount" /> <requiredProperty key="providerIdentity" />
<requiredProperty key="providerKey" /> <requiredProperty key="providerCredential" />
</requiredProperties> </requiredProperties>
<fileSets> <fileSets>
<fileSet filtered="true" packaged="true" encoding="UTF-8"> <fileSet filtered="true" packaged="true" encoding="UTF-8">

View File

@ -1,94 +0,0 @@
#set( $lcaseProviderName = ${providerName.toLowerCase()} )
#set( $symbol_dollar = '$' )
<?xml version="1.0" encoding="UTF-8"?>
<!--
${symbol_dollar}HeadURL${symbol_dollar}
${symbol_dollar}Revision${symbol_dollar}
${symbol_dollar}Date${symbol_dollar}
Copyright (C) 2010 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.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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../project/pom.xml</relativePath>
</parent>
<groupId>${groupId}</groupId>
<artifactId>jclouds-${artifactId}</artifactId>
<name>jclouds ${providerName} core</name>
<description>jclouds components to access ${providerName}</description>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/${lcaseProviderName}</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/${lcaseProviderName}</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/${lcaseProviderName}</url>
</scm>
<!-- bootstrapping: need to fetch the project POM -->
<repositories>
<repository>
<id>jclouds-googlecode-deploy</id>
<url>http://jclouds.googlecode.com/svn/repo</url>
</repository>
<repository>
<id>jclouds-rimu-snapshots-nexus</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<jclouds.test.identity>${providerAccount}</jclouds.test.identity>
<jclouds.test.credential>${providerKey}</jclouds.test.credential>
</properties>
<dependencies>
<dependency>
<groupId>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${symbol_dollar}{project.version}</version>
</dependency>
<dependency>
<groupId>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${symbol_dollar}{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>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${symbol_dollar}{project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,42 +0,0 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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 ${package};
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 ${providerName} resource.
*
* @author ${author}
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface ${providerName} {
}

View File

@ -1,66 +0,0 @@
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 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 ${package};
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Properties;
import org.jclouds.rest.RestContextBuilder;
import ${package}.${providerName}AsyncClient;
import ${package}.${providerName}Client;
import ${package}.config.${providerName}ContextModule;
import ${package}.config.${providerName}RestClientModule;
import ${package}.reference.${providerName}Constants;
import com.google.inject.Module;
/**
*
* @author ${author}
*/
public class ${providerName}ContextBuilder extends RestContextBuilder<${providerName}Client, ${providerName}AsyncClient> {
public ${providerName}ContextBuilder(String providerName, Properties props) {
super(providerName, ${providerName}Client.class, ${providerName}AsyncClient.class, props);
checkNotNull(properties.getProperty(${providerName}Constants.PROPERTY_${ucaseProviderName}_USER));
checkNotNull(properties.getProperty(${providerName}Constants.PROPERTY_${ucaseProviderName}_PASSWORD));
}
protected void addClientModule(List<Module> modules) {
modules.add(new ${providerName}RestClientModule());
}
@Override
protected void addContextModule(String providerName, List<Module> modules) {
modules.add(new ${providerName}ContextModule(providerName));
}
}

View File

@ -1,72 +0,0 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 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 ${package};
import java.net.URI;
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} for {@link ${providerName}Client} 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 ${author}
* @see RestContext
* @see ${providerName}Client
* @see ${providerName}AsyncClient
*/
public class ${providerName}ContextFactory {
public static RestContext<${providerName}Client, ${providerName}AsyncClient> createContext(String user, String password,
Module... modules) {
return new ${providerName}ContextBuilder("${artifactId}", new ${providerName}PropertiesBuilder(user, password).build())
.withModules(modules).buildContext();
}
public static RestContext<${providerName}Client, ${providerName}AsyncClient> createContext(URI endpoint, String user, String password,
Module... modules) {
return new ${providerName}ContextBuilder("${artifactId}", new ${providerName}PropertiesBuilder(user, password).withEndpoint(endpoint).build())
.withModules(modules).buildContext();
}
public static RestContext<${providerName}Client, ${providerName}AsyncClient> createContext(Properties properties, Module... modules) {
return new ${providerName}ContextBuilder("${artifactId}", new ${providerName}PropertiesBuilder(properties).build())
.withModules(modules).buildContext();
}
}

View File

@ -1,73 +0,0 @@
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 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 ${package};
import static com.google.common.base.Preconditions.checkNotNull;
import static ${package}.reference.${providerName}Constants.PROPERTY_${ucaseProviderName}_ENDPOINT;
import static ${package}.reference.${providerName}Constants.PROPERTY_${ucaseProviderName}_PASSWORD;
import static ${package}.reference.${providerName}Constants.PROPERTY_${ucaseProviderName}_USER;
import java.net.URI;
import java.util.Properties;
import org.jclouds.PropertiesBuilder;
/**
* Builds properties used in ${providerName} Clients
*
* @author ${author}
*/
public class ${providerName}PropertiesBuilder extends PropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_${ucaseProviderName}_ENDPOINT, "${providerEndpoint}");
return properties;
}
public ${providerName}PropertiesBuilder(Properties properties) {
super(properties);
}
public ${providerName}PropertiesBuilder(String id, String secret) {
super();
withCredentials(id, secret);
}
public ${providerName}PropertiesBuilder withCredentials(String id, String secret) {
properties.setProperty(PROPERTY_${ucaseProviderName}_USER, checkNotNull(id, "user"));
properties.setProperty(PROPERTY_${ucaseProviderName}_PASSWORD, checkNotNull(secret, "password"));
return this;
}
public ${providerName}PropertiesBuilder withEndpoint(URI endpoint) {
properties.setProperty(PROPERTY_${ucaseProviderName}_ENDPOINT, checkNotNull(endpoint, "endpoint")
.toString());
return this;
}
}

View File

@ -1,63 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.
* ====================================================================
*/
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
package ${package}.config;
import java.net.URI;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.lifecycle.Closer;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl;
import ${package}.${providerName};
import ${package}.${providerName}AsyncClient;
import ${package}.${providerName}Client;
import ${package}.reference.${providerName}Constants;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* Configures the ${providerName} connection, including logging and http transport.
*
* @author ${author}
*/
public class ${providerName}ContextModule extends AbstractModule {
public ${providerName}ContextModule(String providerName) {
// providerName ignored right now
}
@Override
protected void configure() {
// example of how to customize bindings
// bind(DateAdapter.class).to(CDateAdapter.class);
}
@Provides
@Singleton
RestContext<${providerName}Client, ${providerName}AsyncClient> provideContext(Closer closer, ${providerName}AsyncClient asyncApi,
${providerName}Client syncApi, @${providerName} URI endPoint, @Named(${providerName}Constants.PROPERTY_${ucaseProviderName}_USER) String identity) {
return new RestContextImpl<${providerName}Client, ${providerName}AsyncClient>(closer, asyncApi, syncApi, endPoint, identity);
}
}

View File

@ -1,93 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.
* ====================================================================
*/
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
package ${package}.config;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.crypto.Crypto;
import ${package}.${providerName};
import ${package}.${providerName}Client;
import ${package}.${providerName}AsyncClient;
import ${package}.reference.${providerName}Constants;
import ${package}.handlers.${providerName}ErrorHandler;
import com.google.inject.Provides;
/**
* Configures the ${providerName} connection.
*
* @author ${author}
*/
@RequiresHttp
@ConfiguresRestClient
public class ${providerName}RestClientModule extends
RestClientModule<${providerName}Client, ${providerName}AsyncClient> {
public ${providerName}RestClientModule() {
super(${providerName}Client.class, ${providerName}AsyncClient.class);
}
@Provides
@Singleton
public BasicAuthentication provideBasicAuthentication(
@Named(${providerName}Constants.PROPERTY_${ucaseProviderName}_USER) String user,
@Named(${providerName}Constants.PROPERTY_${ucaseProviderName}_PASSWORD) String password,
Crypto crypto)
throws UnsupportedEncodingException {
return new BasicAuthentication(user, password, crypto);
}
@Provides
@Singleton
@${providerName}
protected URI provideURI(@Named(${providerName}Constants.PROPERTY_${ucaseProviderName}_ENDPOINT) String endpoint) {
return URI.create(endpoint);
}
@Override
protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
${providerName}ErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
${providerName}ErrorHandler.class);
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(
${providerName}ErrorHandler.class);
}
@Override
protected void bindRetryHandlers() {
// TODO
}
}

View File

@ -1,92 +0,0 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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 ${package}.handlers;
import java.io.IOException;
import javax.annotation.Resource;
import javax.inject.Singleton;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Utils;
import com.google.common.base.Throwables;
import com.google.common.io.Closeables;
/**
* This will parse and set an appropriate exception on the command object.
*
* @author Adrian Cole
*
*/
@Singleton
public class ${providerName}ErrorHandler implements HttpErrorHandler {
@Resource
protected Logger logger = Logger.NULL;
public void handleError(HttpCommand command, HttpResponse response) {
// it is important to always read fully and close streams
String message = parseMessage(response);
Exception exception = message != null ? new HttpResponseException(command, response, message)
: new HttpResponseException(command, response);
try {
message = message != null ? message : String.format("%s -> %s", command.getRequest()
.getRequestLine(), response.getStatusLine());
switch (response.getStatusCode()) {
case 401:
case 403:
exception = new AuthorizationException(message, exception);
break;
case 404:
if (!command.getRequest().getMethod().equals("DELETE")) {
exception = new ResourceNotFoundException(message, exception);
}
break;
}
} finally {
Closeables.closeQuietly(response.getContent());
command.setException(exception);
}
}
public String parseMessage(HttpResponse response) {
if (response.getContent() == null)
return null;
try {
return Utils.toStringAndClose(response.getContent());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
response.getContent().close();
} catch (IOException e) {
Throwables.propagate(e);
}
}
}
}

View File

@ -1,33 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.
* ====================================================================
*/
#set( $lcaseProviderName = ${providerName.toLowerCase()} )
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
package ${package}.reference;
/**
* Configuration properties and constants used in ${providerName} connections.
*
* @author ${author}
*/
public interface ${providerName}Constants {
public static final String PROPERTY_${ucaseProviderName}_ENDPOINT = "jclouds.${lcaseProviderName}.endpoint";
public static final String PROPERTY_${ucaseProviderName}_USER = "jclouds.${lcaseProviderName}.user";
public static final String PROPERTY_${ucaseProviderName}_PASSWORD = "jclouds.${lcaseProviderName}.password";
}

View File

@ -32,7 +32,7 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<name>jclouds Maven archetypes</name> <name>jclouds Maven archetypes</name>
<modules> <modules>
<module>json-client-archetype</module> <module>rest-client-archetype</module>
<module>compute-service-archetype</module> <module>compute-service-archetype</module>
</modules> </modules>
</project> </project>

View File

@ -28,9 +28,9 @@
<artifactId>jclouds-archetypes</artifactId> <artifactId>jclouds-archetypes</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>jclouds-json-client-archetype</artifactId> <artifactId>jclouds-rest-client-archetype</artifactId>
<name>jclouds JSON client archetype</name> <name>jclouds rest client archetype</name>
<description>Maven archetype for a provider of a JSON-speaking service</description> <description>Maven archetype for a provider of a rest-speaking service</description>
<packaging>maven-archetype</packaging> <packaging>maven-archetype</packaging>
<build> <build>

View File

@ -19,7 +19,7 @@
==================================================================== ====================================================================
--> -->
<archetype-descriptor name="jclouds-json-client-archetype"> <archetype-descriptor name="jclouds-rest-client-archetype">
<requiredProperties> <requiredProperties>
<requiredProperty key="groupId"> <requiredProperty key="groupId">
<defaultValue>org.jclouds</defaultValue> <defaultValue>org.jclouds</defaultValue>
@ -32,8 +32,9 @@
</requiredProperty> </requiredProperty>
<requiredProperty key="providerName" /> <requiredProperty key="providerName" />
<requiredProperty key="providerEndpoint" /> <requiredProperty key="providerEndpoint" />
<requiredProperty key="providerAccount" /> <requiredProperty key="providerIdentity" />
<requiredProperty key="providerKey" /> <requiredProperty key="providerApiVersion" />
<requiredProperty key="providerCredential" />
</requiredProperties> </requiredProperties>
<fileSets> <fileSets>
<fileSet filtered="true" packaged="true" encoding="UTF-8"> <fileSet filtered="true" packaged="true" encoding="UTF-8">

View File

@ -1,8 +1,8 @@
In this module, you can run just unit tests, or run tests that connect directly to the service. To run against the service, you'll need to specify the maven profile live. In this module, you can run just unit tests, or run tests that connect directly to the service. To run against the service, you'll need to specify the maven profile live.
When live is enabled, any tests that have "LiveTest" suffix will be run during the integration-test phase. In order for this to operate, you must specify the following When live is enabled, any tests that have "LiveTest" suffix will be run during the integration-test phase. In order for this to operate, you must specify the following
properties: properties:
* jclouds.test.account * test.${lcaseProviderName}.identity
* jclouds.test.key * test.${lcaseProviderName}.credential
Note that this module is intentionally incomplete. You should global replace and create your own client from this example. Make sure that you use tests propertly. For Note that this module is intentionally incomplete. You should global replace and create your own client from this example. Make sure that you use tests propertly. For
example, the test ending in *AsyncClientTest will help ensure that your annotations parse in the way you expect. example, the test ending in *AsyncClientTest will help ensure that your annotations parse in the way you expect.

View File

@ -0,0 +1,141 @@
#set( $lcaseProviderName = ${providerName.toLowerCase()} )
#set(
$symbol_dollar = '$' )
<?xml version="1.0" encoding="UTF-8"?>
<!--
${symbol_dollar}HeadURL${symbol_dollar}
${symbol_dollar}Revision${symbol_dollar}
${symbol_dollar}Date${symbol_dollar} Copyright (C) 2010 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.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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../project/pom.xml</relativePath>
</parent>
<groupId>${groupId}</groupId>
<artifactId>jclouds-${artifactId}</artifactId>
<name>jclouds ${providerName} core</name>
<description>jclouds components to access ${providerName}</description>
<scm>
<connection>scm:git:git@github.com:jclouds/jclouds.git</connection>
<developerConnection>scm:git:git@github.com:jclouds/jclouds.git</developerConnection>
<url>http://github.com/jclouds/jclouds/tree/master/${lcaseProviderName}</url>
</scm>
<!-- bootstrapping: need to fetch the project POM -->
<repositories>
<repository>
<id>jclouds-googlecode-deploy</id>
<url>http://jclouds.googlecode.com/svn/repo</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>jclouds-rimu-snapshots-nexus</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<test.${lcaseProviderName}.identity>${providerIdentity}</test.${lcaseProviderName}.identity>
<test.${lcaseProviderName}.credential>${providerCredential}</test.${lcaseProviderName}.credential>
<test.${lcaseProviderName}.apiversion>${providerApiVersion}</test.${lcaseProviderName}.apiversion>
<test.${lcaseProviderName}.endpoint>${providerEndpoint}</test.${lcaseProviderName}.endpoint>
</properties>
<dependencies>
<dependency>
<groupId>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${symbol_dollar}{project.version}</version>
</dependency>
<dependency>
<groupId>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${symbol_dollar}{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>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${symbol_dollar}{project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemProperties>
<property>
<name>test.${lcaseProviderName}.identity</name>
<value>\$\{test.${lcaseProviderName}.identity\}</value>
</property>
<property>
<name>test.${lcaseProviderName}.credential</name>
<value>\$\{test.${lcaseProviderName}.credential\}</value>
</property>
<property>
<name>test.${lcaseProviderName}.endpoint</name>
<value>\$\{test.${lcaseProviderName}.endpoint\}</value>
</property>
<property>
<name>test.${lcaseProviderName}.apiversion</name>
<value>\$\{test.${lcaseProviderName}.apiversion\}</value>
</property>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -35,9 +35,9 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.http.filters.BasicAuthentication;
import ${package}.${providerName}Client; import ${package}.${providerName}Client;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
@ -51,10 +51,10 @@ import com.google.common.util.concurrent.ListenableFuture;
* @see <a href="TODO: insert URL of provider documentation" /> * @see <a href="TODO: insert URL of provider documentation" />
* @author ${author} * @author ${author}
*/ */
@Endpoint(${providerName}.class)
@RequestFilters(BasicAuthentication.class) @RequestFilters(BasicAuthentication.class)
@Consumes(MediaType.APPLICATION_JSON)
public interface ${providerName}AsyncClient { public interface ${providerName}AsyncClient {
public static final String API_VERSION = "${providerApiVersion}";
/* /*
* TODO: define interface methods for ${providerName} * TODO: define interface methods for ${providerName}
*/ */
@ -64,6 +64,8 @@ public interface ${providerName}AsyncClient {
*/ */
@GET @GET
@Path("/items") @Path("/items")
@Consumes(MediaType.TEXT_PLAIN)
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<String> list(); ListenableFuture<String> list();
/** /**
@ -71,6 +73,7 @@ public interface ${providerName}AsyncClient {
*/ */
@GET @GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class) @ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Consumes(MediaType.TEXT_PLAIN)
@Path("/items/{itemId}") @Path("/items/{itemId}")
ListenableFuture<String> get(@PathParam("itemId") long id); ListenableFuture<String> get(@PathParam("itemId") long id);

View File

@ -27,27 +27,29 @@
*/ */
package ${package}; package ${package};
import static org.jclouds.rest.RestContextFactory.contextSpec;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import ${package}.config.${providerName}RestClientModule; import org.jclouds.http.HttpRequest;
import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.functions.CloseContentAndReturn; import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.jclouds.http.functions.ReturnStringIf200; import org.jclouds.http.functions.ReturnStringIf2xx;
import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.rest.RestClientTest; import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404; import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import ${package}.${providerName}AsyncClient;
import ${package}.${providerName}Client;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.inject.Module;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
/** /**
* Tests annotation parsing of {@code ${providerName}AsyncClient} * Tests annotation parsing of {@code ${providerName}AsyncClient}
@ -60,69 +62,66 @@ public class ${providerName}AsyncClientTest extends RestClientTest<${providerNam
public void testList() throws SecurityException, NoSuchMethodException, IOException { public void testList() throws SecurityException, NoSuchMethodException, IOException {
Method method = ${providerName}AsyncClient.class.getMethod("list"); Method method = ${providerName}AsyncClient.class.getMethod("list");
GeneratedHttpRequest<${providerName}AsyncClient> httpRequest = processor.createRequest(method); GeneratedHttpRequest<${providerName}AsyncClient> request = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/items HTTP/1.1"); assertRequestLineEquals(request, "GET ${providerEndpoint}/items HTTP/1.1");
assertHeadersEqual(httpRequest, "Accept: application/json\n"); assertNonPayloadHeadersEqual(request, "Accept: text/plain\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(request, null, null, false);
// now make sure request filters apply by replaying // now make sure request filters apply by replaying
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); Iterables.getOnlyElement(request.getFilters()).filter(request);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest); Iterables.getOnlyElement(request.getFilters()).filter(request);
assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/items HTTP/1.1"); assertRequestLineEquals(request, "GET ${providerEndpoint}/items HTTP/1.1");
// for example, using basic authentication, we should get "only one" header // for example, using basic authentication, we should get "only one" header
assertHeadersEqual(httpRequest, "Accept: application/json\nAuthorization: Basic dXNlcjprZXk=\n"); assertNonPayloadHeadersEqual(request, "Accept: text/plain\nAuthorization: Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(request, null, null, false);
// TODO: insert expected response class, which probably extends ParseJson assertResponseParserClassEquals(method, request, ReturnStringIf2xx.class);
assertResponseParserClassEquals(method, httpRequest, ReturnStringIf200.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(httpRequest); checkFilters(request);
} }
public void testGet() throws SecurityException, NoSuchMethodException, IOException { public void testGet() throws SecurityException, NoSuchMethodException, IOException {
Method method = ${providerName}AsyncClient.class.getMethod("get", long.class); Method method = ${providerName}AsyncClient.class.getMethod("get", long.class);
GeneratedHttpRequest<${providerName}AsyncClient> httpRequest = processor.createRequest(method, 1); GeneratedHttpRequest<${providerName}AsyncClient> request = processor.createRequest(method, 1);
assertRequestLineEquals(httpRequest, "GET ${providerEndpoint}/items/1 HTTP/1.1"); assertRequestLineEquals(request, "GET ${providerEndpoint}/items/1 HTTP/1.1");
assertHeadersEqual(httpRequest, "Accept: application/json\n"); assertNonPayloadHeadersEqual(request, "Accept: text/plain\n");
assertPayloadEquals(httpRequest, null); assertPayloadEquals(request, null, null, false);
// TODO: insert expected response class, which probably extends ParseJson assertResponseParserClassEquals(method, request, ReturnStringIf2xx.class);
assertResponseParserClassEquals(method, httpRequest, ReturnStringIf200.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
// note that get methods should convert 404's to null
assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class); assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
checkFilters(httpRequest); checkFilters(request);
} }
public void testDelete() throws SecurityException, NoSuchMethodException, IOException { public void testDelete() throws SecurityException, NoSuchMethodException, IOException {
Method method = ${providerName}AsyncClient.class.getMethod("delete", long.class); Method method = ${providerName}AsyncClient.class.getMethod("delete", long.class);
GeneratedHttpRequest<${providerName}AsyncClient> httpRequest = processor.createRequest( GeneratedHttpRequest<${providerName}AsyncClient> request = processor.createRequest(
method, 1); method, 1);
assertRequestLineEquals(httpRequest, assertRequestLineEquals(request, "DELETE ${providerEndpoint}/items/1 HTTP/1.1");
"DELETE ${providerEndpoint}/items/1 HTTP/1.1"); assertNonPayloadHeadersEqual(request, "");
assertHeadersEqual(httpRequest, "Accept: application/json\n"); assertPayloadEquals(request, null, null, false);
assertPayloadEquals(httpRequest, null);
assertResponseParserClassEquals(method, httpRequest, CloseContentAndReturn.class); assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class); assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
checkFilters(httpRequest); checkFilters(request);
} }
@Override @Override
protected void checkFilters(GeneratedHttpRequest<${providerName}AsyncClient> httpRequest) { protected void checkFilters(HttpRequest request) {
assertEquals(httpRequest.getFilters().size(), 1); assertEquals(request.getFilters().size(), 1);
assertEquals(httpRequest.getFilters().get(0).getClass(), BasicAuthentication.class); assertEquals(request.getFilters().get(0).getClass(), BasicAuthentication.class);
} }
@Override @Override
@ -132,14 +131,8 @@ public class ${providerName}AsyncClientTest extends RestClientTest<${providerNam
} }
@Override @Override
protected Module createModule() { public ContextSpec<${providerName}Client, ${providerName}AsyncClient> createContextSpec() {
return new ${providerName}RestClientModule() { return contextSpec("${lcaseProviderName}", "${providerEndpoint}", "${providerApiVersion}", "identity", "credential", ${providerName}Client.class,
@Override ${providerName}AsyncClient.class);
protected void configure() {
Names.bindProperties(binder(), new ${providerName}PropertiesBuilder("user", "key").build());
install(new NullLoggingModule());
super.configure();
}
};
} }
} }

View File

@ -28,12 +28,19 @@
package ${package}; package ${package};
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.rest.RestContextFactory.contextSpec;
import static org.jclouds.rest.RestContextFactory.createContext;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/** /**
* Tests behavior of {@code ${providerName}Client} * Tests behavior of {@code ${providerName}Client}
* *
@ -42,26 +49,36 @@ import org.testng.annotations.Test;
@Test(groups = "live", testName = "${lcaseProviderName}.${providerName}ClientLiveTest") @Test(groups = "live", testName = "${lcaseProviderName}.${providerName}ClientLiveTest")
public class ${providerName}ClientLiveTest { public class ${providerName}ClientLiveTest {
private ${providerName}Client connection; protected RestContext<${providerName}Client, ${providerName}AsyncClient> context;
protected String provider = "${lcaseProviderName}";
protected String identity;
protected String credential;
protected String endpoint;
protected String apiVersion;
protected void setupCredentials() {
identity = checkNotNull(System.getProperty("test.${lcaseProviderName}.identity"), "test.${lcaseProviderName}.identity");
credential = checkNotNull(System.getProperty("test.${lcaseProviderName}.credential"), "test.${lcaseProviderName}.credential");
endpoint = checkNotNull(System.getProperty("test.${lcaseProviderName}.endpoint"), "test.${lcaseProviderName}.endpoint");
apiVersion = checkNotNull(System.getProperty("test.${lcaseProviderName}.apiversion"), "test.${lcaseProviderName}.apiversion");
}
@BeforeGroups(groups = { "live" }) @BeforeGroups(groups = { "live" })
public void setupClient() { public void setupClient() {
String identity = checkNotNull(System.getProperty("jclouds.test.identity"), "jclouds.test.identity"); setupCredentials();
String credential = checkNotNull(System.getProperty("jclouds.test.credential"), "jclouds.test.credential"); context = createContext(contextSpec(provider, endpoint, apiVersion, identity, credential,
${providerName}Client.class, ${providerName}AsyncClient.class), ImmutableSet.<Module> of(new Log4JLoggingModule()));
connection = ${providerName}ContextFactory.createContext(identity, credential, new Log4JLoggingModule())
.getApi();
} }
@Test @Test
public void testList() throws Exception { public void testList() throws Exception {
String response = connection.list(); String response = context.getApi().list();
assertNotNull(response); assertNotNull(response);
} }
@Test @Test
public void testGet() throws Exception { public void testGet() throws Exception {
String response = connection.get(1l); String response = context.getApi().get(1l);
assertNotNull(response); assertNotNull(response);
} }

View File

@ -51,6 +51,11 @@
<artifactId>jclouds-blobstore</artifactId> <artifactId>jclouds-blobstore</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>[2.1,)</version>
</dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>jclouds-blobstore</artifactId> <artifactId>jclouds-blobstore</artifactId>
@ -77,11 +82,6 @@
<version>1.2.14</version> <version>1.2.14</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-twitter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>jclouds-aws</artifactId> <artifactId>jclouds-aws</artifactId>

View File

@ -41,8 +41,6 @@ import org.jclouds.demo.tweetstore.controller.AddTweetsController;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController; import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses; import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.gae.config.GoogleAppEngineConfigurationModule; import org.jclouds.gae.config.GoogleAppEngineConfigurationModule;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.twitter.TwitterClient;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -52,6 +50,9 @@ import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter; import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import com.google.appengine.api.labs.taskqueue.Queue; import com.google.appengine.api.labs.taskqueue.Queue;
import com.google.appengine.api.labs.taskqueue.QueueFactory; import com.google.appengine.api.labs.taskqueue.QueueFactory;
import com.google.appengine.api.labs.taskqueue.TaskOptions.Method; import com.google.appengine.api.labs.taskqueue.TaskOptions.Method;
@ -74,7 +75,7 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA
private ServletConfig servletConfig; private ServletConfig servletConfig;
private Map<String, BlobStoreContext> providerTypeToBlobStoreMap; private Map<String, BlobStoreContext> providerTypeToBlobStoreMap;
private TwitterClient twitterClient; private Twitter twitterClient;
private String container; private String container;
@PostConstruct @PostConstruct
@ -88,24 +89,19 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA
Set<Module> modules = ImmutableSet.<Module> of(googleModule); Set<Module> modules = ImmutableSet.<Module> of(googleModule);
// shared across all blobstores and used to retrieve tweets // shared across all blobstores and used to retrieve tweets
try { try {
twitterClient = (TwitterClient) new RestContextFactory().createContext("twitter", modules, twitterClient = new TwitterFactory().getInstance(props.getProperty("twitter.identity"), props
props).getApi(); .getProperty("credential"));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new IllegalArgumentException("properties for twitter not configured properly in " throw new IllegalArgumentException("properties for twitter not configured properly in " + props.toString(), e);
+ props.toString(), e);
} }
// common namespace for storing tweets // common namespace for storing tweets
container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), PROPERTY_TWEETSTORE_CONTAINER);
PROPERTY_TWEETSTORE_CONTAINER);
// instantiate and store references to all blobstores by provider name // instantiate and store references to all blobstores by provider name
providerTypeToBlobStoreMap = Maps.newHashMap(); providerTypeToBlobStoreMap = Maps.newHashMap();
for (String hint : Splitter.on(',').split( for (String hint : Splitter.on(',').split(
checkNotNull(props.getProperty(PROPERTY_BLOBSTORE_CONTEXTS), checkNotNull(props.getProperty(PROPERTY_BLOBSTORE_CONTEXTS), PROPERTY_BLOBSTORE_CONTEXTS))) {
PROPERTY_BLOBSTORE_CONTEXTS))) { providerTypeToBlobStoreMap.put(hint, blobStoreContextFactory.createContext(hint, modules, props));
providerTypeToBlobStoreMap.put(hint, blobStoreContextFactory.createContext(hint, modules,
props));
} }
// get a queue for submitting store tweet requests // get a queue for submitting store tweet requests
@ -114,16 +110,14 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA
for (String name : providerTypeToBlobStoreMap.keySet()) { for (String name : providerTypeToBlobStoreMap.keySet()) {
queue.add(url("/store/do").header("context", name).method(Method.GET)); queue.add(url("/store/do").header("context", name).method(Method.GET));
} }
logger.trace( logger.trace("Members initialized. Twitter: '%s', container: '%s', provider types: '%s'", twitterClient,
"Members initialized. TwitterClient: '%s', container: '%s', provider types: '%s'", container, providerTypeToBlobStoreMap.keySet());
twitterClient, container, providerTypeToBlobStoreMap.keySet());
} }
private Properties loadJCloudsProperties() { private Properties loadJCloudsProperties() {
logger.trace("About to read properties from '%s'", "/WEB-INF/jclouds.properties"); logger.trace("About to read properties from '%s'", "/WEB-INF/jclouds.properties");
Properties props = new Properties(); Properties props = new Properties();
InputStream input = servletConfig.getServletContext().getResourceAsStream( InputStream input = servletConfig.getServletContext().getResourceAsStream("/WEB-INF/jclouds.properties");
"/WEB-INF/jclouds.properties");
try { try {
props.load(input); props.load(input);
} catch (IOException e) { } catch (IOException e) {
@ -137,8 +131,7 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA
@Bean @Bean
public StoreTweetsController storeTweetsController() { public StoreTweetsController storeTweetsController() {
StoreTweetsController controller = new StoreTweetsController(providerTypeToBlobStoreMap, StoreTweetsController controller = new StoreTweetsController(providerTypeToBlobStoreMap, container, twitterClient);
container, twitterClient);
injectServletConfig(controller); injectServletConfig(controller);
return controller; return controller;
} }

View File

@ -23,7 +23,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -41,8 +40,9 @@ import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.twitter.TwitterClient;
import org.jclouds.twitter.domain.Status; import twitter4j.Status;
import twitter4j.Twitter;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -75,7 +75,7 @@ public class StoreTweetsController extends HttpServlet {
private static final long serialVersionUID = 7215420527854203714L; private static final long serialVersionUID = 7215420527854203714L;
private final Map<String, BlobStoreContext> contexts; private final Map<String, BlobStoreContext> contexts;
private final TwitterClient client; private final Twitter client;
private final String container; private final String container;
@Resource @Resource
@ -84,18 +84,18 @@ public class StoreTweetsController extends HttpServlet {
@Inject @Inject
@VisibleForTesting @VisibleForTesting
public StoreTweetsController(Map<String, BlobStoreContext> contexts, public StoreTweetsController(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container, TwitterClient client) { @Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container, Twitter client) {
this.container = container; this.container = container;
this.contexts = contexts; this.contexts = contexts;
this.client = client; this.client = client;
} }
@VisibleForTesting @VisibleForTesting
public void addMyTweets(String contextName, Set<Status> allAboutMe) { public void addMyTweets(String contextName, Iterable<Status> responseList) {
BlobStoreContext context = checkNotNull(contexts.get(contextName), "no context for " + contextName + " in " BlobStoreContext context = checkNotNull(contexts.get(contextName), "no context for " + contextName + " in "
+ contexts.keySet()); + contexts.keySet());
BlobMap map = context.createBlobMap(container); BlobMap map = context.createBlobMap(container);
for (Status status : allAboutMe) { for (Status status : responseList) {
Blob blob = null; Blob blob = null;
try { try {
blob = new StatusToBlob(map).apply(status); blob = new StatusToBlob(map).apply(status);
@ -115,7 +115,7 @@ public class StoreTweetsController extends HttpServlet {
try { try {
String contextName = checkNotNull(request.getHeader("context"), "missing header context"); String contextName = checkNotNull(request.getHeader("context"), "missing header context");
logger.info("retrieving tweets"); logger.info("retrieving tweets");
addMyTweets(contextName, client.getMyMentions()); addMyTweets(contextName, client.getMentions());
logger.debug("done storing tweets"); logger.debug("done storing tweets");
response.setContentType(MediaType.TEXT_PLAIN); response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!"); response.getWriter().println("Done!");

View File

@ -19,13 +19,15 @@
package org.jclouds.demo.tweetstore.controller; package org.jclouds.demo.tweetstore.controller;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.jclouds.util.Utils.toStringAndClose; import static org.jclouds.util.Utils.toStringAndClose;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.SortedSet;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -34,13 +36,14 @@ import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.BlobStoreContextFactory; import org.jclouds.blobstore.BlobStoreContextFactory;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.twitter.TwitterClient;
import org.jclouds.twitter.domain.Status;
import org.jclouds.twitter.domain.User;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.User;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
/** /**
* Tests behavior of {@code StoreTweetsController} * Tests behavior of {@code StoreTweetsController}
@ -50,8 +53,8 @@ import com.google.common.collect.Sets;
@Test(groups = "unit", testName = "tweetstore.StoreTweetsControllerTest") @Test(groups = "unit", testName = "tweetstore.StoreTweetsControllerTest")
public class StoreTweetsControllerTest { public class StoreTweetsControllerTest {
TwitterClient createTwitterClient() { Twitter createTwitter() {
return createMock(TwitterClient.class); return createMock(Twitter.class);
} }
Map<String, BlobStoreContext> createBlobStores() throws InterruptedException, ExecutionException { Map<String, BlobStoreContext> createBlobStores() throws InterruptedException, ExecutionException {
@ -66,35 +69,48 @@ public class StoreTweetsControllerTest {
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException { public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
Map<String, BlobStoreContext> stores = createBlobStores(); Map<String, BlobStoreContext> stores = createBlobStores();
StoreTweetsController function = new StoreTweetsController(stores, "favo", StoreTweetsController function = new StoreTweetsController(stores, "favo", createTwitter());
createTwitterClient());
SortedSet<Status> allAboutMe = Sets.newTreeSet(); User frank = createMock(User.class);
User frank = new User(1l, "frank"); expect(frank.getScreenName()).andReturn("frank").atLeastOnce();
Status frankStatus = new Status(1l, frank, "I love beans!");
User jimmy = new User(2l, "jimmy"); Status frankStatus = createMock(Status.class);
Status jimmyStatus = new Status(2l, jimmy, "cloud is king"); expect(frankStatus.getId()).andReturn(1l).atLeastOnce();
expect(frankStatus.getUser()).andReturn(frank).atLeastOnce();
expect(frankStatus.getText()).andReturn("I love beans!").atLeastOnce();
User jimmy = createMock(User.class);
expect(jimmy.getScreenName()).andReturn("jimmy").atLeastOnce();
allAboutMe.add(frankStatus); Status jimmyStatus = createMock(Status.class);
allAboutMe.add(jimmyStatus); expect(jimmyStatus.getId()).andReturn(2l).atLeastOnce();
expect(jimmyStatus.getUser()).andReturn(jimmy).atLeastOnce();
expect(jimmyStatus.getText()).andReturn("cloud is king").atLeastOnce();
function.addMyTweets("test1", allAboutMe); replay(frank);
function.addMyTweets("test2", allAboutMe); replay(frankStatus);
replay(jimmy);
replay(jimmyStatus);
function.addMyTweets("test1", ImmutableList.of(frankStatus, jimmyStatus));
function.addMyTweets("test2", ImmutableList.of(frankStatus, jimmyStatus));
verify(frank);
verify(frankStatus);
verify(jimmy);
verify(jimmyStatus);
for (Entry<String, BlobStoreContext> entry : stores.entrySet()) { for (Entry<String, BlobStoreContext> entry : stores.entrySet()) {
BlobMap map = entry.getValue().createBlobMap("favo"); BlobMap map = entry.getValue().createBlobMap("favo");
Blob frankBlob = map.get("1"); Blob frankBlob = map.get("1");
assertEquals(frankBlob.getMetadata().getName(), "1"); assertEquals(frankBlob.getMetadata().getName(), "1");
assertEquals(frankBlob.getMetadata().getUserMetadata() assertEquals(frankBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "frank");
.get(TweetStoreConstants.SENDER_NAME), "frank");
assertEquals(frankBlob.getMetadata().getContentType(), "text/plain"); assertEquals(frankBlob.getMetadata().getContentType(), "text/plain");
assertEquals(toStringAndClose(frankBlob.getPayload().getInput()), "I love beans!"); assertEquals(toStringAndClose(frankBlob.getPayload().getInput()), "I love beans!");
Blob jimmyBlob = map.get("2"); Blob jimmyBlob = map.get("2");
assertEquals(jimmyBlob.getMetadata().getName(), "2"); assertEquals(jimmyBlob.getMetadata().getName(), "2");
assertEquals(jimmyBlob.getMetadata().getUserMetadata() assertEquals(jimmyBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "jimmy");
.get(TweetStoreConstants.SENDER_NAME), "jimmy");
assertEquals(jimmyBlob.getMetadata().getContentType(), "text/plain"); assertEquals(jimmyBlob.getMetadata().getContentType(), "text/plain");
assertEquals(toStringAndClose(jimmyBlob.getPayload().getInput()), "cloud is king"); assertEquals(toStringAndClose(jimmyBlob.getPayload().getInput()), "cloud is king");
} }

View File

@ -21,7 +21,6 @@ package org.jclouds.demo.tweetstore.integration;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER; import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER;
import static org.jclouds.rest.RestContextFactory.contextSpec;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -39,16 +38,17 @@ import org.jclouds.blobstore.BlobStoreContextFactory;
import org.jclouds.demo.tweetstore.config.SpringServletConfig; import org.jclouds.demo.tweetstore.config.SpringServletConfig;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController; import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.twitter.TwitterAsyncClient;
import org.jclouds.twitter.TwitterClient;
import org.jclouds.twitter.domain.Status;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters; import org.testng.annotations.Parameters;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -56,8 +56,8 @@ import com.google.common.collect.Maps;
import com.google.inject.Module; import com.google.inject.Module;
/** /**
* Starts up the Google App Engine for Java Development environment and deploys * Starts up the Google App Engine for Java Development environment and deploys an application which
* an application which tests accesses twitter and blobstores. * tests accesses twitter and blobstores.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@ -70,16 +70,16 @@ public class TweetStoreLiveTest {
private String container; private String container;
private static final String blobs = System.getProperty("jclouds.tweetstore.blobstores", private static final String blobs = System.getProperty("jclouds.tweetstore.blobstores",
"cloudfiles,googlestorage,s3,azureblob"); "cloudfiles,googlestorage,s3,azureblob");
private static final Iterable<String> blobstores = Splitter.on(',').split(blobs); private static final Iterable<String> blobstores = Splitter.on(',').split(blobs);
private static final Properties props = new Properties(); private static final Properties props = new Properties();
@BeforeTest @BeforeTest
void clearAndCreateContainers() throws InterruptedException, ExecutionException, TimeoutException, IOException { void clearAndCreateContainers() throws InterruptedException, ExecutionException, TimeoutException, IOException, TwitterException {
container = checkNotNull(System.getProperty(PROPERTY_TWEETSTORE_CONTAINER)); container = checkNotNull(System.getProperty(PROPERTY_TWEETSTORE_CONTAINER));
props.setProperty(PROPERTY_TWEETSTORE_CONTAINER, checkNotNull(System.getProperty(PROPERTY_TWEETSTORE_CONTAINER), props.setProperty(PROPERTY_TWEETSTORE_CONTAINER, checkNotNull(System.getProperty(PROPERTY_TWEETSTORE_CONTAINER),
PROPERTY_TWEETSTORE_CONTAINER)); PROPERTY_TWEETSTORE_CONTAINER));
props.setProperty(SpringServletConfig.PROPERTY_BLOBSTORE_CONTEXTS, Joiner.on(',').join(blobstores)); props.setProperty(SpringServletConfig.PROPERTY_BLOBSTORE_CONTEXTS, Joiner.on(',').join(blobstores));
@ -98,17 +98,17 @@ public class TweetStoreLiveTest {
contexts.put(provider, factory.createContext(provider, wiring, props)); contexts.put(provider, factory.createContext(provider, wiring, props));
} }
RestContext<TwitterClient, TwitterAsyncClient> twitterContext = new RestContextFactory().createContext("twitter", Twitter client = new TwitterFactory().getInstance(props.getProperty("twitter.identity"), props
wiring, props); .getProperty("twitter.credential"));
StoreTweetsController controller = new StoreTweetsController(contexts, container, twitterContext.getApi()); StoreTweetsController controller = new StoreTweetsController(contexts, container, client);
Set<Status> statuses = twitterContext.getApi().getMyMentions(); ResponseList<Status> statuses = client.getMentions();
boolean deleted = false; boolean deleted = false;
for (BlobStoreContext context : contexts.values()) { for (BlobStoreContext context : contexts.values()) {
if (context.getBlobStore().containerExists(container)) { if (context.getBlobStore().containerExists(container)) {
System.err.printf("deleting container %s at %s%n", container, context.getProviderSpecificContext() System.err.printf("deleting container %s at %s%n", container, context.getProviderSpecificContext()
.getEndpoint()); .getEndpoint());
context.getBlobStore().deleteContainer(container); context.getBlobStore().deleteContainer(container);
deleted = true; deleted = true;
} }
@ -119,7 +119,7 @@ public class TweetStoreLiveTest {
} }
for (BlobStoreContext context : contexts.values()) { for (BlobStoreContext context : contexts.values()) {
System.err.printf("creating container %s at %s%n", container, context.getProviderSpecificContext() System.err.printf("creating container %s at %s%n", container, context.getProviderSpecificContext()
.getEndpoint()); .getEndpoint());
context.getBlobStore().createContainerInLocation(null, container); context.getBlobStore().createContainerInLocation(null, container);
} }
if (deleted) { if (deleted) {
@ -134,19 +134,17 @@ public class TweetStoreLiveTest {
} }
private void addConfigurationForTwitter(Properties props) { private void addConfigurationForTwitter(Properties props) {
String twitterIdentity = checkNotNull(System.getProperty("twitter.identity"), "twitter.identity"); props.setProperty("twitter.identity", checkNotNull(System.getProperty("twitter.identity"), "twitter.identity"));
String twitterCredential = checkNotNull(System.getProperty("twitter.credential"), "twitter.credential"); props.setProperty("twitter.credential", checkNotNull(System.getProperty("twitter.credential"),
"twitter.credential"));
props.putAll(RestContextFactory.toProperties(contextSpec("twitter", "http://twitter.com", "1", twitterIdentity,
twitterCredential, TwitterClient.class, TwitterAsyncClient.class)));
} }
private void addCredentialsForBlobStores(Properties props) { private void addCredentialsForBlobStores(Properties props) {
for (String provider : blobstores) { for (String provider : blobstores) {
props.setProperty(provider + ".identity", checkNotNull(System.getProperty(provider + ".identity"), provider props.setProperty(provider + ".identity", checkNotNull(System.getProperty(provider + ".identity"), provider
+ ".identity")); + ".identity"));
props.setProperty(provider + ".credential", checkNotNull(System.getProperty(provider + ".credential"), props.setProperty(provider + ".credential", checkNotNull(System.getProperty(provider + ".credential"),
provider + ".credential")); provider + ".credential"));
} }
} }

View File

@ -44,6 +44,11 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>[2.1,)</version>
</dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>jclouds-blobstore</artifactId> <artifactId>jclouds-blobstore</artifactId>
@ -75,11 +80,6 @@
<version>1.2.14</version> <version>1.2.14</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-twitter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>jclouds-aws</artifactId> <artifactId>jclouds-aws</artifactId>

View File

@ -36,8 +36,9 @@ import org.jclouds.blobstore.BlobStoreContextFactory;
import org.jclouds.demo.tweetstore.controller.AddTweetsController; import org.jclouds.demo.tweetstore.controller.AddTweetsController;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController; import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.gae.config.GoogleAppEngineConfigurationModule; import org.jclouds.gae.config.GoogleAppEngineConfigurationModule;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.twitter.TwitterClient; import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import com.google.appengine.api.labs.taskqueue.Queue; import com.google.appengine.api.labs.taskqueue.Queue;
import com.google.appengine.api.labs.taskqueue.QueueFactory; import com.google.appengine.api.labs.taskqueue.QueueFactory;
@ -63,7 +64,7 @@ public class GuiceServletConfig extends GuiceServletContextListener {
public static final String PROPERTY_BLOBSTORE_CONTEXTS = "blobstore.contexts"; public static final String PROPERTY_BLOBSTORE_CONTEXTS = "blobstore.contexts";
private Map<String, BlobStoreContext> providerTypeToBlobStoreMap; private Map<String, BlobStoreContext> providerTypeToBlobStoreMap;
private TwitterClient twitterClient; private Twitter twitterClient;
private String container; private String container;
@Override @Override
@ -77,24 +78,19 @@ public class GuiceServletConfig extends GuiceServletContextListener {
Set<Module> modules = ImmutableSet.<Module> of(googleModule); Set<Module> modules = ImmutableSet.<Module> of(googleModule);
// shared across all blobstores and used to retrieve tweets // shared across all blobstores and used to retrieve tweets
try { try {
twitterClient = (TwitterClient) new RestContextFactory().createContext("twitter", modules, twitterClient = new TwitterFactory().getInstance(props.getProperty("twitter.identity"), props
props).getApi(); .getProperty("credential"));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new IllegalArgumentException("properties for twitter not configured properly in " throw new IllegalArgumentException("properties for twitter not configured properly in " + props.toString(), e);
+ props.toString(), e);
} }
// common namespace for storing tweets // common namespace for storing tweets
container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), PROPERTY_TWEETSTORE_CONTAINER);
PROPERTY_TWEETSTORE_CONTAINER);
// instantiate and store references to all blobstores by provider name // instantiate and store references to all blobstores by provider name
providerTypeToBlobStoreMap = Maps.newHashMap(); providerTypeToBlobStoreMap = Maps.newHashMap();
for (String hint : Splitter.on(',').split( for (String hint : Splitter.on(',').split(
checkNotNull(props.getProperty(PROPERTY_BLOBSTORE_CONTEXTS), checkNotNull(props.getProperty(PROPERTY_BLOBSTORE_CONTEXTS), PROPERTY_BLOBSTORE_CONTEXTS))) {
PROPERTY_BLOBSTORE_CONTEXTS))) { providerTypeToBlobStoreMap.put(hint, blobStoreContextFactory.createContext(hint, modules, props));
providerTypeToBlobStoreMap.put(hint, blobStoreContextFactory.createContext(hint, modules,
props));
} }
// get a queue for submitting store tweet requests // get a queue for submitting store tweet requests
@ -108,8 +104,7 @@ public class GuiceServletConfig extends GuiceServletContextListener {
} }
private Properties loadJCloudsProperties(ServletContextEvent servletContextEvent) { private Properties loadJCloudsProperties(ServletContextEvent servletContextEvent) {
InputStream input = servletContextEvent.getServletContext().getResourceAsStream( InputStream input = servletContextEvent.getServletContext().getResourceAsStream("/WEB-INF/jclouds.properties");
"/WEB-INF/jclouds.properties");
Properties props = new Properties(); Properties props = new Properties();
try { try {
props.load(input); props.load(input);
@ -128,7 +123,7 @@ public class GuiceServletConfig extends GuiceServletContextListener {
protected void configureServlets() { protected void configureServlets() {
bind(new TypeLiteral<Map<String, BlobStoreContext>>() { bind(new TypeLiteral<Map<String, BlobStoreContext>>() {
}).toInstance(providerTypeToBlobStoreMap); }).toInstance(providerTypeToBlobStoreMap);
bind(TwitterClient.class).toInstance(twitterClient); bind(Twitter.class).toInstance(twitterClient);
bindConstant().annotatedWith(Names.named(PROPERTY_TWEETSTORE_CONTAINER)).to(container); bindConstant().annotatedWith(Names.named(PROPERTY_TWEETSTORE_CONTAINER)).to(container);
serve("/store/*").with(StoreTweetsController.class); serve("/store/*").with(StoreTweetsController.class);
serve("/tweets/*").with(AddTweetsController.class); serve("/tweets/*").with(AddTweetsController.class);

View File

@ -23,7 +23,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -41,8 +40,9 @@ import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.twitter.TwitterClient;
import org.jclouds.twitter.domain.Status; import twitter4j.Status;
import twitter4j.Twitter;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -75,7 +75,7 @@ public class StoreTweetsController extends HttpServlet {
private static final long serialVersionUID = 7215420527854203714L; private static final long serialVersionUID = 7215420527854203714L;
private final Map<String, BlobStoreContext> contexts; private final Map<String, BlobStoreContext> contexts;
private final TwitterClient client; private final Twitter client;
private final String container; private final String container;
@Resource @Resource
@ -84,18 +84,18 @@ public class StoreTweetsController extends HttpServlet {
@Inject @Inject
@VisibleForTesting @VisibleForTesting
public StoreTweetsController(Map<String, BlobStoreContext> contexts, public StoreTweetsController(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container, TwitterClient client) { @Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container, Twitter client) {
this.container = container; this.container = container;
this.contexts = contexts; this.contexts = contexts;
this.client = client; this.client = client;
} }
@VisibleForTesting @VisibleForTesting
public void addMyTweets(String contextName, Set<Status> allAboutMe) { public void addMyTweets(String contextName, Iterable<Status> responseList) {
BlobStoreContext context = checkNotNull(contexts.get(contextName), "no context for " + contextName + " in " BlobStoreContext context = checkNotNull(contexts.get(contextName), "no context for " + contextName + " in "
+ contexts.keySet()); + contexts.keySet());
BlobMap map = context.createBlobMap(container); BlobMap map = context.createBlobMap(container);
for (Status status : allAboutMe) { for (Status status : responseList) {
Blob blob = null; Blob blob = null;
try { try {
blob = new StatusToBlob(map).apply(status); blob = new StatusToBlob(map).apply(status);
@ -115,7 +115,7 @@ public class StoreTweetsController extends HttpServlet {
try { try {
String contextName = checkNotNull(request.getHeader("context"), "missing header context"); String contextName = checkNotNull(request.getHeader("context"), "missing header context");
logger.info("retrieving tweets"); logger.info("retrieving tweets");
addMyTweets(contextName, client.getMyMentions()); addMyTweets(contextName, client.getMentions());
logger.debug("done storing tweets"); logger.debug("done storing tweets");
response.setContentType(MediaType.TEXT_PLAIN); response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!"); response.getWriter().println("Done!");

View File

@ -19,13 +19,15 @@
package org.jclouds.demo.tweetstore.controller; package org.jclouds.demo.tweetstore.controller;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.jclouds.util.Utils.toStringAndClose; import static org.jclouds.util.Utils.toStringAndClose;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.SortedSet;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -34,13 +36,14 @@ import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.BlobStoreContextFactory; import org.jclouds.blobstore.BlobStoreContextFactory;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.twitter.TwitterClient;
import org.jclouds.twitter.domain.Status;
import org.jclouds.twitter.domain.User;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.User;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
/** /**
* Tests behavior of {@code StoreTweetsController} * Tests behavior of {@code StoreTweetsController}
@ -50,8 +53,8 @@ import com.google.common.collect.Sets;
@Test(groups = "unit", testName = "tweetstore.StoreTweetsControllerTest") @Test(groups = "unit", testName = "tweetstore.StoreTweetsControllerTest")
public class StoreTweetsControllerTest { public class StoreTweetsControllerTest {
TwitterClient createTwitterClient() { Twitter createTwitter() {
return createMock(TwitterClient.class); return createMock(Twitter.class);
} }
Map<String, BlobStoreContext> createBlobStores() throws InterruptedException, ExecutionException { Map<String, BlobStoreContext> createBlobStores() throws InterruptedException, ExecutionException {
@ -66,35 +69,48 @@ public class StoreTweetsControllerTest {
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException { public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
Map<String, BlobStoreContext> stores = createBlobStores(); Map<String, BlobStoreContext> stores = createBlobStores();
StoreTweetsController function = new StoreTweetsController(stores, "favo", StoreTweetsController function = new StoreTweetsController(stores, "favo", createTwitter());
createTwitterClient());
SortedSet<Status> allAboutMe = Sets.newTreeSet(); User frank = createMock(User.class);
User frank = new User(1l, "frank"); expect(frank.getScreenName()).andReturn("frank").atLeastOnce();
Status frankStatus = new Status(1l, frank, "I love beans!");
User jimmy = new User(2l, "jimmy"); Status frankStatus = createMock(Status.class);
Status jimmyStatus = new Status(2l, jimmy, "cloud is king"); expect(frankStatus.getId()).andReturn(1l).atLeastOnce();
expect(frankStatus.getUser()).andReturn(frank).atLeastOnce();
expect(frankStatus.getText()).andReturn("I love beans!").atLeastOnce();
User jimmy = createMock(User.class);
expect(jimmy.getScreenName()).andReturn("jimmy").atLeastOnce();
allAboutMe.add(frankStatus); Status jimmyStatus = createMock(Status.class);
allAboutMe.add(jimmyStatus); expect(jimmyStatus.getId()).andReturn(2l).atLeastOnce();
expect(jimmyStatus.getUser()).andReturn(jimmy).atLeastOnce();
expect(jimmyStatus.getText()).andReturn("cloud is king").atLeastOnce();
function.addMyTweets("test1", allAboutMe); replay(frank);
function.addMyTweets("test2", allAboutMe); replay(frankStatus);
replay(jimmy);
replay(jimmyStatus);
function.addMyTweets("test1", ImmutableList.of(frankStatus, jimmyStatus));
function.addMyTweets("test2", ImmutableList.of(frankStatus, jimmyStatus));
verify(frank);
verify(frankStatus);
verify(jimmy);
verify(jimmyStatus);
for (Entry<String, BlobStoreContext> entry : stores.entrySet()) { for (Entry<String, BlobStoreContext> entry : stores.entrySet()) {
BlobMap map = entry.getValue().createBlobMap("favo"); BlobMap map = entry.getValue().createBlobMap("favo");
Blob frankBlob = map.get("1"); Blob frankBlob = map.get("1");
assertEquals(frankBlob.getMetadata().getName(), "1"); assertEquals(frankBlob.getMetadata().getName(), "1");
assertEquals(frankBlob.getMetadata().getUserMetadata() assertEquals(frankBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "frank");
.get(TweetStoreConstants.SENDER_NAME), "frank");
assertEquals(frankBlob.getMetadata().getContentType(), "text/plain"); assertEquals(frankBlob.getMetadata().getContentType(), "text/plain");
assertEquals(toStringAndClose(frankBlob.getPayload().getInput()), "I love beans!"); assertEquals(toStringAndClose(frankBlob.getPayload().getInput()), "I love beans!");
Blob jimmyBlob = map.get("2"); Blob jimmyBlob = map.get("2");
assertEquals(jimmyBlob.getMetadata().getName(), "2"); assertEquals(jimmyBlob.getMetadata().getName(), "2");
assertEquals(jimmyBlob.getMetadata().getUserMetadata() assertEquals(jimmyBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "jimmy");
.get(TweetStoreConstants.SENDER_NAME), "jimmy");
assertEquals(jimmyBlob.getMetadata().getContentType(), "text/plain"); assertEquals(jimmyBlob.getMetadata().getContentType(), "text/plain");
assertEquals(toStringAndClose(jimmyBlob.getPayload().getInput()), "cloud is king"); assertEquals(toStringAndClose(jimmyBlob.getPayload().getInput()), "cloud is king");
} }

View File

@ -21,7 +21,6 @@ package org.jclouds.demo.tweetstore.integration;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER; import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER;
import static org.jclouds.rest.RestContextFactory.contextSpec;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -40,16 +39,17 @@ import org.jclouds.demo.tweetstore.config.GuiceServletConfig;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController; import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.twitter.TwitterAsyncClient;
import org.jclouds.twitter.TwitterClient;
import org.jclouds.twitter.domain.Status;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters; import org.testng.annotations.Parameters;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -75,7 +75,7 @@ public class TweetStoreLiveTest {
private static final Properties props = new Properties(); private static final Properties props = new Properties();
@BeforeTest @BeforeTest
void clearAndCreateContainers() throws InterruptedException, ExecutionException, TimeoutException, IOException { void clearAndCreateContainers() throws InterruptedException, ExecutionException, TimeoutException, IOException, TwitterException {
container = checkNotNull(System.getProperty(PROPERTY_TWEETSTORE_CONTAINER)); container = checkNotNull(System.getProperty(PROPERTY_TWEETSTORE_CONTAINER));
props.setProperty(PROPERTY_TWEETSTORE_CONTAINER, checkNotNull(System.getProperty(PROPERTY_TWEETSTORE_CONTAINER), props.setProperty(PROPERTY_TWEETSTORE_CONTAINER, checkNotNull(System.getProperty(PROPERTY_TWEETSTORE_CONTAINER),
@ -98,11 +98,11 @@ public class TweetStoreLiveTest {
contexts.put(provider, factory.createContext(provider, wiring, props)); contexts.put(provider, factory.createContext(provider, wiring, props));
} }
RestContext<TwitterClient, TwitterAsyncClient> twitterContext = new RestContextFactory().createContext("twitter", Twitter client = new TwitterFactory().getInstance(props.getProperty("twitter.identity"), props
wiring, props); .getProperty("twitter.credential"));
StoreTweetsController controller = new StoreTweetsController(contexts, container, twitterContext.getApi()); StoreTweetsController controller = new StoreTweetsController(contexts, container, client);
Set<Status> statuses = twitterContext.getApi().getMyMentions(); ResponseList<Status> statuses = client.getMentions();
boolean deleted = false; boolean deleted = false;
for (BlobStoreContext context : contexts.values()) { for (BlobStoreContext context : contexts.values()) {
@ -148,11 +148,9 @@ public class TweetStoreLiveTest {
} }
private void addConfigurationForTwitter(Properties props) { private void addConfigurationForTwitter(Properties props) {
String twitterIdentity = checkNotNull(System.getProperty("twitter.identity"), "twitter.identity"); props.setProperty("twitter.identity", checkNotNull(System.getProperty("twitter.identity"), "twitter.identity"));
String twitterCredential = checkNotNull(System.getProperty("twitter.credential"), "twitter.credential"); props.setProperty("twitter.credential", checkNotNull(System.getProperty("twitter.credential"),
"twitter.credential"));
props.putAll(RestContextFactory.toProperties(contextSpec("twitter", "http://twitter.com", "1", twitterIdentity,
twitterCredential, TwitterClient.class, TwitterAsyncClient.class)));
} }
private void addCredentialsForBlobStores(Properties props) { private void addCredentialsForBlobStores(Properties props) {

View File

@ -47,7 +47,6 @@
<module>rackspace</module> <module>rackspace</module>
<module>slicehost</module> <module>slicehost</module>
<module>rimuhosting</module> <module>rimuhosting</module>
<module>twitter</module>
<module>vcloud</module> <module>vcloud</module>
<module>gogrid</module> <module>gogrid</module>
<module>allcompute</module> <module>allcompute</module>

View File

@ -1,25 +0,0 @@
====
Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
====================================================================
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.
====================================================================
====
#
# The jclouds provider for Twitter (http://twitter.com/).
#
# TODO: Implementation status.
# TODO: Supported features.
# TODO: Usage example.

View File

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
====================================================================
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.
====================================================================
-->
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../project/pom.xml</relativePath>
</parent>
<artifactId>jclouds-twitter</artifactId>
<name>jclouds twitter core</name>
<description>jclouds components to access twitter</description>
<scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/twitter</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/twitter</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/twitter</url>
</scm>
<properties>
<jclouds.test.identity>${jclouds.twitter.user}</jclouds.test.identity>
<jclouds.test.credential>${jclouds.twitter.password}</jclouds.test.credential>
</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>

View File

@ -1,57 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.twitter;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.twitter.domain.Status;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides asynchronous access to Twitter via their REST API.
* <p/>
*
* @see TwitterClient
* @see <a href= "http://apiwiki.twitter.com/Twitter-REST-API-Method" />
* @author Adrian Cole
*/
@RequestFilters(BasicAuthentication.class)
public interface TwitterAsyncClient {
/**
* @see TwitterClient#getMyMentions()
*/
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Path("/statuses/mentions.json")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
ListenableFuture<Set<Status>> getMyMentions();
}

View File

@ -1,41 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.twitter;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
import org.jclouds.twitter.domain.Status;
/**
* Provides access to Twitter via their REST API.
* <p/>
*
* @see <a href= "http://apiwiki.twitter.com/Twitter-REST-API-Method" />
* @see TwitterAsyncClient
* @author Adrian Cole
*/
@Timeout(duration = 4, timeUnit = TimeUnit.SECONDS)
public interface TwitterClient {
Set<Status> getMyMentions();
}

View File

@ -1,83 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.twitter.domain;
import java.util.Arrays;
/**
*
* @author Adrian Cole
*
*/
public class Location {
private String type;
private double[] coordinates;
public Location() {
}
public Location(String type, double[] coordinates) {
this.type = type;
this.coordinates = Arrays.copyOf(coordinates, coordinates.length);
}
public String getType() {
return type;
}
public double[] getCoordinates() {
return coordinates;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(coordinates);
result = prime * result + ((type == null) ? 0 : type.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;
Location other = (Location) obj;
if (!Arrays.equals(coordinates, other.coordinates))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
return true;
}
@Override
public String toString() {
return "Location [coordinates=" + Arrays.toString(coordinates) + ", type=" + type + "]";
}
}

View File

@ -1,158 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.twitter.domain;
import java.util.Date;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*
*/
public class Status implements Comparable<Status> {
@SerializedName("created_at")
private Date createdAt;
private boolean favorited;
private Location geo;
private long id;
@SerializedName("in_reply_to_screen_name")
private String inReplyToScreenName;
@SerializedName("in_reply_to_status_id")
private Long 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(long id, User user, String text) {
this.id = id;
this.user = user;
this.text = text;
}
public Status(Date createdAt, boolean favorited, Location geo, long id,
String inReplyToScreenName, Long 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;
}
public int compareTo(Status o) {
return (int) ((this == o) ? 0 : id + "".compareTo(o.id + ""));
}
@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;
}
@Override
public String toString() {
return "Status [createdAt=" + createdAt + ", favorited=" + favorited + ", geo=" + geo
+ ", id=" + id + ", inReplyToScreenName=" + inReplyToScreenName
+ ", inReplyToStatusId=" + inReplyToStatusId + ", inReplyToUserId="
+ inReplyToUserId + ", source=" + source + ", text=" + text + ", truncated="
+ truncated + ", user=" + user + "]";
}
public Date getCreatedAt() {
return createdAt;
}
public boolean isFavorited() {
return favorited;
}
public Location getGeo() {
return geo;
}
public long getId() {
return id;
}
public String getInReplyToScreenName() {
return inReplyToScreenName;
}
public Long getInReplyToStatusId() {
return inReplyToStatusId;
}
public Integer getInReplyToUserId() {
return inReplyToUserId;
}
public String getSource() {
return source;
}
public String getText() {
return text;
}
public boolean isTruncated() {
return truncated;
}
public User getUser() {
return user;
}
}

View File

@ -1,299 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.twitter.domain;
import java.net.URI;
import java.util.Date;
import com.google.gson.annotations.SerializedName;
/**
*
* @author Adrian Cole
*/
public class User implements Comparable<User> {
@SerializedName("created_at")
private Date 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;
@SerializedName("contributors_enabled")
private boolean contributorsEnabled;
private long id;
private String location;
private String name;
private String lang;
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_use_background_image")
private boolean profileUseBackgroundImage;
@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(long id, String screenName) {
this.id = id;
this.screenName = screenName;
}
public User(Date createdAt, String description, int favouritesCount, int followersCount,
boolean following, int friendsCount, boolean geoEnabled, boolean contributorsEnabled,
long id, String location, String name, String lang, boolean notifications,
String profileBackgroundColor, boolean profileUseBackgroundImage,
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.geoEnabled = geoEnabled;
this.id = id;
this.location = location;
this.name = name;
this.lang = lang;
this.notifications = notifications;
this.contributorsEnabled = contributorsEnabled;
this.profileBackgroundColor = profileBackgroundColor;
this.profileUseBackgroundImage = profileUseBackgroundImage;
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;
}
public Date getCreatedAt() {
return createdAt;
}
public String getDescription() {
return description;
}
public int getFavouritesCount() {
return favouritesCount;
}
public int getFollowersCount() {
return followersCount;
}
public boolean isFollowing() {
return following;
}
public int getFriendsCount() {
return friendsCount;
}
public boolean isGeoEnabled() {
return geoEnabled;
}
public long getId() {
return id;
}
public String getLocation() {
return location;
}
public String getName() {
return name;
}
public boolean isNotifications() {
return notifications;
}
public String getProfileBackgroundColor() {
return profileBackgroundColor;
}
public URI getProfileBackgroundImageUrl() {
return profileBackgroundImageUrl;
}
public boolean isProfileBackgroundTile() {
return profileBackgroundTile;
}
public boolean isProfileUseBackgroundImage() {
return profileUseBackgroundImage;
}
public URI getProfileImageUrl() {
return profileImageUrl;
}
public String getProfileLinkColor() {
return profileLinkColor;
}
public String getProfileSidebarBorderColor() {
return profileSidebarBorderColor;
}
public String getProfileSidebarFillColor() {
return profileSidebarFillColor;
}
public String getProfileTextColor() {
return profileTextColor;
}
public boolean isProtected() {
return isProtected;
}
public String getScreenName() {
return screenName;
}
public int getStatusesCount() {
return statusesCount;
}
public String getTimeZone() {
return timeZone;
}
public URI getUrl() {
return url;
}
public int getUtcOffset() {
return utcOffset;
}
public boolean isVerified() {
return verified;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
result = prime * result + ((screenName == null) ? 0 : screenName.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 (screenName == null) {
if (other.screenName != null)
return false;
} else if (!screenName.equals(other.screenName))
return false;
return true;
}
@Override
public String toString() {
return "User [createdAt=" + createdAt + ", description=" + description + ", favouritesCount="
+ favouritesCount + ", followersCount=" + followersCount + ", following="
+ following + ", friendsCount=" + friendsCount + ", geoEnabled=" + geoEnabled
+ ", id=" + id + ", isProtected=" + isProtected + ", location=" + location
+ ", name=" + name + ", notifications=" + notifications
+ ", profileBackgroundColor=" + profileBackgroundColor
+ ", profileBackgroundImageUrl=" + profileBackgroundImageUrl
+ ", profileBackgroundTile=" + profileBackgroundTile + ", profileImageUrl="
+ profileImageUrl + ", profileLinkColor=" + profileLinkColor
+ ", profileSidebarBorderColor=" + profileSidebarBorderColor
+ ", profileSidebarFillColor=" + profileSidebarFillColor + ", profileTextColor="
+ profileTextColor + ", profileUseBackgroundImage=" + profileUseBackgroundImage
+ ", screenName=" + screenName + ", statusesCount=" + statusesCount + ", timeZone="
+ timeZone + ", url=" + url + ", utcOffset=" + utcOffset + ", verified=" + verified
+ "]";
}
public int compareTo(User o) {
if (screenName == null)
return -1;
return (this == o) ? 0 : screenName.compareTo(o.screenName);
}
public boolean isContributorsEnabled() {
return contributorsEnabled;
}
public String getLang() {
return lang;
}
}

View File

@ -1,80 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.twitter;
import static org.jclouds.rest.RestContextFactory.contextSpec;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.lang.reflect.Method;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code TwitterClient}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "twitter.TwitterClientTest")
public class TwitterAsyncClientTest extends RestClientTest<TwitterAsyncClient> {
public void testGetMyMentions() throws SecurityException, NoSuchMethodException, IOException {
Method method = TwitterAsyncClient.class.getMethod("getMyMentions");
HttpRequest request = processor.createRequest(method);
assertRequestLineEquals(request, "GET http://twitter.com/statuses/mentions.json HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/json\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ParseJson.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
checkFilters(request);
}
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
assertEquals(request.getFilters().get(0).getClass(), BasicAuthentication.class);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<TwitterAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<TwitterAsyncClient>>() {
};
}
@Override
public ContextSpec<TwitterClient, TwitterAsyncClient> createContextSpec() {
return contextSpec("test", "http://twitter.com", "1", "identity", "credential", TwitterClient.class,
TwitterAsyncClient.class);
}
}

View File

@ -1,74 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.twitter;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.rest.RestContextFactory.contextSpec;
import static org.jclouds.rest.RestContextFactory.createContext;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.jclouds.twitter.domain.Status;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Tests behavior of {@code TwitterClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "twitter.TwitterClientLiveTest")
public class TwitterClientLiveTest {
private TwitterClient connection;
private RestContext<TwitterClient, TwitterAsyncClient> context;
@BeforeGroups(groups = "live")
public void setupClient() throws InterruptedException, ExecutionException, TimeoutException {
String identity = checkNotNull(System.getProperty("jclouds.test.identity"), "jclouds.test.identity");
String credential = checkNotNull(System.getProperty("jclouds.test.credential"), "jclouds.test.credential");
context = createContext(contextSpec("twitter", "http://twitter.com", "1", identity, credential,
TwitterClient.class, TwitterAsyncClient.class), ImmutableSet.<Module> of(new Log4JLoggingModule()));
connection = context.getApi();
}
@Test
public void testGetMyMentions() throws Exception {
Set<Status> response = connection.getMyMentions();
assert (response.size() > 0);
}
@AfterGroups(groups = "live")
void tearDown() {
if (context != null)
context.close();
}
}

View File

@ -1,103 +0,0 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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.jclouds.twitter.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.SortedSet;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.json.config.GsonModule;
import org.jclouds.twitter.domain.Location;
import org.jclouds.twitter.domain.Status;
import org.jclouds.twitter.domain.User;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSortedSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code ParseStatusesFromJsonResponse}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "twitter.ParseStatusesFromJsonResponseTest")
public class ParseStatusesFromJsonResponseTest {
Injector i = Guice.createInjector(new GsonModule());
DateService dateService = new SimpleDateFormatDateService();
public void testApplyInputStreamDetails() throws IOException {
InputStream is = getClass().getResourceAsStream("/test_mentions.json");
SortedSet<Status> expects = ImmutableSortedSet
.of(
new Status(
dateService.cDateParse("Tue Jun 29 20:41:15 +0000 2010"),
false,
new Location("Point", new double[] { 153.08691298, -26.38658779 }),
15138751340l,
"adrianfcole",
15112459535l,
21744326,
null,
"@adrianfcole hehe, yes. Still going :) hope you're keeping well!",
false,
new User(
dateService.cDateParse("Sat Jul 26 08:08:17 +0000 2008"),
"London-based South African software geek & amateur photog. Since Nov 2009, travelling the world with @sunflowerkate on an extended honeymoon",
21,
315,
true,
405,
true,
false,
15608907,
"Travelling around the world",
"Andrew Newdigate",
"en",
false,
"FFF04D",
true,
URI
.create("http://a1.twimg.com/profile_background_images/62032362/_MG_8095_6_7HDR_tonemapped.jpg"),
false, URI
.create("http://a1.twimg.com/profile_images/593267212/many_moon_honeymoon_normal.jpg"),
"0099CC", "fff8ad", "f6ffd1", "333333", false, "suprememoocow", 987, "Kuala Lumpur", URI
.create("http://newdigate.me"), -28800, false))
);
ParseJson<SortedSet<Status>> parser = i.getInstance(Key.get(new TypeLiteral<ParseJson<SortedSet<Status>>>() {
}));
SortedSet<Status> response = parser.apply(is);
assertEquals(response, expects);
}
}

View File

@ -1,109 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009 Cloud Conscious, LLC.
<info@cloudconscious.com>
====================================================================
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.
====================================================================
-->
<!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.headers">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<category name="jclouds.wire">
<priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" />
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -1,49 +0,0 @@
[{
"favorited": false,
"contributors": null,
"coordinates": {
"type": "Point",
"coordinates": [153.08691298, -26.38658779]
}, "source": "<a href=\"http://itunes.apple.com/app/twitter/id333903271?mt=8\" rel=\"nofollow\">Twitter for iPhone</a>",
"created_at": "Mon May 31 23:22:51 +0000 2010",
"place": null,
"user": {
"statuses_count": 987,
"notifications": false,
"profile_sidebar_border_color": "fff8ad",
"description": "London-based South African software geek & amateur photog. Since Nov 2009, travelling the world with @sunflowerkate on an extended honeymoon",
"location": "Travelling around the world",
"screen_name": "suprememoocow",
"profile_use_background_image": true,
"followers_count": 315,
"contributors_enabled": false,
"friends_count": 405,
"lang": "en",
"geo_enabled": true,
"profile_background_color": "FFF04D",
"favourites_count": 21,
"verified": false,
"profile_text_color": "333333",
"following": true,
"time_zone": "Kuala Lumpur",
"created_at": "Sat Jul 26 08:08:17 +0000 2008",
"profile_link_color": "0099CC",
"protected": false,
"profile_background_image_url": "http://a1.twimg.com/profile_background_images/62032362/_MG_8095_6_7HDR_tonemapped.jpg",
"name": "Andrew Newdigate",
"profile_sidebar_fill_color": "f6ffd1",
"url": "http://newdigate.me",
"profile_image_url": "http://a1.twimg.com/profile_images/593267212/many_moon_honeymoon_normal.jpg",
"id": 15608907,
"profile_background_tile": false,
"utc_offset": 28800
}, "in_reply_to_screen_name": "adrianfcole",
"truncated": false,
"in_reply_to_user_id": 21744326,
"id": 15138751340,
"geo": {
"type": "Point",
"coordinates": [-26.38658779, 153.08691298]
}, "in_reply_to_status_id": 15112459535,
"text": "@adrianfcole hehe, yes. Still going :) hope you're keeping well!"
}]

View File

@ -55,7 +55,7 @@ public class BlueLockVCloudDirectorComputeServiceLiveTest extends VCloudComputeS
@Test @Test
public void testTemplateBuilder() { public void testTemplateBuilder() {
Template defaultTemplate = client.templateBuilder().build(); Template defaultTemplate = client.templateBuilder().build();
assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), false);
assert OperatingSystemPredicates.supportsApt().apply(defaultTemplate.getImage().getOperatingSystem()); assert OperatingSystemPredicates.supportsApt().apply(defaultTemplate.getImage().getOperatingSystem());
assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(defaultTemplate.getImage().getOperatingSystem().getDescription(), "Ubuntu Linux (64-bit)"); assertEquals(defaultTemplate.getImage().getOperatingSystem().getDescription(), "Ubuntu Linux (64-bit)");