Issue 1111:Move tweetstore to new jclouds-tweetstore repository

This commit is contained in:
Adrian Cole 2012-10-21 15:27:45 -07:00
parent 4e2834b6cd
commit e43df10f39
224 changed files with 0 additions and 20155 deletions

View File

@ -37,7 +37,6 @@
<module>speedtest-azurequeue</module>
<module>speedtest-sqs</module>
<module>simpledb</module>
<module>tweetstore</module>
</modules>
<dependencies>
<dependency>

View File

@ -1,41 +0,0 @@
====
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
====
A guide to generating Twitter consumer keys and access tokens is at http://tinyurl.com/2fhebgb
Please modify your maven settings.xml like below before attempting to run 'mvn -Plive install'
<profile>
<id>keys</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<test.aws-s3.identity>YOUR_ACCESS_KEY_ID</test.aws-s3.identity>
<test.aws-s3.credential>YOUR_SECRET_KEY</test.aws-s3.credential>
<test.cloudfiles-us.identity>YOUR_USER</test.cloudfiles-us.identity>
<test.cloudfiles-us.credential>YOUR_HEX_KEY</test.cloudfiles-us.credential>
<test.azureblob.identity>YOUR_ACCOUNT</test.azureblob.identity>
<test.azureblob.credential>YOUR_BASE64_ENCODED_KEY</test.azureblob.credential>
<test.twitter.cf-tweetstore-spring.consumer.identity>YOUR_TWITTER_CONSUMER_KEY</test.twitter.cf-tweetstore-spring.consumer.identity>
<test.twitter.cf-tweetstore-spring.consumer.credential>YOUR_TWITTER_CONSUMER_SECRET</test.twitter.cf-tweetstore-spring.consumer.credential>
<test.twitter.cf-tweetstore-spring.access.identity>YOUR_TWITTER_ACCESSTOKEN</test.twitter.cf-tweetstore-spring.access.identity>
<test.twitter.cf-tweetstore-spring.access.credential>YOUR_TWITTER_ACCESSTOKEN_SECRET</test.twitter.cf-tweetstore-spring.access.credential>
</properties>
</profile>

View File

@ -1,191 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<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-demos-tweetstore-project</artifactId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<artifactId>jclouds-demo-cf-tweetstore-spring</artifactId>
<packaging>war</packaging>
<name>jclouds TweetStore for Cloud Foundry</name>
<description>jclouds TweetStore for Cloud Foundry using Spring for Dependency Injection</description>
<properties>
<cloudfoundry.version>0.8.1</cloudfoundry.version>
<cloudfoundry.applicationid>jclouds-tweetstore</cloudfoundry.applicationid>
<test.cloudfoundry.target>http://api.cloudfoundry.com</test.cloudfoundry.target>
<test.cloudfoundry.address>test-${cloudfoundry.applicationid}.cloudfoundry.com</test.cloudfoundry.address>
<test.cloudfoundry.port>80</test.cloudfoundry.port>
<jclouds.tweetstore.container>jclouds-cf-tweetstore-spring</jclouds.tweetstore.container>
</properties>
<dependencies>
<!-- ensure this matches the version of Spring imported by cloudfoundry-runtime -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.5.RELEASE</version>
<!-- using the SLF4J/commons-logging bridge -->
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.1.3</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Cloud Foundry API -->
<dependency>
<groupId>org.cloudfoundry</groupId>
<artifactId>cloudfoundry-runtime</artifactId>
<version>${cloudfoundry.version}</version>
</dependency>
<dependency>
<groupId>org.cloudfoundry</groupId>
<artifactId>cloudfoundry-client-lib</artifactId>
<version>0.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-archiver</artifactId>
<version>2.1.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>org.springframework.maven.milestone</id>
<url>http://maven.springframework.org/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<test.twitter.consumer.identity>${test.twitter.gae-tweetstore-spring.consumer.identity}</test.twitter.consumer.identity>
<test.twitter.consumer.credential>${test.twitter.gae-tweetstore-spring.consumer.credential}</test.twitter.consumer.credential>
<test.twitter.access.identity>${test.twitter.gae-tweetstore-spring.access.identity}</test.twitter.access.identity>
<test.twitter.access.credential>${test.twitter.gae-tweetstore-spring.access.credential}</test.twitter.access.credential>
<test.azureblob.identity>${test.azureblob.identity}</test.azureblob.identity>
<test.azureblob.credential>${test.azureblob.credential}</test.azureblob.credential>
<test.cloudfiles-us.identity>${test.cloudfiles-us.identity}</test.cloudfiles-us.identity>
<test.cloudfiles-us.credential>${test.cloudfiles-us.credential}</test.cloudfiles-us.credential>
<test.aws-s3.identity>${test.aws-s3.identity}</test.aws-s3.identity>
<test.aws-s3.credential>${test.aws-s3.credential}</test.aws-s3.credential>
<test.cloudonestorage.identity>${test.cloudonestorage.identity}</test.cloudonestorage.identity>
<test.cloudonestorage.credential>${test.cloudonestorage.credential}</test.cloudonestorage.credential>
<test.ninefold-storage.identity>${test.ninefold-storage.identity}</test.ninefold-storage.identity>
<test.ninefold-storage.credential>${test.ninefold-storage.credential}</test.ninefold-storage.credential>
<cloudfoundry.address>${test.cloudfoundry.address}</cloudfoundry.address>
<cloudfoundry.port>${test.cloudfoundry.port}</cloudfoundry.port>
<cloudfoundry.target>${test.cloudfoundry.target}</cloudfoundry.target>
<cloudfoundry.username>${cloudfoundry.username}</cloudfoundry.username>
<cloudfoundry.password>${cloudfoundry.password}</cloudfoundry.password>
<jclouds.tweetstore.blobstores>${jclouds.tweetstore.blobstores}</jclouds.tweetstore.blobstores>
<jclouds.tweetstore.container>test.${jclouds.tweetstore.container}</jclouds.tweetstore.container>
<warfile>${project.build.directory}/${project.build.finalName}</warfile>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>deploy</id>
<properties>
<!-- classifier to choose the correct jclouds.properties file -->
<tweetstore.instance>cf-tweetstore-spring</tweetstore.instance>
</properties>
<pluginRepositories>
<pluginRepository>
<id>org.springframework.maven.milestone</id>
<url>http://maven.springframework.org/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.cloudfoundry</groupId>
<artifactId>cf-maven-plugin</artifactId>
<version>1.0.0.M1</version>
<configuration>
<target>http://api.cloudfoundry.com</target>
<username>${cloudfoundry.username}</username>
<password>${cloudfoundry.password}</password>
<appname>${cloudfoundry.applicationid}</appname>
<memory>256</memory>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -1,64 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.demo.paas.config.PlatformServicesInitializer.PLATFORM_SERVICES_ATTRIBUTE_NAME;
import java.util.Map;
import javax.servlet.ServletContext;
import org.jclouds.demo.paas.service.scheduler.Scheduler;
import org.jclouds.demo.paas.service.taskqueue.TaskQueue;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
/**
* @author Andrew Phillips
*/
public class PlatformServices {
protected final String baseUrl;
protected final Scheduler scheduler;
private ImmutableMap<String, TaskQueue> taskQueues;
public PlatformServices(String baseUrl, Scheduler scheduler, Map<String, TaskQueue> taskQueues) {
this.baseUrl = baseUrl;
this.scheduler = scheduler;
this.taskQueues = ImmutableMap.copyOf(taskQueues);
}
public String getBaseUrl() {
return baseUrl;
}
public Scheduler getScheduler() {
return scheduler;
}
public @Nullable TaskQueue getTaskQueue(String name) {
return taskQueues.get(name);
}
public static PlatformServices get(ServletContext context) {
return (PlatformServices) checkNotNull(context.getAttribute(
PLATFORM_SERVICES_ATTRIBUTE_NAME), PLATFORM_SERVICES_ATTRIBUTE_NAME);
}
}

View File

@ -1,126 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas;
import static java.lang.String.format;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpRequest;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
public class RunnableHttpRequest implements Runnable {
public static final String PLATFORM_REQUEST_ORIGINATOR_HEADER = "X-Platform-Originator";
public static Factory factory(HttpCommandExecutorService httpClient) {
return factory(httpClient, format("%s@%d", Factory.class.getName(), System.currentTimeMillis()));
}
public static Factory factory(HttpCommandExecutorService httpClient, String originator) {
return new Factory(httpClient, originator);
}
public static class Factory {
protected final HttpCommandExecutorService httpClient;
protected final String originator;
private Factory(HttpCommandExecutorService httpClient, String originator) {
this.httpClient = httpClient;
this.originator = originator;
}
public RunnableHttpRequest create(HttpRequest request) {
HttpRequest requestWithSubmitter = request.toBuilder()
.headers(copyOfWithEntry(request.getHeaders(),
PLATFORM_REQUEST_ORIGINATOR_HEADER, originator)).build();
return new RunnableHttpRequest(httpClient, requestWithSubmitter);
}
private static <K, V> Multimap<K, V> copyOfWithEntry(
Multimap<? extends K, ? extends V> multimap, K k1, V v1) {
return ImmutableMultimap.<K, V>builder().putAll(multimap).put(k1, v1).build();
}
}
private final HttpCommandExecutorService httpClient;
private final HttpRequest request;
private RunnableHttpRequest(HttpCommandExecutorService httpClient, HttpRequest request) {
this.httpClient = httpClient;
this.request = request;
}
@Override
public void run() {
httpClient.submit(new ImmutableHttpCommand(request));
}
private class ImmutableHttpCommand implements HttpCommand {
private final HttpRequest request;
public ImmutableHttpCommand(HttpRequest request) {
this.request = request;
}
@Override
public void setException(Exception exception) {
}
@Override
public void setCurrentRequest(HttpRequest request) {
}
@Override
public boolean isReplayable() {
return false;
}
@Override
public int incrementRedirectCount() {
return 0;
}
@Override
public int incrementFailureCount() {
return 0;
}
@Override
public int getRedirectCount() {
return 0;
}
@Override
public int getFailureCount() {
return 0;
}
@Override
public Exception getException() {
return null;
}
@Override
public HttpRequest getCurrentRequest() {
return request;
}
}
}

View File

@ -1,65 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas.config;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.inject.name.Names.bindProperties;
import static org.jclouds.Constants.*;
import java.util.Properties;
import javax.servlet.ServletContext;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.demo.tweetstore.config.util.PropertiesLoader;
import com.google.inject.AbstractModule;
import com.sun.jersey.api.uri.UriBuilderImpl;
/**
* @author Andrew Phillips
*/
public class HttpClientModule extends AbstractModule {
private final ServletContext context;
HttpClientModule(ServletContext context) {
this.context = context;
}
@Override
protected void configure() {
// URL connection defaults
Properties toBind = defaultProperties();
toBind.putAll(checkNotNull(new PropertiesLoader(context).get(), "properties"));
toBind.putAll(System.getProperties());
bindProperties(binder(), toBind);
bind(UriBuilder.class).to(UriBuilderImpl.class);
}
private static Properties defaultProperties() {
Properties props = new Properties();
props.setProperty(PROPERTY_MAX_CONNECTIONS_PER_CONTEXT, 20 + "");
props.setProperty(PROPERTY_MAX_CONNECTIONS_PER_HOST, 0 + "");
props.setProperty(PROPERTY_SO_TIMEOUT, 60000 + "");
props.setProperty(PROPERTY_CONNECTION_TIMEOUT, 60000 + "");
props.setProperty(PROPERTY_USER_THREADS, 0 + "");
props.setProperty(PROPERTY_IO_WORKER_THREADS, 20 + "");
return props;
}
}

View File

@ -1,86 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas.config;
import static java.util.concurrent.TimeUnit.SECONDS;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.cloudfoundry.runtime.env.ApplicationInstanceInfo;
import org.cloudfoundry.runtime.env.CloudEnvironment;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.demo.paas.PlatformServices;
import org.jclouds.demo.paas.service.scheduler.Scheduler;
import org.jclouds.demo.paas.service.taskqueue.TaskQueue;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.inject.Guice;
/**
* @author Andrew Phillips
*/
public class PlatformServicesInitializer implements ServletContextListener {
public static final String PLATFORM_SERVICES_ATTRIBUTE_NAME = PlatformServices.class.getName();
@Override
public void contextInitialized(ServletContextEvent contextEvent) {
ServletContext context = contextEvent.getServletContext();
context.setAttribute(PLATFORM_SERVICES_ATTRIBUTE_NAME, createServices(context));
}
protected static PlatformServices createServices(ServletContext context) {
HttpCommandExecutorService httpClient = createHttpClient(context);
return new PlatformServices(getBaseUrl(context), new Scheduler(httpClient),
createTaskQueues(httpClient));
}
protected static HttpCommandExecutorService createHttpClient(
final ServletContext context) {
return Guice.createInjector(new ExecutorServiceModule(),
new JavaUrlHttpCommandExecutorServiceModule(),
new HttpClientModule(context))
.getInstance(HttpCommandExecutorService.class);
}
protected static String getBaseUrl(ServletContext context) {
ApplicationInstanceInfo instanceInfo = new CloudEnvironment().getInstanceInfo();
// using localhost instead of instanceInfo.getHost(). See http://support.cloudfoundry.com/requests/102117
return "http://127.0.0.1:" + instanceInfo.getPort() + context.getContextPath();
}
// TODO: make the number and names of queues configurable
protected static ImmutableMap<String, TaskQueue> createTaskQueues(HttpCommandExecutorService httpClient) {
Builder<String, TaskQueue> taskQueues = ImmutableMap.builder();
taskQueues.put("twitter", TaskQueue.builder(httpClient)
.name("twitter").period(SECONDS.toMillis(30))
.build());
return taskQueues.build();
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ServletContext context = servletContextEvent.getServletContext();
context.removeAttribute(PLATFORM_SERVICES_ATTRIBUTE_NAME);
}
}

View File

@ -1,28 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas.reference;
/**
* Configuration properties and constants used in PaaS applications.
*
* @author Andrew Phillips
*/
public interface PaasConstants {
static final String PROPERTY_PLATFORM_BASE_URL = "jclouds.paas.baseurl";
}

View File

@ -1,69 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas.service.scheduler;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import javax.servlet.ServletContext;
import org.jclouds.demo.paas.PlatformServices;
import org.jclouds.demo.paas.RunnableHttpRequest;
import org.jclouds.http.HttpRequest;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
/**
* @author Andrew Phillips
*/
public class HttpRequestJob implements Job {
protected static final String URL_ATTRIBUTE_NAME = "url";
// keep in sync with "quartz:scheduler-context-servlet-context-key" param in web.xml
protected static final String SERVLET_CONTEXT_KEY = "servlet-context";
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
PlatformServices platform = JobContexts.getPlatform(context);
RunnableHttpRequest request = platform.getScheduler().getHttpRequestFactory().create(
HttpRequest.builder()
.endpoint(JobContexts.getTargetUrl(platform.getBaseUrl(), context))
.method("GET").build());
request.run();
}
private static class JobContexts {
private static URI getTargetUrl(String baseUrl, JobExecutionContext context) {
return URI.create(baseUrl + (String) checkNotNull(
context.getMergedJobDataMap().get(URL_ATTRIBUTE_NAME), URL_ATTRIBUTE_NAME));
}
private static PlatformServices getPlatform(JobExecutionContext jobContext) throws JobExecutionException {
try {
return PlatformServices.get((ServletContext) checkNotNull(
jobContext.getScheduler().getContext().get(SERVLET_CONTEXT_KEY), SERVLET_CONTEXT_KEY));
} catch (SchedulerException exception) {
throw new JobExecutionException("Unable to get platform services from the job execution context", exception);
}
}
}
}

View File

@ -1,41 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas.service.scheduler;
import org.jclouds.demo.paas.RunnableHttpRequest;
import org.jclouds.demo.paas.RunnableHttpRequest.Factory;
import org.jclouds.http.HttpCommandExecutorService;
/**
* @author Andrew Phillips
*/
public class Scheduler {
protected static final String SCHEDULER_ORIGINATOR_NAME = "scheduler";
protected final Factory httpRequestFactory;
public Scheduler(HttpCommandExecutorService httpClient) {
httpRequestFactory =
RunnableHttpRequest.factory(httpClient, SCHEDULER_ORIGINATOR_NAME);
}
public Factory getHttpRequestFactory() {
return httpRequestFactory;
}
}

View File

@ -1,401 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas.service.scheduler.quartz.plugins;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.jclouds.logging.Logger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.TriggerKey;
import org.quartz.jobs.FileScanJob;
import org.quartz.jobs.FileScanListener;
import org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin;
import org.quartz.simpl.CascadingClassLoadHelper;
import org.quartz.spi.ClassLoadHelper;
import org.quartz.spi.SchedulerPlugin;
import org.quartz.xml.XMLSchedulingDataProcessor;
/**
* A copy of {@link XMLSchedulingDataProcessorPlugin} that does not reference
* {@code javax.transaction.UserTransaction} as so does not require a dependency
* on JTA.
*
* @author Andrew Phillips
* @see XMLSchedulingDataProcessorPlugin
*/
public class TransactionlessXmlSchedulingDataProcessorPlugin implements
FileScanListener, SchedulerPlugin {
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Data members.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
private static final int MAX_JOB_TRIGGER_NAME_LEN = 80;
private static final String JOB_INITIALIZATION_PLUGIN_NAME = "JobSchedulingDataLoaderPlugin";
private static final String FILE_NAME_DELIMITERS = ",";
private String name;
private Scheduler scheduler;
private final Logger log = Logger.CONSOLE;
private boolean failOnFileNotFound = true;
private String fileNames = XMLSchedulingDataProcessor.QUARTZ_XML_DEFAULT_FILE_NAME;
// Populated by initialization
private Map<String, JobFile> jobFiles = new LinkedHashMap<String, JobFile>();
private long scanInterval = 0;
boolean started = false;
protected ClassLoadHelper classLoadHelper = null;
private Set<String> jobTriggerNameSet = new HashSet<String>();
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* Comma separated list of file names (with paths) to the XML files that should be read.
*/
public String getFileNames() {
return fileNames;
}
/**
* The file name (and path) to the XML file that should be read.
*/
public void setFileNames(String fileNames) {
this.fileNames = fileNames;
}
/**
* The interval (in seconds) at which to scan for changes to the file.
* If the file has been changed, it is re-loaded and parsed. The default
* value for the interval is 0, which disables scanning.
*
* @return Returns the scanInterval.
*/
public long getScanInterval() {
return scanInterval / 1000;
}
/**
* The interval (in seconds) at which to scan for changes to the file.
* If the file has been changed, it is re-loaded and parsed. The default
* value for the interval is 0, which disables scanning.
*
* @param scanInterval The scanInterval to set.
*/
public void setScanInterval(long scanInterval) {
this.scanInterval = scanInterval * 1000;
}
/**
* Whether or not initialization of the plugin should fail (throw an
* exception) if the file cannot be found. Default is <code>true</code>.
*/
public boolean isFailOnFileNotFound() {
return failOnFileNotFound;
}
/**
* Whether or not initialization of the plugin should fail (throw an
* exception) if the file cannot be found. Default is <code>true</code>.
*/
public void setFailOnFileNotFound(boolean failOnFileNotFound) {
this.failOnFileNotFound = failOnFileNotFound;
}
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* SchedulerPlugin Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* <p>
* Called during creation of the <code>Scheduler</code> in order to give
* the <code>SchedulerPlugin</code> a chance to initialize.
* </p>
*
* @throws org.quartz.SchedulerConfigException
* if there is an error initializing.
*/
@Override
public void initialize(String name, Scheduler scheduler)
throws SchedulerException {
this.name = name;
this.scheduler = scheduler;
classLoadHelper = new CascadingClassLoadHelper();
classLoadHelper.initialize();
log.info("Registering Quartz Job Initialization Plug-in.");
// Create JobFile objects
StringTokenizer stok = new StringTokenizer(fileNames, FILE_NAME_DELIMITERS);
while (stok.hasMoreTokens()) {
final String fileName = stok.nextToken();
final JobFile jobFile = new JobFile(fileName);
jobFiles.put(fileName, jobFile);
}
}
@Override
public void start() {
try {
if (jobFiles.isEmpty() == false) {
if (scanInterval > 0) {
scheduler.getContext().put(JOB_INITIALIZATION_PLUGIN_NAME + '_' + name, this);
}
Iterator<JobFile> iterator = jobFiles.values().iterator();
while (iterator.hasNext()) {
JobFile jobFile = iterator.next();
if (scanInterval > 0) {
String jobTriggerName = buildJobTriggerName(jobFile.getFileBasename());
TriggerKey tKey = new TriggerKey(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME);
// remove pre-existing job/trigger, if any
scheduler.unscheduleJob(tKey);
// TODO: convert to use builder
SimpleTrigger trig = newTrigger()
.withIdentity(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME)
.startNow()
.endAt(null)
.withSchedule(simpleSchedule()
.repeatForever()
.withIntervalInMilliseconds(scanInterval))
.build();
JobDetail job = JobBuilder.newJob(FileScanJob.class)
.withIdentity(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME)
.build();
job.getJobDataMap().put(FileScanJob.FILE_NAME, jobFile.getFileName());
job.getJobDataMap().put(FileScanJob.FILE_SCAN_LISTENER_NAME, JOB_INITIALIZATION_PLUGIN_NAME + '_' + name);
scheduler.scheduleJob(job, trig);
log.debug("Scheduled file scan job for data file: {}, at interval: {}", jobFile.getFileName(), scanInterval);
}
processFile(jobFile);
}
}
} catch(SchedulerException se) {
log.error("Error starting background-task for watching jobs file.", se);
} finally {
started = true;
}
}
/**
* Helper method for generating unique job/trigger name for the
* file scanning jobs (one per FileJob). The unique names are saved
* in jobTriggerNameSet.
*/
private String buildJobTriggerName(
String fileBasename) {
// Name w/o collisions will be prefix + _ + filename (with '.' of filename replaced with '_')
// For example: JobInitializationPlugin_jobInitializer_myjobs_xml
String jobTriggerName = JOB_INITIALIZATION_PLUGIN_NAME + '_' + name + '_' + fileBasename.replace('.', '_');
// If name is too long (DB column is 80 chars), then truncate to max length
if (jobTriggerName.length() > MAX_JOB_TRIGGER_NAME_LEN) {
jobTriggerName = jobTriggerName.substring(0, MAX_JOB_TRIGGER_NAME_LEN);
}
// Make sure this name is unique in case the same file name under different
// directories is being checked, or had a naming collision due to length truncation.
// If there is a conflict, keep incrementing a _# suffix on the name (being sure
// not to get too long), until we find a unique name.
int currentIndex = 1;
while (jobTriggerNameSet.add(jobTriggerName) == false) {
// If not our first time through, then strip off old numeric suffix
if (currentIndex > 1) {
jobTriggerName = jobTriggerName.substring(0, jobTriggerName.lastIndexOf('_'));
}
String numericSuffix = "_" + currentIndex++;
// If the numeric suffix would make the name too long, then make room for it.
if (jobTriggerName.length() > (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length())) {
jobTriggerName = jobTriggerName.substring(0, (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length()));
}
jobTriggerName += numericSuffix;
}
return jobTriggerName;
}
@Override
public void shutdown() {
// nothing to do
}
private void processFile(JobFile jobFile) {
if (jobFile == null || !jobFile.getFileFound()) {
return;
}
try {
XMLSchedulingDataProcessor processor =
new XMLSchedulingDataProcessor(this.classLoadHelper);
processor.addJobGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME);
processor.addTriggerGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME);
processor.processFileAndScheduleJobs(
jobFile.getFileName(),
jobFile.getFileName(), // systemId
scheduler);
} catch (Exception e) {
log.error("Error scheduling jobs: " + e.getMessage(), e);
}
}
public void processFile(String filePath) {
processFile((JobFile)jobFiles.get(filePath));
}
/**
* @see org.quartz.jobs.FileScanListener#fileUpdated(java.lang.String)
*/
public void fileUpdated(String fileName) {
if (started) {
processFile(fileName);
}
}
class JobFile {
private String fileName;
// These are set by initialize()
private String filePath;
private String fileBasename;
private boolean fileFound;
protected JobFile(String fileName) throws SchedulerException {
this.fileName = fileName;
initialize();
}
protected String getFileName() {
return fileName;
}
protected boolean getFileFound() {
return fileFound;
}
protected String getFilePath() {
return filePath;
}
protected String getFileBasename() {
return fileBasename;
}
private void initialize() throws SchedulerException {
InputStream f = null;
try {
String furl = null;
File file = new File(getFileName()); // files in filesystem
if (!file.exists()) {
URL url = classLoadHelper.getResource(getFileName());
if(url != null) {
try {
furl = URLDecoder.decode(url.getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
furl = url.getPath();
}
file = new File(furl);
try {
f = url.openStream();
} catch (IOException ignore) {
// Swallow the exception
}
}
} else {
try {
f = new java.io.FileInputStream(file);
}catch (FileNotFoundException e) {
// ignore
}
}
if (f == null) {
if (isFailOnFileNotFound()) {
throw new SchedulerException(
"File named '" + getFileName() + "' does not exist.");
} else {
log.warn("File named '" + getFileName() + "' does not exist.");
}
} else {
fileFound = true;
}
filePath = (furl != null) ? furl : file.getAbsolutePath();
fileBasename = file.getName();
} finally {
try {
if (f != null) {
f.close();
}
} catch (IOException ioe) {
log.warn("Error closing jobs file " + getFileName(), ioe);
}
}
}
}
}

View File

@ -1,107 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.paas.service.taskqueue;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import org.jclouds.demo.paas.RunnableHttpRequest;
import org.jclouds.demo.paas.RunnableHttpRequest.Factory;
import org.jclouds.http.HttpCommandExecutorService;
import com.google.inject.Provider;
public class TaskQueue {
protected final Factory httpRequestFactory;
private final Timer timer;
private final ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<Runnable>();
private TaskQueue(String name, long pollingIntervalMillis, Factory httpRequestFactory) {
this.httpRequestFactory = httpRequestFactory;
timer = new Timer(name);
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Runnable task = tasks.poll();
if (task != null) {
task.run();
}
}
}, 0, pollingIntervalMillis);
}
public void add(final Runnable task) {
tasks.add(task);
}
public Factory getHttpRequestFactory() {
return httpRequestFactory;
}
public void destroy() {
timer.cancel();
tasks.clear();
}
public static Builder builder(HttpCommandExecutorService httpClient) {
return new Builder(httpClient);
}
public static class Builder implements Provider<TaskQueue> {
protected final HttpCommandExecutorService httpClient;
protected String name = "default";
protected long pollingIntervalMillis = TimeUnit.SECONDS.toMillis(1);
private Builder(HttpCommandExecutorService httpClient) {
this.httpClient = checkNotNull(httpClient, "httpClient");
}
public Builder name(String name) {
this.name = checkNotNull(name, "name");
return this;
}
public Builder period(TimeUnit period) {
this.pollingIntervalMillis = checkNotNull(period, "period").toMillis(1);
return this;
}
public Builder period(long pollingIntervalMillis) {
checkArgument(pollingIntervalMillis > 0, "pollingIntervalMillis");
this.pollingIntervalMillis = pollingIntervalMillis;
return this;
}
public TaskQueue build() {
return new TaskQueue(name, pollingIntervalMillis,
RunnableHttpRequest.factory(httpClient, format("taskqueue-%s", name)));
}
@Override
public TaskQueue get() {
return build();
}
}
}

View File

@ -1,129 +0,0 @@
package org.jclouds.demo.tweetstore.config;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
class DelegatingAutowireCapableBeanFactory implements AutowireCapableBeanFactory {
private final AutowireCapableBeanFactory delegate;
DelegatingAutowireCapableBeanFactory(AutowireCapableBeanFactory delegate) {
this.delegate = delegate;
}
public <T> T createBean(Class<T> beanClass) throws BeansException {
return delegate.createBean(beanClass);
}
public void autowireBean(Object existingBean) throws BeansException {
delegate.autowireBean(existingBean);
}
public Object configureBean(Object existingBean, String beanName)
throws BeansException {
return delegate.configureBean(existingBean, beanName);
}
public Object getBean(String name) throws BeansException {
return delegate.getBean(name);
}
public Object resolveDependency(DependencyDescriptor descriptor,
String beanName) throws BeansException {
return delegate.resolveDependency(descriptor, beanName);
}
public <T> T getBean(String name, Class<T> requiredType)
throws BeansException {
return delegate.getBean(name, requiredType);
}
@SuppressWarnings("rawtypes")
public Object createBean(Class beanClass, int autowireMode,
boolean dependencyCheck) throws BeansException {
return delegate.createBean(beanClass, autowireMode, dependencyCheck);
}
public <T> T getBean(Class<T> requiredType) throws BeansException {
return delegate.getBean(requiredType);
}
@SuppressWarnings("rawtypes")
public Object autowire(Class beanClass, int autowireMode,
boolean dependencyCheck) throws BeansException {
return delegate.autowire(beanClass, autowireMode, dependencyCheck);
}
public Object getBean(String name, Object... args) throws BeansException {
return delegate.getBean(name, args);
}
public void autowireBeanProperties(Object existingBean, int autowireMode,
boolean dependencyCheck) throws BeansException {
delegate.autowireBeanProperties(existingBean, autowireMode,
dependencyCheck);
}
public boolean containsBean(String name) {
return delegate.containsBean(name);
}
public boolean isSingleton(String name)
throws NoSuchBeanDefinitionException {
return delegate.isSingleton(name);
}
public void applyBeanPropertyValues(Object existingBean, String beanName)
throws BeansException {
delegate.applyBeanPropertyValues(existingBean, beanName);
}
public boolean isPrototype(String name)
throws NoSuchBeanDefinitionException {
return delegate.isPrototype(name);
}
@SuppressWarnings("rawtypes")
public boolean isTypeMatch(String name, Class targetType)
throws NoSuchBeanDefinitionException {
return delegate.isTypeMatch(name, targetType);
}
public Object initializeBean(Object existingBean, String beanName)
throws BeansException {
return delegate.initializeBean(existingBean, beanName);
}
public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return delegate.getType(name);
}
public Object applyBeanPostProcessorsBeforeInitialization(
Object existingBean, String beanName) throws BeansException {
return delegate.applyBeanPostProcessorsBeforeInitialization(
existingBean, beanName);
}
public String[] getAliases(String name) {
return delegate.getAliases(name);
}
public Object applyBeanPostProcessorsAfterInitialization(
Object existingBean, String beanName) throws BeansException {
return delegate.applyBeanPostProcessorsAfterInitialization(
existingBean, beanName);
}
public Object resolveDependency(DependencyDescriptor descriptor,
String beanName, Set<String> autowiredBeanNames,
TypeConverter typeConverter) throws BeansException {
return delegate.resolveDependency(descriptor, beanName,
autowiredBeanNames, typeConverter);
}
}

View File

@ -1,101 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.jclouds.logging.LoggingModules.firstOrJDKLoggingModule;
import java.util.Set;
import javax.annotation.PostConstruct;
import org.jclouds.logging.Logger;
import org.jclouds.logging.Logger.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
/**
* Spring config that sets up {@link CommonAnnotationBeanPostProcessor} support
* for injecting loggers.
*
* @author Andrew Phillips
*/
abstract class LoggingConfig implements BeanFactoryAware {
protected static final LoggerFactory LOGGER_FACTORY = firstOrJDKLoggingModule().createLoggerFactory();
private static final Logger LOGGER = LOGGER_FACTORY.getLogger(LoggingConfig.class.getName());
private AutowireCapableBeanFactory beanFactory;
@PostConstruct
public void initLoggerSupport() {
CommonAnnotationBeanPostProcessor resourceProcessor =
(CommonAnnotationBeanPostProcessor) beanFactory.getBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME);
resourceProcessor.setResourceFactory(new LoggerResourceBeanFactory(beanFactory));
}
private static class LoggerResourceBeanFactory extends DelegatingAutowireCapableBeanFactory {
LoggerResourceBeanFactory(AutowireCapableBeanFactory delegate) {
super(delegate);
}
@Override
public Object resolveDependency(DependencyDescriptor descriptor,
String beanName, Set<String> autowiredBeanNames,
TypeConverter typeConverter) throws BeansException {
if (descriptor.getDependencyType().equals(Logger.class)) {
Class<?> requestingType = getType(beanName);
LOGGER.trace("About to resolve logger for bean '%s' of type '%s'",
beanName, requestingType);
Logger logger = resolveLogger(requestingType, autowiredBeanNames);
LOGGER.trace("Successfully resolved logger.");
return logger;
}
return super.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
}
private Logger resolveLogger(Class<?> type, Set<String> autowiredBeanNames) {
String loggerBeanName = format("%s#logger", type);
if (autowiredBeanNames.contains(loggerBeanName)) {
LOGGER.trace("Returning existing bean '%s'", loggerBeanName);
return (Logger) getBean(loggerBeanName);
}
LOGGER.trace("About to create logger for type '%s'", type);
Logger logger = LOGGER_FACTORY.getLogger(type.getName());
LOGGER.trace("Successfully created logger.");
return logger;
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
checkArgument(beanFactory instanceof AutowireCapableBeanFactory, "expected an instance of '%s' but was '%s'",
AutowireCapableBeanFactory.class, beanFactory.getClass());
this.beanFactory = (AutowireCapableBeanFactory) beanFactory;
}
}

View File

@ -1,242 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.in;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Sets.filter;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_BLOBSTORES;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN_SECRET;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_KEY;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_SECRET;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.paas.PlatformServices;
import org.jclouds.demo.paas.service.taskqueue.TaskQueue;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector;
import org.jclouds.demo.tweetstore.controller.AddTweetsController;
import org.jclouds.demo.tweetstore.controller.ClearTweetsController;
import org.jclouds.demo.tweetstore.controller.EnqueueStoresController;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.logging.Logger;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.ServletConfigAware;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.io.Closeables;
import com.google.inject.Module;
/**
* Creates servlets (using resources from the {@link SpringAppConfig}) and mappings.
*
* @author Andrew Phillips
* @see SpringAppConfig
*/
@Configuration
public class SpringServletConfig extends LoggingConfig implements ServletConfigAware {
public static final String PROPERTY_BLOBSTORE_CONTEXTS = "blobstore.contexts";
private static final Logger LOGGER = LOGGER_FACTORY.getLogger(SpringServletConfig.class.getName());
private ServletConfig servletConfig;
private Map<String, BlobStoreContext> providerTypeToBlobStoreMap;
private Twitter twitterClient;
private String container;
private TaskQueue queue;
private String baseUrl;
@PostConstruct
public void initialize() throws IOException {
Properties props = loadJCloudsProperties();
LOGGER.trace("About to initialize members.");
Set<Module> modules = ImmutableSet.of();
// shared across all blobstores and used to retrieve tweets
try {
twitter4j.conf.Configuration twitterConf = new ConfigurationBuilder()
.setOAuthConsumerKey(props.getProperty(PROPERTY_TWITTER_CONSUMER_KEY))
.setOAuthConsumerSecret(props.getProperty(PROPERTY_TWITTER_CONSUMER_SECRET))
.setOAuthAccessToken(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN))
.setOAuthAccessTokenSecret(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET))
.build();
twitterClient = new TwitterFactory(twitterConf).getInstance();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("properties for twitter not configured properly in " + props.toString(), e);
}
// common namespace for storing tweets
container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), PROPERTY_TWEETSTORE_CONTAINER);
// instantiate and store references to all blobstores by provider name
providerTypeToBlobStoreMap = Maps.newHashMap();
for (String hint : getBlobstoreContexts(props)) {
providerTypeToBlobStoreMap.put(hint, ContextBuilder.newBuilder(hint)
.modules(modules).overrides(props).build(BlobStoreContext.class));
}
// get a queue for submitting store tweet requests and the application's base URL
PlatformServices platform = PlatformServices.get(servletConfig.getServletContext());
queue = platform.getTaskQueue("twitter");
baseUrl = platform.getBaseUrl();
LOGGER.trace("Members initialized. Twitter: '%s', container: '%s', provider types: '%s'", twitterClient,
container, providerTypeToBlobStoreMap.keySet());
}
private static Iterable<String> getBlobstoreContexts(Properties props) {
Set<String> contexts = new CredentialsCollector().apply(props).keySet();
String explicitContexts = props.getProperty(PROPERTY_TWEETSTORE_BLOBSTORES);
if (explicitContexts != null) {
contexts = filter(contexts, in(copyOf(Splitter.on(',').split(explicitContexts))));
}
checkState(!contexts.isEmpty(), "no credentials available for any requested context");
return contexts;
}
private Properties loadJCloudsProperties() {
LOGGER.trace("About to read properties from '%s'", "/WEB-INF/jclouds.properties");
Properties props = new Properties();
InputStream input = servletConfig.getServletContext().getResourceAsStream("/WEB-INF/jclouds.properties");
try {
props.load(input);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
Closeables.closeQuietly(input);
}
LOGGER.trace("Properties successfully read.");
return props;
}
@Bean
public StoreTweetsController storeTweetsController() {
StoreTweetsController controller = new StoreTweetsController(providerTypeToBlobStoreMap, container, twitterClient);
injectServletConfig(controller);
return controller;
}
@Bean
public AddTweetsController addTweetsController() {
AddTweetsController controller = new AddTweetsController(providerTypeToBlobStoreMap,
serviceToStoredTweetStatuses());
injectServletConfig(controller);
return controller;
}
@Bean
public EnqueueStoresController enqueueStoresController() {
return new EnqueueStoresController(providerTypeToBlobStoreMap, queue, baseUrl);
}
@Bean
public ClearTweetsController clearTweetsController() {
return new ClearTweetsController(providerTypeToBlobStoreMap, container);
}
private void injectServletConfig(Servlet servlet) {
LOGGER.trace("About to inject servlet config '%s'", servletConfig);
try {
servlet.init(checkNotNull(servletConfig));
} catch (ServletException exception) {
throw new BeanCreationException("Unable to instantiate " + servlet, exception);
}
LOGGER.trace("Successfully injected servlet config.");
}
@Bean
ServiceToStoredTweetStatuses serviceToStoredTweetStatuses() {
return new ServiceToStoredTweetStatuses(providerTypeToBlobStoreMap, container);
}
@Bean
public HandlerMapping handlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
Map<String, Object> urlMap = Maps.newHashMapWithExpectedSize(2);
urlMap.put("/store/*", storeTweetsController());
urlMap.put("/tweets/*", addTweetsController());
urlMap.put("/stores/*", enqueueStoresController());
urlMap.put("/clear/*", clearTweetsController());
mapping.setUrlMap(urlMap);
/*
* "/store", "/tweets" and "/stores" are part of the servlet mapping and thus
* stripped by the mapping if using default settings.
*/
mapping.setAlwaysUseFullPath(true);
return mapping;
}
@Bean
public HandlerAdapter servletHandlerAdapter() {
return new SimpleServletHandlerAdapter();
}
@PreDestroy
public void destroy() throws Exception {
LOGGER.trace("About to close contexts.");
for (BlobStoreContext context : providerTypeToBlobStoreMap.values()) {
context.close();
}
LOGGER.trace("Contexts closed.");
LOGGER.trace("About to purge request queue.");
queue.destroy();
LOGGER.trace("Request queue purged.");
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.context.ServletConfigAware#setServletConfig(javax.servlet.ServletConfig
* )
*/
@Override
public void setServletConfig(ServletConfig servletConfig) {
this.servletConfig = servletConfig;
}
}

View File

@ -1,153 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Collections2.filter;
import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Maps.filterValues;
import static org.jclouds.util.Maps2.fromKeys;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector.Credential;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
/**
* Reads provider credentials from a {@link Properties} bag.
*
* @author Andrew Phillips
*
*/
public class CredentialsCollector implements Function<Properties, Map<String, Credential>> {
private static final String IDENTITY_PROPERTY_SUFFIX = ".identity";
private static final String CREDENTIAL_PROPERTY_SUFFIX = ".credential";
// using the identity for provider name extraction
private static final Pattern IDENTITY_PROPERTY_PATTERN =
Pattern.compile("([a-zA-Z0-9-]+)" + Pattern.quote(IDENTITY_PROPERTY_SUFFIX));
@Override
public Map<String, Credential> apply(final Properties properties) {
Collection<String> providerNames = transform(
filter(properties.stringPropertyNames(), MatchesPattern.matches(IDENTITY_PROPERTY_PATTERN)),
new Function<String, String>() {
@Override
public String apply(String input) {
Matcher matcher = IDENTITY_PROPERTY_PATTERN.matcher(input);
// as a side-effect, sets the matching group!
checkState(matcher.matches(), "'%s' should match '%s'", input, IDENTITY_PROPERTY_PATTERN);
return matcher.group(1);
}
});
/*
* Providers without a credential property result in null values, which are
* removed from the returned map.
*/
return filterValues(fromKeys(copyOf(providerNames), new Function<String, Credential>() {
@Override
public Credential apply(String providerName) {
String identity = properties.getProperty(providerName + IDENTITY_PROPERTY_SUFFIX);
String credential = properties.getProperty(providerName + CREDENTIAL_PROPERTY_SUFFIX);
return (((identity != null) && (credential != null))
? new Credential(identity, credential)
: null);
}
}), notNull());
}
public static class Credential {
private final String identity;
private final String credential;
public Credential(String identity, String credential) {
this.identity = checkNotNull(identity, "identity");
this.credential = checkNotNull(credential, "credential");
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((credential == null) ? 0 : credential.hashCode());
result = prime * result
+ ((identity == null) ? 0 : identity.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;
Credential other = (Credential) obj;
if (credential == null) {
if (other.credential != null)
return false;
} else if (!credential.equals(other.credential))
return false;
if (identity == null) {
if (other.identity != null)
return false;
} else if (!identity.equals(other.identity))
return false;
return true;
}
public String getIdentity() {
return identity;
}
public String getCredential() {
return credential;
}
}
@GwtIncompatible(value = "java.util.regex.Pattern")
private static class MatchesPattern implements Predicate<String> {
private final Pattern pattern;
private MatchesPattern(Pattern pattern) {
this.pattern = pattern;
}
@Override
public boolean apply(String input) {
return pattern.matcher(input).matches();
}
private static MatchesPattern matches(Pattern pattern) {
return new MatchesPattern(pattern);
}
}
}

View File

@ -1,59 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.servlet.ServletContext;
import com.google.common.io.Closeables;
import com.google.inject.Provider;
/**
* @author Andrew Phillips
*/
public class PropertiesLoader implements Provider<Properties>{
private static final String PROPERTIES_FILE = "/WEB-INF/jclouds.properties";
private final Properties properties;
public PropertiesLoader(ServletContext context) {
properties = loadJcloudsProperties(context);
}
private static Properties loadJcloudsProperties(ServletContext context) {
InputStream input = context.getResourceAsStream(PROPERTIES_FILE);
Properties props = new Properties();
try {
props.load(input);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
Closeables.closeQuietly(input);
}
return props;
}
@Override
public Properties get() {
return properties;
}
}

View File

@ -1,96 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
/**
* Shows an example of how to use @{link BlobStoreContext} injected with Guice.
*
* @author Adrian Cole
*/
@Singleton
public class AddTweetsController extends HttpServlet implements
Function<Set<String>, List<StoredTweetStatus>> {
/** The serialVersionUID */
private static final long serialVersionUID = 3888348023150822683L;
private final Map<String, BlobStoreContext> contexts;
private final ServiceToStoredTweetStatuses blobStoreContextToContainerResult;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public AddTweetsController(Map<String, BlobStoreContext> contexts,
ServiceToStoredTweetStatuses blobStoreContextToContainerResult) {
this.contexts = contexts;
this.blobStoreContextToContainerResult = blobStoreContextToContainerResult;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
addMyTweetsToRequest(request);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/tweets.jsp");
dispatcher.forward(request, response);
} catch (Exception e) {
logger.error(e, "Error listing containers");
throw new ServletException(e);
}
}
void addMyTweetsToRequest(HttpServletRequest request) throws InterruptedException,
ExecutionException, TimeoutException {
request.setAttribute("tweets", apply(contexts.keySet()));
}
public List<StoredTweetStatus> apply(Set<String> in) {
List<StoredTweetStatus> statuses = Lists.newArrayList();
for (Iterable<StoredTweetStatus> list : Iterables.transform(in,
blobStoreContextToContainerResult)) {
Iterables.addAll(statuses, list);
}
return statuses;
}
}

View File

@ -1,96 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.nullToEmpty;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
/**
* Grab tweets related to me and store them into blobstores
*
* @author Adrian Cole
*/
@Singleton
public class ClearTweetsController extends HttpServlet {
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Map<String, BlobStoreContext> contexts;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
@Inject
@VisibleForTesting
public ClearTweetsController(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container) {
this.container = container;
this.contexts = contexts;
}
@VisibleForTesting
public void clearContainer(String contextName) {
BlobStoreContext context = checkNotNull(contexts.get(contextName),
"no context for %s in %s", contextName, contexts.keySet());
try {
context.getBlobStore().clearContainer(container);
} catch (Exception e) {
logger.error(e, "Error clearing tweets in %s/%s", container, context);
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (nullToEmpty(request.getHeader("X-Originator")).equals("admin")) {
try {
String contextName = checkNotNull(request.getHeader("context"), "missing header context");
logger.info("clearing tweets in %s/%s", container, contextName);
clearContainer(contextName);
logger.debug("done clearing tweets");
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error clearing tweets");
throw new ServletException(e);
}
} else {
response.sendError(401);
}
}
}

View File

@ -1,101 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.common.base.Strings.nullToEmpty;
import static org.jclouds.demo.paas.RunnableHttpRequest.PLATFORM_REQUEST_ORIGINATOR_HEADER;
import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.paas.reference.PaasConstants;
import org.jclouds.demo.paas.service.taskqueue.TaskQueue;
import org.jclouds.http.HttpRequest;
import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMultimap;
/**
* Adds tasks to retrieve and store tweets in all registered contexts to an async
* task queue.
*
* @author Andrew Phillips
* @see StoreTweetsController
*/
@Singleton
public class EnqueueStoresController extends HttpServlet {
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Set<String> contextNames;
private final TaskQueue taskQueue;
private final String baseUrl;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public EnqueueStoresController(Map<String, BlobStoreContext> contexts, TaskQueue taskQueue,
@Named(PaasConstants.PROPERTY_PLATFORM_BASE_URL) String baseUrl) {
contextNames = contexts.keySet();
this.taskQueue = taskQueue;
this.baseUrl = baseUrl;
}
@VisibleForTesting
void enqueueStoreTweetTasks() {
for (String contextName : contextNames) {
logger.debug("enqueuing task to store tweets in blobstore '%s'", contextName);
taskQueue.add(taskQueue.getHttpRequestFactory().create(HttpRequest.builder()
.endpoint(URI.create(baseUrl + "/store/do"))
.headers(ImmutableMultimap.of("context", contextName))
.method("GET").build()));
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (!nullToEmpty(request.getHeader(PLATFORM_REQUEST_ORIGINATOR_HEADER)).equals("scheduler")) {
response.sendError(401);
}
try {
enqueueStoreTweetTasks();
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error storing tweets");
throw new ServletException(e);
}
}
}

View File

@ -1,130 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.nullToEmpty;
import static org.jclouds.demo.paas.RunnableHttpRequest.PLATFORM_REQUEST_ORIGINATOR_HEADER;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import twitter4j.Status;
import twitter4j.Twitter;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
/**
* Grab tweets related to me and store them into blobstores
*
* @author Adrian Cole
*/
@Singleton
public class StoreTweetsController extends HttpServlet {
private static final class StatusToBlob implements Function<Status, Blob> {
private final BlobMap map;
private StatusToBlob(BlobMap map) {
this.map = map;
}
public Blob apply(Status from) {
Blob to = map.blobBuilder().name(from.getId() + "").build();
to.setPayload(from.getText());
to.getPayload().getContentMetadata().setContentType(MediaType.TEXT_PLAIN);
to.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, from.getUser().getScreenName());
return to;
}
}
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Map<String, BlobStoreContext> contexts;
private final Twitter client;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
@Inject
@VisibleForTesting
public StoreTweetsController(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container, Twitter client) {
this.container = container;
this.contexts = contexts;
this.client = client;
}
@VisibleForTesting
public void addMyTweets(String contextName, Iterable<Status> responseList) {
BlobStoreContext context = checkNotNull(contexts.get(contextName), "no context for " + contextName + " in "
+ contexts.keySet());
BlobMap map = context.createBlobMap(container);
for (Status status : responseList) {
Blob blob = null;
try {
blob = new StatusToBlob(map).apply(status);
map.put(status.getId() + "", blob);
} catch (AuthorizationException e) {
throw e;
} catch (Exception e) {
logger.error(e, "Error storing tweet %s (blob[%s]) on map %s/%s", status.getId(), blob, context, container);
}
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (nullToEmpty(request.getHeader(PLATFORM_REQUEST_ORIGINATOR_HEADER)).equals("taskqueue-twitter")) {
try {
String contextName = checkNotNull(request.getHeader("context"), "missing header context");
logger.info("retrieving tweets");
addMyTweets(contextName, client.getMentions());
logger.debug("done storing tweets");
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error storing tweets");
throw new ServletException(e);
}
} else {
response.sendError(401);
}
}
}

View File

@ -1,149 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.domain;
import java.io.Serializable;
/**
*
* @author Adrian Cole
*/
public class StoredTweetStatus implements Comparable<StoredTweetStatus>, Serializable {
/** The serialVersionUID */
private static final long serialVersionUID = -3257496189689220018L;
private final String service;
private final String host;
private final String container;
private final String id;
private final String from;
private final String tweet;
private final String status;
@Override
public String toString() {
return "StoredTweetStatus [container=" + container + ", from=" + from + ", host=" + host
+ ", id=" + id + ", service=" + service + ", status=" + status + ", tweet=" + tweet
+ "]";
}
public StoredTweetStatus(String service, String host, String container, String id, String from,
String tweet, String status) {
this.service = service;
this.host = host;
this.container = container;
this.id = id;
this.from = from;
this.tweet = tweet;
this.status = status;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((container == null) ? 0 : container.hashCode());
result = prime * result + ((from == null) ? 0 : from.hashCode());
result = prime * result + ((host == null) ? 0 : host.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((service == null) ? 0 : service.hashCode());
result = prime * result + ((tweet == null) ? 0 : tweet.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;
StoredTweetStatus other = (StoredTweetStatus) obj;
if (container == null) {
if (other.container != null)
return false;
} else if (!container.equals(other.container))
return false;
if (from == null) {
if (other.from != null)
return false;
} else if (!from.equals(other.from))
return false;
if (host == null) {
if (other.host != null)
return false;
} else if (!host.equals(other.host))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (service == null) {
if (other.service != null)
return false;
} else if (!service.equals(other.service))
return false;
if (tweet == null) {
if (other.tweet != null)
return false;
} else if (!tweet.equals(other.tweet))
return false;
return true;
}
public String getService() {
return service;
}
public String getHost() {
return host;
}
public String getContainer() {
return container;
}
public String getFrom() {
return from;
}
public String getTweet() {
return tweet;
}
public String getStatus() {
return status;
}
public int compareTo(StoredTweetStatus o) {
if (id == null)
return -1;
return (int) ((this == o) ? 0 : id.compareTo(o.id));
}
public String getId() {
return id;
}
}

View File

@ -1,70 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import javax.annotation.Resource;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import org.jclouds.util.Strings2;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
public class KeyToStoredTweetStatus implements Function<String, StoredTweetStatus> {
private final String host;
private final BlobMap map;
private final String service;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
KeyToStoredTweetStatus(BlobMap map, String service, String host, String container) {
this.host = host;
this.map = map;
this.service = service;
this.container = container;
}
public StoredTweetStatus apply(String id) {
String status;
String from;
String tweet;
try {
long start = System.currentTimeMillis();
Blob blob = map.get(id);
status = ((System.currentTimeMillis() - start) + "ms");
from = blob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME);
tweet = Strings2.toString(blob.getPayload());
} catch (Exception e) {
logger.error(e, "Error listing container %s//%s/%s", service, container, id);
status = (e.getMessage());
tweet = "";
from = "";
}
return new StoredTweetStatus(service, host, container, id, from, tweet, status);
}
}

View File

@ -1,72 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Context;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
@Singleton
public class ServiceToStoredTweetStatuses implements Function<String, Iterable<StoredTweetStatus>> {
private final Map<String, BlobStoreContext> contexts;
private final String container;
@Inject
public ServiceToStoredTweetStatuses(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container) {
this.contexts = contexts;
this.container = container;
}
@Resource
protected Logger logger = Logger.NULL;
public Iterable<StoredTweetStatus> apply(String service) {
BlobStoreContext context = contexts.get(service);
String host = URI.create(context.unwrap(Context.class).getProviderMetadata().getEndpoint()).getHost();
try {
BlobMap blobMap = context.createBlobMap(container);
Set<String> blobs = blobMap.keySet();
return Iterables.transform(blobs, new KeyToStoredTweetStatus(blobMap, service, host,
container));
} catch (Exception e) {
StoredTweetStatus result = new StoredTweetStatus(service, host, container, null, null,
null, e.getMessage());
logger.error(e, "Error listing service %s", service);
return ImmutableList.of(result);
}
}
}

View File

@ -1,34 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.reference;
/**
* Configuration properties and constants used in TweetStore connections.
*
* @author Adrian Cole
*/
public interface TweetStoreConstants {
static final String PROPERTY_TWEETSTORE_BLOBSTORES = "jclouds.tweetstore.blobstores";
static final String PROPERTY_TWEETSTORE_CONTAINER = "jclouds.tweetstore.container";
/**
* Note that this has to conform to restrictions of all blobstores. for
* example, azure doesn't support periods.
*/
static final String SENDER_NAME = "sendername";
}

View File

@ -1,31 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.reference;
/**
* Configuration properties and constants used in Twitter connections.
*
* @author Andrew Phillips
*/
public interface TwitterConstants {
static final String PROPERTY_TWITTER_CONSUMER_KEY = "twitter.consumer.identity";
static final String PROPERTY_TWITTER_CONSUMER_SECRET = "twitter.consumer.credential";
static final String PROPERTY_TWITTER_ACCESSTOKEN = "twitter.access.identity";
static final String PROPERTY_TWITTER_ACCESSTOKEN_SECRET = "twitter.access.credential";
}

View File

@ -1 +0,0 @@
# PaaS vendor specific files go in here

View File

@ -1,29 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<job-scheduling-data xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd"
version="2.0">
<schedule>
<job>
<name>enqueue-store-tweet-tasks</name>
<description>Enqueue 'store tweet' tasks for all contexts</description>
<job-class>org.jclouds.demo.paas.service.scheduler.HttpRequestJob</job-class>
<job-data-map>
<entry>
<key>url</key>
<value>/stores/do</value>
</entry>
</job-data-map>
</job>
<trigger>
<calendar-interval>
<name>submit-recurring-job</name>
<job-name>enqueue-store-tweet-tasks</job-name>
<repeat-interval>10</repeat-interval>
<repeat-interval-unit>MINUTE</repeat-interval-unit>
</calendar-interval>
</trigger>
</schedule>
</job-scheduling-data>

View File

@ -1,28 +0,0 @@
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.skipUpdateCheck: true
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 1
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#============================================================================
# Configure the Job Initialization Plugin
#============================================================================
org.quartz.plugin.jobInitializer.class: org.jclouds.demo.paas.service.scheduler.quartz.plugins.TransactionlessXmlSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames: jobs.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound: true
org.quartz.plugin.jobInitializer.scanInterval: 0
#org.quartz.plugin.jobInitializer.wrapInUserTransaction: false

View File

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
version="2.5">
<display-name>jclouds-tweetstore</display-name>
<context-param>
<param-name>quartz:scheduler-context-servlet-context-key</param-name>
<param-value>servlet-context</param-value>
</context-param>
<!-- must be started first -->
<listener>
<listener-class>org.jclouds.demo.paas.config.PlatformServicesInitializer</listener-class>
</listener>
<listener>
<listener-class>org.quartz.ee.servlet.QuartzInitializerListener</listener-class>
</listener>
<!-- Servlets -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.jclouds.demo.tweetstore.config.SpringServletConfig</param-value>
</init-param>
</servlet>
<!-- should be kept in sync with the mappings defined in SpringServletConfig -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/store/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/tweets/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/stores/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/clear/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -1,30 +0,0 @@
<%--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
--%>
<html>
<head>
<title>jclouds: anyweight cloudware for java</title>
</head>
<body>
<h2>Welcome!</h2>
<p>Click <a href="/tweets/get">here</a> to see tweets about jclouds.</p>
<p><img src="/images/cloudfoundry-logo.png" alt="Powered by Cloud Foundry" /></p>
</body>
</html>

View File

@ -1,108 +0,0 @@
<%--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
--%>
<%@ page buffer="20kb"%>
<%@ taglib uri="http://displaytag.sf.net" prefix="display"%>
<html>
<head>
<title>jclouds: anyweight cloudware for java</title>
<style type="text/css">
<!--
table.staticheader {
text-decoration: none;
border: 1px solid #CCC;
width: 98%;
}
table.staticheader th {
padding: 3px 3px 3px 3px !important;
text-align:center;
}
table.staticheader td {
padding: 3px 3px 3px 3px !important;
}
table.staticheader thead tr {
position: relative;
height: 10px;
background-color: #D7E5F3;
}
table.staticheader tbody {
height:800px;
overflow-x:hidden;
overflow-y: auto;
overflow:scroll;
}
table.staticheader tbody tr {
height: auto;
white-space: nowrap;
}
table.staticheader tbody tr.odd {
background-color: #eee
}
table.staticheader tbody tr.tableRowEven,tr.even {
background-color: #ddd
}
table.staticheader tbody tr td:last-child {
padding-right: 20px;
}
table.staticheader tbody td {
padding: 2px 4px 2px 4px !important;
}
div.TableContainer {
height: 800px;
overflow-x:hidden;
overflow-y:auto;
}
-->
</style>
</head>
<body>
<h2>Tweets in Clouds</h2>
<table width="100%" border="0">
<tr>
<td>
<div class="TableContainer">
<display:table name="tweets" defaultsort="1" cellpadding="5" cellspacing="1" class="staticheader">
<display:column property="id" title="Tweet ID" />
<display:column property="from" title="Who Said it" />
<display:column property="tweet" title="Tweet" />
<display:column property="service" title="Cloud" />
<display:column property="host" title="Host" />
<display:column property="status" title="Status" />
</display:table>
</div>
</td>
</tr>
<tr>
<td><img src="/images/cloudfoundry-logo.png" alt="Powered by Cloud Foundry" /></td>
</tr>
</table>
</body>
</html>

View File

@ -1,82 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config.util;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Map;
import java.util.Properties;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector.Credential;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@code CredentialsCollector}
*
* @author Andrew Phillips
*/
@Test(groups = "unit")
public class CredentialsCollectorTest {
private CredentialsCollector collector = new CredentialsCollector();
public void testEmptyProperties() {
assertTrue(collector.apply(new Properties()).isEmpty(),
"Expected returned map to be empty");
}
public void testNoCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("not-an-identity",
"v1", "not-a-credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
private static Properties propertiesOf(Map<String, String> entries) {
Properties properties = new Properties();
properties.putAll(entries);
return properties;
}
public void testNonMatchingCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("non_matching.identity", "v1",
"non_matching.credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
public void testIncompleteCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("acme.identity", "v1",
"acme-2.credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
public void testCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("acme.identity", "v1",
"acme.credential", "v2", "acme-2.identity", "v3",
"acme-2.credential", "v4"));
assertEquals(collector.apply(properties),
ImmutableMap.of("acme", new Credential("v1", "v2"),
"acme-2", new Credential("v3", "v4")));
}
}

View File

@ -1,78 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
import org.testng.collections.Maps;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code AddTweetsController}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class AddTweetsControllerTest {
Map<String, BlobStoreContext> createServices(String container) throws InterruptedException,
ExecutionException {
Map<String, BlobStoreContext> services = Maps.newHashMap();
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
for (String name : new String[] { "1", "2" }) {
BlobStoreContext context = ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class);
context.getAsyncBlobStore().createContainerInLocation(null, container).get();
Blob blob = context.getAsyncBlobStore().blobBuilder("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
context.getAsyncBlobStore().putBlob(container, blob).get();
services.put(name, context);
}
return services;
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
String container = "container";
Map<String, BlobStoreContext> contexts = createServices(container);
ServiceToStoredTweetStatuses function = new ServiceToStoredTweetStatuses(contexts, container);
AddTweetsController controller = new AddTweetsController(contexts, function);
List<StoredTweetStatus> list = controller.apply(ImmutableSet.of("1", "2"));
assertEquals(list.size(), 2);
assertEquals(list, ImmutableList.of(new StoredTweetStatus("1", "localhost", container, "1",
"frank", "I love beans!", null), new StoredTweetStatus("2", "localhost", container,
"1", "frank", "I love beans!", null)));
}
}

View File

@ -1,72 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@code AddTweetsController}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ClearTweetsControllerTest {
Map<String, BlobStoreContext> createBlobStores(String container) throws InterruptedException, ExecutionException {
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext>of(
"test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class),
"test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class));
for (BlobStoreContext blobstore : contexts.values()) {
blobstore.getBlobStore().createContainerInLocation(null, container);
Blob blob = blobstore.getAsyncBlobStore().blobBuilder("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
blobstore.getBlobStore().putBlob(container, blob);
}
return contexts;
}
public void testClearTweets() throws IOException, InterruptedException, ExecutionException {
String container = ClearTweetsControllerTest.class.getName() + "#container";
Map<String, BlobStoreContext> contexts = createBlobStores(container);
ClearTweetsController controller = new ClearTweetsController(contexts,
container);
controller.clearContainer("test1");
controller.clearContainer("test2");
for (BlobStoreContext context : contexts.values()) {
assertEquals(context.getBlobStore().countBlobs(container), 0, context.toString());
}
}
}

View File

@ -1,85 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.easymock.EasyMock.*;
import java.net.URI;
import java.util.Map;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.demo.paas.RunnableHttpRequest;
import org.jclouds.demo.paas.RunnableHttpRequest.Factory;
import org.jclouds.demo.paas.service.taskqueue.TaskQueue;
import org.jclouds.http.HttpRequest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
/**
* Tests behavior of {@code EnqueueStoresController}
*
* @author Andrew Phillips
*/
@Test(groups = "unit")
public class EnqueueStoresControllerTest {
Map<String, BlobStoreContext> createBlobStores() {
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext>of(
"test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class),
"test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class));
return contexts;
}
public void testEnqueueStores() {
Map<String, BlobStoreContext> stores = createBlobStores();
TaskQueue taskQueue = createMock(TaskQueue.class);
Factory httpRequestFactory = createMock(Factory.class);
EnqueueStoresController function = new EnqueueStoresController(stores,
taskQueue, "http://localhost:8080");
expect(taskQueue.getHttpRequestFactory()).andStubReturn(httpRequestFactory);
HttpRequest storeInTest1Request = HttpRequest.builder().endpoint(
URI.create("http://localhost:8080/store/do"))
.headers(ImmutableMultimap.of("context", "test1")).method("GET").build();
RunnableHttpRequest storeInTest1Task = null;
expect(httpRequestFactory.create(eq(storeInTest1Request))).andReturn(storeInTest1Task);
HttpRequest storeInTest2Request = HttpRequest.builder().endpoint(
URI.create("http://localhost:8080/store/do"))
.headers(ImmutableMultimap.of("context", "test2")).method("GET").build();
RunnableHttpRequest storeInTest2Task = null;
expect(httpRequestFactory.create(eq(storeInTest2Request))).andReturn(storeInTest2Task);
taskQueue.add(storeInTest1Task);
expectLastCall();
taskQueue.add(storeInTest2Task);
expectLastCall();
replay(httpRequestFactory, taskQueue);
function.enqueueStoreTweetTasks();
verify(taskQueue);
}
}

View File

@ -1,120 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.util.Strings2;
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;
/**
* Tests behavior of {@code StoreTweetsController}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class StoreTweetsControllerTest {
Twitter createTwitter() {
return createMock(Twitter.class);
}
Map<String, BlobStoreContext> createBlobStores() throws InterruptedException, ExecutionException {
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext>of(
"test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class),
"test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class));
for (BlobStoreContext blobstore : contexts.values()) {
blobstore.getAsyncBlobStore().createContainerInLocation(null, "favo").get();
}
return contexts;
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
Map<String, BlobStoreContext> stores = createBlobStores();
StoreTweetsController function = new StoreTweetsController(stores, "favo", createTwitter());
User frank = createMock(User.class);
expect(frank.getScreenName()).andReturn("frank").atLeastOnce();
Status frankStatus = createMock(Status.class);
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();
Status jimmyStatus = createMock(Status.class);
expect(jimmyStatus.getId()).andReturn(2l).atLeastOnce();
expect(jimmyStatus.getUser()).andReturn(jimmy).atLeastOnce();
expect(jimmyStatus.getText()).andReturn("cloud is king").atLeastOnce();
replay(frank);
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()) {
BlobMap map = entry.getValue().createBlobMap("favo");
Blob frankBlob = map.get("1");
assertEquals(frankBlob.getMetadata().getName(), "1");
assertEquals(frankBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "frank");
assertEquals(frankBlob.getMetadata().getContentMetadata().getContentType(), "text/plain");
assertEquals(Strings2.toString(frankBlob.getPayload()), "I love beans!");
Blob jimmyBlob = map.get("2");
assertEquals(jimmyBlob.getMetadata().getName(), "2");
assertEquals(jimmyBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "jimmy");
assertEquals(jimmyBlob.getMetadata().getContentMetadata().getContentType(), "text/plain");
assertEquals(Strings2.toString(jimmyBlob.getPayload()), "cloud is king");
}
}
}

View File

@ -1,69 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code KeyToStoredTweetStatus}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class KeyToStoredTweetStatusTest {
BlobMap createMap() throws InterruptedException, ExecutionException {
BlobStoreContext context =
ContextBuilder.newBuilder(TransientApiMetadata.builder().build()).build(BlobStoreContext.class);
context.getBlobStore().createContainerInLocation(null, "test1");
return context.createBlobMap("test1");
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
BlobMap map = createMap();
Blob blob = map.blobBuilder().name("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
map.put("1", blob);
String host = "localhost";
String service = "stub";
String container = "tweetstore";
KeyToStoredTweetStatus function = new KeyToStoredTweetStatus(map, service, host, container);
StoredTweetStatus result = function.apply("1");
StoredTweetStatus expected = new StoredTweetStatus(service, host, container, "1", "frank",
"I love beans!", null);
assertEquals(result, expected);
}
}

View File

@ -1,75 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
import org.testng.collections.Maps;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code ServiceToStoredTweetStatuses}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ServiceToStoredTweetStatusesTest {
Map<String, BlobStoreContext> createServices(String container) throws InterruptedException,
ExecutionException {
Map<String, BlobStoreContext> services = Maps.newHashMap();
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
for (String name : new String[] { "1", "2" }) {
BlobStoreContext context = ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class);
context.getAsyncBlobStore().createContainerInLocation(null, container).get();
Blob blob = context.getAsyncBlobStore().blobBuilder("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
context.getAsyncBlobStore().putBlob(container, blob).get();
services.put(name, context);
}
return services;
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
String container = "container";
Map<String, BlobStoreContext> contexts = createServices(container);
ServiceToStoredTweetStatuses function = new ServiceToStoredTweetStatuses(contexts, container);
assertEquals(Iterables.getLast(function.apply("1")), new StoredTweetStatus("1", "localhost",
container, "1", "frank", "I love beans!", null));
assertEquals(Iterables.getLast(function.apply("2")), new StoredTweetStatus("2", "localhost",
container, "1", "frank", "I love beans!", null));
}
}

View File

@ -1,106 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.integration;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.io.Closeables.closeQuietly;
import static java.lang.String.format;
import static org.jclouds.demo.tweetstore.integration.util.Zips.zipDir;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.cloudfoundry.client.lib.CloudApplication.AppState;
import org.cloudfoundry.client.lib.CloudFoundryClient;
/**
* Basic &quot;server facade&quot; functionality to deploy a WAR to Cloud Foundry.
*
* @author Andrew Phillips
*/
public class CloudFoundryServer {
private static final String CLOUD_FOUNDRY_APPLICATION_URL_SUFFIX = ".cloudfoundry.com";
protected CloudFoundryClient client;
protected String appName;
public void writePropertiesAndStartServer(final String address, final String warfile,
String target, String username, String password, Properties props) throws IOException, InterruptedException, ExecutionException {
String propsfile = String.format("%1$s/WEB-INF/jclouds.properties", warfile);
System.err.println("file: " + propsfile);
storeProperties(propsfile, props);
assert new File(propsfile).exists();
client = new CloudFoundryClient(username, password, target);
client.login();
appName = getAppName(address);
deploy(warfile);
client.logout();
TimeUnit.SECONDS.sleep(10);
}
private void deploy(String explodedWar) throws IOException {
File war = zipDir(explodedWar, format("%s-cloudfoundry.war", explodedWar));
client.uploadApplication(appName, war);
// adapted from https://github.com/cloudfoundry/vcap-java-client/blob/master/cloudfoundry-maven-plugin/src/main/java/org/cloudfoundry/maven/Update.java
AppState appState = client.getApplication(appName).getState();
switch (appState) {
case STOPPED:
client.startApplication(appName);
break;
case STARTED:
client.restartApplication(appName);
break;
default:
throw new IllegalStateException(format("Unexpected application state '%s'", appState));
}
}
private static void storeProperties(String filename, Properties props)
throws IOException {
FileOutputStream targetFile = new FileOutputStream(filename);
try {
props.store(targetFile, "test");
} finally {
closeQuietly(targetFile);
}
}
private static String getAppName(String applicationUrl) {
checkArgument(applicationUrl.endsWith(CLOUD_FOUNDRY_APPLICATION_URL_SUFFIX),
"Application URL '%s' does not end in '%s'", applicationUrl,
CLOUD_FOUNDRY_APPLICATION_URL_SUFFIX);
return applicationUrl.substring(0,
applicationUrl.length() - CLOUD_FOUNDRY_APPLICATION_URL_SUFFIX.length());
}
public void stop() throws Exception {
checkState(client != null, "'stop' called before 'writePropertiesAndStartServer'");
client.login();
client.stopApplication(appName);
client.logout();
}
}

View File

@ -1,234 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.integration;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_BLOBSTORES;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN_SECRET;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_KEY;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_SECRET;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.Context;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.config.SpringServletConfig;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.util.Strings2;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.inject.Module;
/**
* Starts up the Google App Engine for Java Development environment and deploys an application which
* tests accesses twitter and blobstores.
*
* @author Adrian Cole
*/
@Test(groups = "live", singleThreaded = true)
public class TweetStoreLiveTest {
CloudFoundryServer server;
private URL url;
private Map<String, BlobStoreContext> contexts;
private String container;
private static final Iterable<String> blobstores =
Splitter.on(',').split(System.getProperty(PROPERTY_TWEETSTORE_BLOBSTORES,
"cloudfiles-us,aws-s3,azureblob"));
private static final Properties props = new Properties();
@BeforeTest
void clearAndCreateContainers() throws InterruptedException, ExecutionException, TimeoutException, IOException,
TwitterException {
container = getRequiredSystemProperty(PROPERTY_TWEETSTORE_CONTAINER);
props.setProperty(PROPERTY_TWEETSTORE_CONTAINER, container);
props.setProperty(SpringServletConfig.PROPERTY_BLOBSTORE_CONTEXTS, Joiner.on(',').join(blobstores));
// put all identity/credential pairs into the client
addCredentialsForBlobStores(props);
// example of an ad-hoc client configuration
addConfigurationForTwitter(props);
// for testing, capture logs.
final Set<Module> wiring = ImmutableSet.<Module> of(new Log4JLoggingModule());
this.contexts = Maps.newConcurrentMap();
for (String provider : blobstores) {
contexts.put(provider, ContextBuilder.newBuilder(provider).modules(wiring)
.overrides(props).build(BlobStoreContext.class));
}
Configuration conf = new ConfigurationBuilder()
.setOAuthConsumerKey(props.getProperty(PROPERTY_TWITTER_CONSUMER_KEY))
.setOAuthConsumerSecret(props.getProperty(PROPERTY_TWITTER_CONSUMER_SECRET))
.setOAuthAccessToken(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN))
.setOAuthAccessTokenSecret(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET))
.build();
Twitter client = new TwitterFactory(conf).getInstance();
StoreTweetsController controller = new StoreTweetsController(contexts, container, client);
ResponseList<Status> statuses = client.getMentions();
boolean deleted = false;
for (BlobStoreContext context : contexts.values()) {
if (context.getBlobStore().containerExists(container)) {
System.err.printf("deleting container %s at %s%n", container,
context.unwrap(Context.class).getProviderMetadata().getEndpoint());
context.getBlobStore().deleteContainer(container);
deleted = true;
}
}
if (deleted) {
System.err.println("sleeping 60 seconds to allow containers to clear");
Thread.sleep(60000);
}
for (BlobStoreContext context : contexts.values()) {
System.err.printf("creating container %s at %s%n", container,
context.unwrap(Context.class).getProviderMetadata().getEndpoint());
context.getBlobStore().createContainerInLocation(null, container);
}
if (deleted) {
System.err.println("sleeping 5 seconds to allow containers to create");
Thread.sleep(5000);
}
for (Entry<String, BlobStoreContext> entry : contexts.entrySet()) {
System.err.printf("filling container %s at %s%n", container, entry.getKey());
controller.addMyTweets(entry.getKey(), statuses);
}
}
private static String getRequiredSystemProperty(String key) {
return checkNotNull(System.getProperty(key), key);
}
private void addConfigurationForTwitter(Properties props) {
props.setProperty(PROPERTY_TWITTER_CONSUMER_KEY,
getRequiredSystemProperty("test." + PROPERTY_TWITTER_CONSUMER_KEY));
props.setProperty(PROPERTY_TWITTER_CONSUMER_SECRET,
getRequiredSystemProperty("test." + PROPERTY_TWITTER_CONSUMER_SECRET));
props.setProperty(PROPERTY_TWITTER_ACCESSTOKEN,
getRequiredSystemProperty("test." + PROPERTY_TWITTER_ACCESSTOKEN));
props.setProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET,
getRequiredSystemProperty("test." + PROPERTY_TWITTER_ACCESSTOKEN_SECRET));
}
private void addCredentialsForBlobStores(Properties props) {
for (String provider : blobstores) {
props.setProperty(provider + ".identity",
getRequiredSystemProperty("test." + provider + ".identity"));
props.setProperty(provider + ".credential",
getRequiredSystemProperty("test." + provider + ".credential"));
}
}
@BeforeTest
@Parameters({ "warfile", "cloudfoundry.address", "cloudfoundry.port", "cloudfoundry.target", "cloudfoundry.username", "cloudfoundry.password" })
public void startDevAppServer(final String warfile, final String address, final String port,
String target, String username, String password) throws Exception {
url = new URL(String.format("http://%s:%s", address, port));
server = new CloudFoundryServer();
server.writePropertiesAndStartServer(address, warfile, target, username, password, props);
}
@Test
public void shouldPass() throws InterruptedException, IOException {
InputStream i = url.openStream();
String string = Strings2.toStringAndClose(i);
assert string.indexOf("Welcome") >= 0 : string;
}
@Test(dependsOnMethods = "shouldPass", expectedExceptions = IOException.class)
public void shouldFail() throws InterruptedException, IOException {
new URL(url, "/store/do").openStream();
}
@Test(dependsOnMethods = "shouldFail")
public void testPrimeContainers() throws IOException, InterruptedException {
URL gurl = new URL(url, "/store/do");
for (String context : blobstores) {
System.out.println("storing at context: " + context);
HttpURLConnection connection = (HttpURLConnection) gurl.openConnection();
connection.addRequestProperty("X-Platform-Originator", "taskqueue-twitter");
connection.addRequestProperty("context", context);
InputStream i = connection.getInputStream();
String string = Strings2.toStringAndClose(i);
assert string.indexOf("Done!") >= 0 : string;
connection.disconnect();
}
System.err.println("sleeping 20 seconds to allow for eventual consistency delay");
Thread.sleep(20000);
for (BlobStoreContext context : contexts.values()) {
assert context.createInputStreamMap(container).size() > 0 : context.unwrap(Context.class).getProviderMetadata().getEndpoint();
}
}
@Test(invocationCount = 5, dependsOnMethods = "testPrimeContainers")
public void testSerial() throws InterruptedException, IOException {
URL gurl = new URL(url, "/tweets/get");
InputStream i = gurl.openStream();
String string = Strings2.toStringAndClose(i);
assert string.indexOf("Tweets in Clouds") >= 0 : string;
}
@Test(invocationCount = 10, dependsOnMethods = "testPrimeContainers", threadPoolSize = 3)
public void testParallel() throws InterruptedException, IOException {
URL gurl = new URL(url, "/tweets/get");
InputStream i = gurl.openStream();
String string = Strings2.toStringAndClose(i);
assert string.indexOf("Tweets in Clouds") >= 0 : string;
}
@AfterTest
public void stopDevAppServer() throws Exception {
server.stop();
}
}

View File

@ -1,36 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.integration.util;
import java.io.File;
import java.io.IOException;
import org.codehaus.plexus.archiver.zip.ZipArchiver;
public class Zips {
public static File zipDir(String dirToZip, String zipFile) throws IOException {
ZipArchiver archiver = new ZipArchiver();
archiver.addDirectory(new File(dirToZip));
File zip = new File(zipFile);
archiver.setDestFile(zip);
archiver.createArchive();
return zip;
}
}

View File

@ -1,95 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<!--
<category name="jclouds.wire"> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> </category> <category
name="jclouds.signature"> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> </category>
-->
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -1,64 +0,0 @@
====
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
====
This sample is a "port" of jclouds-demo-gae-tweetstore with the initial context setup
and wiring carried out with Spring. It is intended to demonstrate how to integrate
jclouds into your Spring application.
It should not be regarded as a sample of how to write a web application using Spring,
however! The original jclouds-demo-gae-tweetstore has been modified in as few places as
possible; it has not been rewritten in the style of a Spring MVC application.
A guide to generating Twitter consumer keys and access tokens is at http://tinyurl.com/2fhebgb
This sample uses the Google App Engine for Java SDK located at
http://code.google.com/p/googleappengine/downloads/list
Please unzip the above file and modify your maven settings.xml like below before
attempting to run 'mvn -Plive install'
<profile>
<id>appengine</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<appengine.sdk.root>/path/to/appengine-java-sdk-1.4.2</appengine.home>
<appengine.applicationid>yourappid</appengine.applicationid>
</properties>
</profile>
<profile>
<id>keys</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<test.aws-s3.identity>YOUR_ACCESS_KEY_ID</test.aws-s3.identity>
<test.aws-s3.credential>YOUR_SECRET_KEY</test.aws-s3.credential>
<test.cloudfiles-us.identity>YOUR_USER</test.cloudfiles-us.identity>
<test.cloudfiles-us.credential>YOUR_HEX_KEY</test.cloudfiles-us.credential>
<test.azureblob.identity>YOUR_ACCOUNT</test.azureblob.identity>
<test.azureblob.credential>YOUR_BASE64_ENCODED_KEY</test.azureblob.credential>
<test.twitter.gae-tweetstore-spring.consumer.identity>YOUR_TWITTER_CONSUMER_KEY</test.twitter.gae-tweetstore-spring.consumer.identity>
<test.twitter.gae-tweetstore-spring.consumer.credential>YOUR_TWITTER_CONSUMER_SECRET</test.twitter.gae-tweetstore-spring.consumer.credential>
<test.twitter.gae-tweetstore-spring.access.identity>YOUR_TWITTER_ACCESSTOKEN</test.twitter.gae-tweetstore-spring.access.identity>
<test.twitter.gae-tweetstore-spring.access.credential>YOUR_TWITTER_ACCESSTOKEN_SECRET</test.twitter.gae-tweetstore-spring.access.credential>
</properties>
</profile>

View File

@ -1,156 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<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-demos-tweetstore-project</artifactId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<artifactId>jclouds-demo-gae-tweetstore-spring</artifactId>
<packaging>war</packaging>
<name>jclouds TweetStore for Google App Engine (Spring)</name>
<description>JClouds TweetStore for Google App Engine using Spring for Dependency Injection</description>
<properties>
<!--
note you must set the property ${appengine.sdk.root} to a valid
extraction of appengine-java-sdk
-->
<appengine.applicationid>jclouds-tweetstore-spring</appengine.applicationid>
<appengine.sdk.version>1.6.1</appengine.sdk.version>
<devappserver.address>localhost</devappserver.address>
<devappserver.port>8088</devappserver.port>
<jclouds.tweetstore.container>jclouds-gae-tweetstore-spring</jclouds.tweetstore.container>
</properties>
<dependencies>
<dependency>
<groupId>org.jclouds.driver</groupId>
<artifactId>jclouds-gae</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.5.RELEASE</version>
<!-- using the SLF4J/commons-logging bridge -->
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
<scope>runtime</scope>
</dependency>
<!-- Google App Engine API -->
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-1.0-sdk</artifactId>
<version>${appengine.sdk.version}</version>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-tools-sdk</artifactId>
<version>${appengine.sdk.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<test.twitter.consumer.identity>${test.twitter.gae-tweetstore-spring.consumer.identity}</test.twitter.consumer.identity>
<test.twitter.consumer.credential>${test.twitter.gae-tweetstore-spring.consumer.credential}</test.twitter.consumer.credential>
<test.twitter.access.identity>${test.twitter.gae-tweetstore-spring.access.identity}</test.twitter.access.identity>
<test.twitter.access.credential>${test.twitter.gae-tweetstore-spring.access.credential}</test.twitter.access.credential>
<test.azureblob.identity>${test.azureblob.identity}</test.azureblob.identity>
<test.azureblob.credential>${test.azureblob.credential}</test.azureblob.credential>
<test.cloudfiles-us.identity>${test.cloudfiles-us.identity}</test.cloudfiles-us.identity>
<test.cloudfiles-us.credential>${test.cloudfiles-us.credential}</test.cloudfiles-us.credential>
<test.aws-s3.identity>${test.aws-s3.identity}</test.aws-s3.identity>
<test.aws-s3.credential>${test.aws-s3.credential}</test.aws-s3.credential>
<test.cloudonestorage.identity>${test.cloudonestorage.identity}</test.cloudonestorage.identity>
<test.cloudonestorage.credential>${test.cloudonestorage.credential}</test.cloudonestorage.credential>
<test.ninefold-storage.identity>${test.ninefold-storage.identity}</test.ninefold-storage.identity>
<test.ninefold-storage.credential>${test.ninefold-storage.credential}</test.ninefold-storage.credential>
<appengine.sdk.root>${appengine.sdk.root}</appengine.sdk.root>
<devappserver.address>${devappserver.address}</devappserver.address>
<devappserver.port>${devappserver.port}</devappserver.port>
<jclouds.tweetstore.blobstores>${jclouds.tweetstore.blobstores}</jclouds.tweetstore.blobstores>
<jclouds.tweetstore.container>test.${jclouds.tweetstore.container}</jclouds.tweetstore.container>
<warfile>${project.build.directory}/${project.artifactId}</warfile>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>deploy</id>
<properties>
<!-- classifier to choose the correct jclouds.properties file -->
<tweetstore.instance>gae-tweetstore-spring</tweetstore.instance>
</properties>
<build>
<plugins>
<plugin>
<groupId>net.kindleit</groupId>
<artifactId>maven-gae-plugin</artifactId>
<version>0.9.2</version>
<configuration>
<serverId>google-appengine</serverId>
<sdkDir>${appengine.sdk.root}</sdkDir>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -1,32 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config;
import static org.jclouds.logging.LoggingModules.firstOrJDKLoggingModule;
import org.jclouds.logging.Logger.LoggerFactory;
/**
* Spring config that provides a logger.
*
* @author Andrew Phillips
*/
abstract class LoggingConfig {
protected static final LoggerFactory LOGGER_FACTORY = firstOrJDKLoggingModule().createLoggerFactory();
}

View File

@ -1,241 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.in;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Sets.filter;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_BLOBSTORES;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN_SECRET;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_KEY;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_SECRET;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector;
import org.jclouds.demo.tweetstore.controller.AddTweetsController;
import org.jclouds.demo.tweetstore.controller.ClearTweetsController;
import org.jclouds.demo.tweetstore.controller.EnqueueStoresController;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.gae.config.GoogleAppEngineConfigurationModule;
import org.jclouds.logging.Logger;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.ServletConfigAware;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.io.Closeables;
import com.google.inject.Module;
/**
* Creates servlets (using resources from the {@link SpringAppConfig}) and mappings.
*
* @author Andrew Phillips
* @see SpringAppConfig
*/
@Configuration
public class SpringServletConfig extends LoggingConfig implements ServletConfigAware {
public static final String PROPERTY_BLOBSTORE_CONTEXTS = "blobstore.contexts";
private static final Logger LOGGER = LOGGER_FACTORY.getLogger(SpringServletConfig.class.getName());
private ServletConfig servletConfig;
private Map<String, BlobStoreContext> providerTypeToBlobStoreMap;
private Twitter twitterClient;
private String container;
private Queue queue;
@PostConstruct
public void initialize() throws IOException {
Properties props = loadJCloudsProperties();
LOGGER.trace("About to initialize members.");
Module googleModule = new GoogleAppEngineConfigurationModule();
Set<Module> modules = ImmutableSet.<Module> of(googleModule);
// shared across all blobstores and used to retrieve tweets
try {
twitter4j.conf.Configuration twitterConf = new ConfigurationBuilder()
.setOAuthConsumerKey(props.getProperty(PROPERTY_TWITTER_CONSUMER_KEY))
.setOAuthConsumerSecret(props.getProperty(PROPERTY_TWITTER_CONSUMER_SECRET))
.setOAuthAccessToken(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN))
.setOAuthAccessTokenSecret(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET))
.build();
twitterClient = new TwitterFactory(twitterConf).getInstance();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("properties for twitter not configured properly in " + props.toString(), e);
}
// common namespace for storing tweets
container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), PROPERTY_TWEETSTORE_CONTAINER);
// instantiate and store references to all blobstores by provider name
providerTypeToBlobStoreMap = Maps.newHashMap();
for (String hint : getBlobstoreContexts(props)) {
providerTypeToBlobStoreMap.put(hint, ContextBuilder.newBuilder(hint)
.modules(modules).overrides(props).build(BlobStoreContext.class));
}
// get a queue for submitting store tweet requests
queue = QueueFactory.getQueue("twitter");
LOGGER.trace("Members initialized. Twitter: '%s', container: '%s', provider types: '%s'", twitterClient,
container, providerTypeToBlobStoreMap.keySet());
}
private static Iterable<String> getBlobstoreContexts(Properties props) {
Set<String> contexts = new CredentialsCollector().apply(props).keySet();
String explicitContexts = props.getProperty(PROPERTY_TWEETSTORE_BLOBSTORES);
if (explicitContexts != null) {
contexts = filter(contexts, in(copyOf(Splitter.on(',').split(explicitContexts))));
}
checkState(!contexts.isEmpty(), "no credentials available for any requested context");
return contexts;
}
private Properties loadJCloudsProperties() {
LOGGER.trace("About to read properties from '%s'", "/WEB-INF/jclouds.properties");
Properties props = new Properties();
InputStream input = servletConfig.getServletContext().getResourceAsStream("/WEB-INF/jclouds.properties");
try {
props.load(input);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
Closeables.closeQuietly(input);
}
LOGGER.trace("Properties successfully read.");
return props;
}
@Bean
public StoreTweetsController storeTweetsController() {
StoreTweetsController controller = new StoreTweetsController(providerTypeToBlobStoreMap, container, twitterClient);
injectServletConfig(controller);
return controller;
}
@Bean
public AddTweetsController addTweetsController() {
AddTweetsController controller = new AddTweetsController(providerTypeToBlobStoreMap,
serviceToStoredTweetStatuses());
injectServletConfig(controller);
return controller;
}
@Bean
public EnqueueStoresController enqueueStoresController() {
return new EnqueueStoresController(providerTypeToBlobStoreMap, queue);
}
@Bean
public ClearTweetsController clearTweetsController() {
return new ClearTweetsController(providerTypeToBlobStoreMap, container);
}
private void injectServletConfig(Servlet servlet) {
LOGGER.trace("About to inject servlet config '%s'", servletConfig);
try {
servlet.init(checkNotNull(servletConfig));
} catch (ServletException exception) {
throw new BeanCreationException("Unable to instantiate " + servlet, exception);
}
LOGGER.trace("Successfully injected servlet config.");
}
@Bean
ServiceToStoredTweetStatuses serviceToStoredTweetStatuses() {
return new ServiceToStoredTweetStatuses(providerTypeToBlobStoreMap, container);
}
@Bean
public HandlerMapping handlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
Map<String, Object> urlMap = Maps.newHashMapWithExpectedSize(2);
urlMap.put("/store/*", storeTweetsController());
urlMap.put("/tweets/*", addTweetsController());
urlMap.put("/stores/*", enqueueStoresController());
urlMap.put("/clear/*", clearTweetsController());
mapping.setUrlMap(urlMap);
/*
* "/store", "/tweets" and "/stores" are part of the servlet mapping and thus
* stripped by the mapping if using default settings.
*/
mapping.setAlwaysUseFullPath(true);
return mapping;
}
@Bean
public HandlerAdapter servletHandlerAdapter() {
return new SimpleServletHandlerAdapter();
}
@PreDestroy
public void destroy() throws Exception {
LOGGER.trace("About to close contexts.");
for (BlobStoreContext context : providerTypeToBlobStoreMap.values()) {
context.close();
}
LOGGER.trace("Contexts closed.");
LOGGER.trace("About to purge request queue.");
queue.purge();
LOGGER.trace("Request queue purged.");
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.context.ServletConfigAware#setServletConfig(javax.servlet.ServletConfig
* )
*/
@Override
public void setServletConfig(ServletConfig servletConfig) {
this.servletConfig = servletConfig;
}
}

View File

@ -1,153 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Collections2.filter;
import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Maps.filterValues;
import static org.jclouds.util.Maps2.fromKeys;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector.Credential;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
/**
* Reads provider credentials from a {@link Properties} bag.
*
* @author Andrew Phillips
*
*/
public class CredentialsCollector implements Function<Properties, Map<String, Credential>> {
private static final String IDENTITY_PROPERTY_SUFFIX = ".identity";
private static final String CREDENTIAL_PROPERTY_SUFFIX = ".credential";
// using the identity for provider name extraction
private static final Pattern IDENTITY_PROPERTY_PATTERN =
Pattern.compile("([a-zA-Z0-9-]+)" + Pattern.quote(IDENTITY_PROPERTY_SUFFIX));
@Override
public Map<String, Credential> apply(final Properties properties) {
Collection<String> providerNames = transform(
filter(properties.stringPropertyNames(), MatchesPattern.matches(IDENTITY_PROPERTY_PATTERN)),
new Function<String, String>() {
@Override
public String apply(String input) {
Matcher matcher = IDENTITY_PROPERTY_PATTERN.matcher(input);
// as a side-effect, sets the matching group!
checkState(matcher.matches(), "'%s' should match '%s'", input, IDENTITY_PROPERTY_PATTERN);
return matcher.group(1);
}
});
/*
* Providers without a credential property result in null values, which are
* removed from the returned map.
*/
return filterValues(fromKeys(copyOf(providerNames), new Function<String, Credential>() {
@Override
public Credential apply(String providerName) {
String identity = properties.getProperty(providerName + IDENTITY_PROPERTY_SUFFIX);
String credential = properties.getProperty(providerName + CREDENTIAL_PROPERTY_SUFFIX);
return (((identity != null) && (credential != null))
? new Credential(identity, credential)
: null);
}
}), notNull());
}
public static class Credential {
private final String identity;
private final String credential;
public Credential(String identity, String credential) {
this.identity = checkNotNull(identity, "identity");
this.credential = checkNotNull(credential, "credential");
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((credential == null) ? 0 : credential.hashCode());
result = prime * result
+ ((identity == null) ? 0 : identity.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;
Credential other = (Credential) obj;
if (credential == null) {
if (other.credential != null)
return false;
} else if (!credential.equals(other.credential))
return false;
if (identity == null) {
if (other.identity != null)
return false;
} else if (!identity.equals(other.identity))
return false;
return true;
}
public String getIdentity() {
return identity;
}
public String getCredential() {
return credential;
}
}
@GwtIncompatible(value = "java.util.regex.Pattern")
private static class MatchesPattern implements Predicate<String> {
private final Pattern pattern;
private MatchesPattern(Pattern pattern) {
this.pattern = pattern;
}
@Override
public boolean apply(String input) {
return pattern.matcher(input).matches();
}
private static MatchesPattern matches(Pattern pattern) {
return new MatchesPattern(pattern);
}
}
}

View File

@ -1,96 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.logging.Logger;
import com.google.appengine.repackaged.com.google.common.collect.Lists;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
/**
* Shows an example of how to use @{link BlobStoreContext} injected with Guice.
*
* @author Adrian Cole
*/
@Singleton
public class AddTweetsController extends HttpServlet implements
Function<Set<String>, List<StoredTweetStatus>> {
/** The serialVersionUID */
private static final long serialVersionUID = 3888348023150822683L;
private final Map<String, BlobStoreContext> contexts;
private final ServiceToStoredTweetStatuses blobStoreContextToContainerResult;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public AddTweetsController(Map<String, BlobStoreContext> contexts,
ServiceToStoredTweetStatuses blobStoreContextToContainerResult) {
this.contexts = contexts;
this.blobStoreContextToContainerResult = blobStoreContextToContainerResult;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
addMyTweetsToRequest(request);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/tweets.jsp");
dispatcher.forward(request, response);
} catch (Exception e) {
logger.error(e, "Error listing containers");
throw new ServletException(e);
}
}
void addMyTweetsToRequest(HttpServletRequest request) throws InterruptedException,
ExecutionException, TimeoutException {
request.setAttribute("tweets", apply(contexts.keySet()));
}
public List<StoredTweetStatus> apply(Set<String> in) {
List<StoredTweetStatus> statuses = Lists.newArrayList();
for (Iterable<StoredTweetStatus> list : Iterables.transform(in,
blobStoreContextToContainerResult)) {
Iterables.addAll(statuses, list);
}
return statuses;
}
}

View File

@ -1,96 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.nullToEmpty;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
/**
* Grab tweets related to me and store them into blobstores
*
* @author Adrian Cole
*/
@Singleton
public class ClearTweetsController extends HttpServlet {
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Map<String, BlobStoreContext> contexts;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
@Inject
@VisibleForTesting
public ClearTweetsController(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container) {
this.container = container;
this.contexts = contexts;
}
@VisibleForTesting
public void clearContainer(String contextName) {
BlobStoreContext context = checkNotNull(contexts.get(contextName),
"no context for %s in %s", contextName, contexts.keySet());
try {
context.getBlobStore().clearContainer(container);
} catch (Exception e) {
logger.error(e, "Error clearing tweets in %s/%s", container, context);
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (nullToEmpty(request.getHeader("X-Originator")).equals("admin")) {
try {
String contextName = checkNotNull(request.getHeader("context"), "missing header context");
logger.info("clearing tweets in %s/%s", container, contextName);
clearContainer(contextName);
logger.debug("done clearing tweets");
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error clearing tweets");
throw new ServletException(e);
}
} else {
response.sendError(401);
}
}
}

View File

@ -1,92 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
import static com.google.appengine.repackaged.com.google.common.base.Strings.nullToEmpty;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.logging.Logger;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.common.annotations.VisibleForTesting;
/**
* Adds tasks to retrieve and store tweets in all registered contexts to an async
* task queue.
*
* @author Andrew Phillips
* @see StoreTweetsController
*/
@Singleton
public class EnqueueStoresController extends HttpServlet {
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Set<String> contextNames;
private final Queue taskQueue;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public EnqueueStoresController(Map<String, BlobStoreContext> contexts,
Queue taskQueue) {
contextNames = contexts.keySet();
this.taskQueue = taskQueue;
}
@VisibleForTesting
void enqueueStoreTweetTasks() {
for (String contextName : contextNames) {
logger.debug("enqueuing task to store tweets in blobstore '%s'", contextName);
taskQueue.add(withUrl("/store/do").header("context", contextName).method(Method.GET));
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (!nullToEmpty(request.getHeader("X-AppEngine-Cron")).equals("true")) {
response.sendError(401);
}
try {
enqueueStoreTweetTasks();
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error storing tweets");
throw new ServletException(e);
}
}
}

View File

@ -1,129 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import twitter4j.Status;
import twitter4j.Twitter;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
/**
* Grab tweets related to me and store them into blobstores
*
* @author Adrian Cole
*/
@Singleton
public class StoreTweetsController extends HttpServlet {
private static final class StatusToBlob implements Function<Status, Blob> {
private final BlobMap map;
private StatusToBlob(BlobMap map) {
this.map = map;
}
public Blob apply(Status from) {
Blob to = map.blobBuilder().name(from.getId() + "").build();
to.setPayload(from.getText());
to.getPayload().getContentMetadata().setContentType(MediaType.TEXT_PLAIN);
to.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, from.getUser().getScreenName());
return to;
}
}
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Map<String, BlobStoreContext> contexts;
private final Twitter client;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
@Inject
@VisibleForTesting
public StoreTweetsController(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container, Twitter client) {
this.container = container;
this.contexts = contexts;
this.client = client;
}
@VisibleForTesting
public void addMyTweets(String contextName, Iterable<Status> responseList) {
BlobStoreContext context = checkNotNull(contexts.get(contextName), "no context for " + contextName + " in "
+ contexts.keySet());
BlobMap map = context.createBlobMap(container);
for (Status status : responseList) {
Blob blob = null;
try {
blob = new StatusToBlob(map).apply(status);
map.put(status.getId() + "", blob);
} catch (AuthorizationException e) {
throw e;
} catch (Exception e) {
logger.error(e, "Error storing tweet %s (blob[%s]) on map %s/%s", status.getId(), blob, context, container);
}
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (request.getHeader("X-AppEngine-QueueName") != null
&& request.getHeader("X-AppEngine-QueueName").equals("twitter")) {
try {
String contextName = checkNotNull(request.getHeader("context"), "missing header context");
logger.info("retrieving tweets");
addMyTweets(contextName, client.getMentions());
logger.debug("done storing tweets");
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error storing tweets");
throw new ServletException(e);
}
} else {
response.sendError(401);
}
}
}

View File

@ -1,149 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.domain;
import java.io.Serializable;
/**
*
* @author Adrian Cole
*/
public class StoredTweetStatus implements Comparable<StoredTweetStatus>, Serializable {
/** The serialVersionUID */
private static final long serialVersionUID = -3257496189689220018L;
private final String service;
private final String host;
private final String container;
private final String id;
private final String from;
private final String tweet;
private final String status;
@Override
public String toString() {
return "StoredTweetStatus [container=" + container + ", from=" + from + ", host=" + host
+ ", id=" + id + ", service=" + service + ", status=" + status + ", tweet=" + tweet
+ "]";
}
public StoredTweetStatus(String service, String host, String container, String id, String from,
String tweet, String status) {
this.service = service;
this.host = host;
this.container = container;
this.id = id;
this.from = from;
this.tweet = tweet;
this.status = status;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((container == null) ? 0 : container.hashCode());
result = prime * result + ((from == null) ? 0 : from.hashCode());
result = prime * result + ((host == null) ? 0 : host.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((service == null) ? 0 : service.hashCode());
result = prime * result + ((tweet == null) ? 0 : tweet.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;
StoredTweetStatus other = (StoredTweetStatus) obj;
if (container == null) {
if (other.container != null)
return false;
} else if (!container.equals(other.container))
return false;
if (from == null) {
if (other.from != null)
return false;
} else if (!from.equals(other.from))
return false;
if (host == null) {
if (other.host != null)
return false;
} else if (!host.equals(other.host))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (service == null) {
if (other.service != null)
return false;
} else if (!service.equals(other.service))
return false;
if (tweet == null) {
if (other.tweet != null)
return false;
} else if (!tweet.equals(other.tweet))
return false;
return true;
}
public String getService() {
return service;
}
public String getHost() {
return host;
}
public String getContainer() {
return container;
}
public String getFrom() {
return from;
}
public String getTweet() {
return tweet;
}
public String getStatus() {
return status;
}
public int compareTo(StoredTweetStatus o) {
if (id == null)
return -1;
return (int) ((this == o) ? 0 : id.compareTo(o.id));
}
public String getId() {
return id;
}
}

View File

@ -1,70 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import javax.annotation.Resource;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import org.jclouds.util.Strings2;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
public class KeyToStoredTweetStatus implements Function<String, StoredTweetStatus> {
private final String host;
private final BlobMap map;
private final String service;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
KeyToStoredTweetStatus(BlobMap map, String service, String host, String container) {
this.host = host;
this.map = map;
this.service = service;
this.container = container;
}
public StoredTweetStatus apply(String id) {
String status;
String from;
String tweet;
try {
long start = System.currentTimeMillis();
Blob blob = map.get(id);
status = ((System.currentTimeMillis() - start) + "ms");
from = blob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME);
tweet = Strings2.toString(blob.getPayload());
} catch (Exception e) {
logger.error(e, "Error listing container %s//%s/%s", service, container, id);
status = (e.getMessage());
tweet = "";
from = "";
}
return new StoredTweetStatus(service, host, container, id, from, tweet, status);
}
}

View File

@ -1,72 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Context;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
@Singleton
public class ServiceToStoredTweetStatuses implements Function<String, Iterable<StoredTweetStatus>> {
private final Map<String, BlobStoreContext> contexts;
private final String container;
@Inject
public ServiceToStoredTweetStatuses(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container) {
this.contexts = contexts;
this.container = container;
}
@Resource
protected Logger logger = Logger.NULL;
public Iterable<StoredTweetStatus> apply(String service) {
BlobStoreContext context = contexts.get(service);
String host = URI.create(context.unwrap(Context.class).getProviderMetadata().getEndpoint()).getHost();
try {
BlobMap blobMap = context.createBlobMap(container);
Set<String> blobs = blobMap.keySet();
return Iterables.transform(blobs, new KeyToStoredTweetStatus(blobMap, service, host,
container));
} catch (Exception e) {
StoredTweetStatus result = new StoredTweetStatus(service, host, container, null, null,
null, e.getMessage());
logger.error(e, "Error listing service %s", service);
return ImmutableList.of(result);
}
}
}

View File

@ -1,34 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.reference;
/**
* Configuration properties and constants used in TweetStore connections.
*
* @author Adrian Cole
*/
public interface TweetStoreConstants {
static final String PROPERTY_TWEETSTORE_BLOBSTORES = "jclouds.tweetstore.blobstores";
static final String PROPERTY_TWEETSTORE_CONTAINER = "jclouds.tweetstore.container";
/**
* Note that this has to conform to restrictions of all blobstores. for
* example, azure doesn't support periods.
*/
static final String SENDER_NAME = "sendername";
}

View File

@ -1,31 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.reference;
/**
* Configuration properties and constants used in Twitter connections.
*
* @author Andrew Phillips
*/
public interface TwitterConstants {
static final String PROPERTY_TWITTER_CONSUMER_KEY = "twitter.consumer.identity";
static final String PROPERTY_TWITTER_CONSUMER_SECRET = "twitter.consumer.credential";
static final String PROPERTY_TWITTER_ACCESSTOKEN = "twitter.access.identity";
static final String PROPERTY_TWITTER_ACCESSTOKEN_SECRET = "twitter.access.credential";
}

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>${appengine.applicationid}</application>
<version>1</version>
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
</system-properties>
</appengine-web-app>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<cronentries>
<cron>
<url>/stores/do</url>
<description>Enqueue 'store tweet' tasks for all contexts</description>
<schedule>every 10 minutes</schedule>
</cron>
</cronentries>

View File

@ -1,50 +0,0 @@
#
# Licensed to jclouds, Inc. (jclouds) under one or more
# contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. jclouds 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.
#
# A default java.util.logging configuration.
# (All App Engine logging is through java.util.logging by default).
#
# To use this configuration, copy it into your application's WEB-INF
# folder and add the following to your appengine-web.xml:
#
# <system-properties>
# <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
# </system-properties>
#
# Set the default logging level for all loggers to INFO
.level = INFO
org.jclouds.level=INFO
org.jclouds.demo.tweetstore.config.level=FINEST
# Set the default logging level for ORM, specifically, to WARNING
DataNucleus.JDO.level=WARNING
DataNucleus.Persistence.level=WARNING
DataNucleus.Cache.level=WARNING
DataNucleus.MetaData.level=WARNING
DataNucleus.General.level=WARNING
DataNucleus.Utility.level=WARNING
DataNucleus.Transaction.level=WARNING
DataNucleus.Datastore.level=WARNING
DataNucleus.ClassLoading.level=WARNING
DataNucleus.Plugin.level=WARNING
DataNucleus.ValueGeneration.level=WARNING
DataNucleus.Enhancer.level=WARNING
DataNucleus.SchemaTool.level=WARNING

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- the usual <context:annotation-config/> can't be used because the
CommonAnnotationBeanPostProcessor causes a security exception in GAE when it
tries to load javax.annotation.Resource -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.context.annotation.ConfigurationClassPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor">
<property name="initAnnotationType" value="javax.annotation.PostConstruct" />
<property name="destroyAnnotationType" value="javax.annotation.PreDestroy" />
</bean>
<bean class="org.jclouds.demo.tweetstore.config.SpringServletConfig" />
</beans>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<queue-entries>
<queue>
<name>twitter</name>
<!-- poll every 30s, but only allow one request at a time to save CPU -->
<rate>2/m</rate>
<max-concurrent-requests>1</max-concurrent-requests>
</queue>
</queue-entries>

View File

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
version="2.5">
<display-name>jclouds-tweetstore-spring</display-name>
<!-- Servlets -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- cannot use the AnnotationConfigWebApplicationContext as it causes a security
exception in GAE by trying to load javax.annotation.Resource -->
</servlet>
<!-- should be kept in sync with the mappings defined in SpringServletConfig -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/store/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/tweets/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/stores/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/clear/*</url-pattern>
</servlet-mapping>
<!-- limit submission of storage tasks to the cron job -->
<security-constraint>
<web-resource-collection>
<url-pattern>/stores/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

View File

@ -1,31 +0,0 @@
<%--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
--%>
<html>
<head>
<title>jclouds: anyweight cloudware for java</title>
</head>
<body>
<h2>Welcome!</h2>
<p>Click <a href="/tweets/get">here</a> to see tweets about jclouds.</p>
<p><img src="http://code.google.com/appengine/images/appengine-noborder-120x30.gif"
alt="Powered by Google App Engine" /></p>
</body>
</html>

View File

@ -1,109 +0,0 @@
<%--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
--%>
<%@ page buffer="20kb"%>
<%@ taglib uri="http://displaytag.sf.net" prefix="display"%>
<html>
<head>
<title>jclouds: anyweight cloudware for java</title>
<style type="text/css">
<!--
table.staticheader {
text-decoration: none;
border: 1px solid #CCC;
width: 98%;
}
table.staticheader th {
padding: 3px 3px 3px 3px !important;
text-align:center;
}
table.staticheader td {
padding: 3px 3px 3px 3px !important;
}
table.staticheader thead tr {
position: relative;
height: 10px;
background-color: #D7E5F3;
}
table.staticheader tbody {
height:800px;
overflow-x:hidden;
overflow-y: auto;
overflow:scroll;
}
table.staticheader tbody tr {
height: auto;
white-space: nowrap;
}
table.staticheader tbody tr.odd {
background-color: #eee
}
table.staticheader tbody tr.tableRowEven,tr.even {
background-color: #ddd
}
table.staticheader tbody tr td:last-child {
padding-right: 20px;
}
table.staticheader tbody td {
padding: 2px 4px 2px 4px !important;
}
div.TableContainer {
height: 800px;
overflow-x:hidden;
overflow-y:auto;
}
-->
</style>
</head>
<body>
<h2>Tweets in Clouds</h2>
<table width="100%" border="0">
<tr>
<td>
<div class="TableContainer">
<display:table name="tweets" defaultsort="1" cellpadding="5" cellspacing="1" class="staticheader">
<display:column property="id" title="Tweet ID" />
<display:column property="from" title="Who Said it" />
<display:column property="tweet" title="Tweet" />
<display:column property="service" title="Cloud" />
<display:column property="host" title="Host" />
<display:column property="status" title="Status" />
</display:table>
</div>
</td>
</tr>
<tr>
<td><img src="http://code.google.com/appengine/images/appengine-noborder-120x30.gif"
alt="Powered by Google App Engine" /></td>
</tr>
</table>
</body>
</html>

View File

@ -1,82 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config.util;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Map;
import java.util.Properties;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector.Credential;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@code CredentialsCollector}
*
* @author Andrew Phillips
*/
@Test(groups = "unit")
public class CredentialsCollectorTest {
private CredentialsCollector collector = new CredentialsCollector();
public void testEmptyProperties() {
assertTrue(collector.apply(new Properties()).isEmpty(),
"Expected returned map to be empty");
}
public void testNoCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("not-an-identity",
"v1", "not-a-credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
private static Properties propertiesOf(Map<String, String> entries) {
Properties properties = new Properties();
properties.putAll(entries);
return properties;
}
public void testNonMatchingCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("non_matching.identity", "v1",
"non_matching.credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
public void testIncompleteCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("acme.identity", "v1",
"acme-2.credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
public void testCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("acme.identity", "v1",
"acme.credential", "v2", "acme-2.identity", "v3",
"acme-2.credential", "v4"));
assertEquals(collector.apply(properties),
ImmutableMap.of("acme", new Credential("v1", "v2"),
"acme-2", new Credential("v3", "v4")));
}
}

View File

@ -1,78 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
import org.testng.collections.Maps;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code AddTweetsController}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class AddTweetsControllerTest {
Map<String, BlobStoreContext> createServices(String container) throws InterruptedException,
ExecutionException {
Map<String, BlobStoreContext> services = Maps.newHashMap();
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
for (String name : new String[] { "1", "2" }) {
BlobStoreContext context = ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class);
context.getAsyncBlobStore().createContainerInLocation(null, container).get();
Blob blob = context.getAsyncBlobStore().blobBuilder("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
context.getAsyncBlobStore().putBlob(container, blob).get();
services.put(name, context);
}
return services;
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
String container = "container";
Map<String, BlobStoreContext> contexts = createServices(container);
ServiceToStoredTweetStatuses function = new ServiceToStoredTweetStatuses(contexts, container);
AddTweetsController controller = new AddTweetsController(contexts, function);
List<StoredTweetStatus> list = controller.apply(ImmutableSet.of("1", "2"));
assertEquals(list.size(), 2);
assertEquals(list, ImmutableList.of(new StoredTweetStatus("1", "localhost", container, "1",
"frank", "I love beans!", null), new StoredTweetStatus("2", "localhost", container,
"1", "frank", "I love beans!", null)));
}
}

View File

@ -1,72 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@code AddTweetsController}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ClearTweetsControllerTest {
Map<String, BlobStoreContext> createBlobStores(String container) throws InterruptedException, ExecutionException {
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext>of(
"test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class),
"test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class));
for (BlobStoreContext blobstore : contexts.values()) {
blobstore.getBlobStore().createContainerInLocation(null, container);
Blob blob = blobstore.getAsyncBlobStore().blobBuilder("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
blobstore.getBlobStore().putBlob(container, blob);
}
return contexts;
}
public void testClearTweets() throws IOException, InterruptedException, ExecutionException {
String container = ClearTweetsControllerTest.class.getName() + "#container";
Map<String, BlobStoreContext> contexts = createBlobStores(container);
ClearTweetsController controller = new ClearTweetsController(contexts,
container);
controller.clearContainer("test1");
controller.clearContainer("test2");
for (BlobStoreContext context : contexts.values()) {
assertEquals(context.getBlobStore().countBlobs(container), 0, context.toString());
}
}
}

View File

@ -1,67 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.util.Map;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.testng.annotations.Test;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@link EnqueueStoresController}
*
* @author Andrew Phillips
*/
@Test(groups = "unit")
public class EnqueueStoresControllerTest {
Map<String, BlobStoreContext> createBlobStores() {
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext>of(
"test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class),
"test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class));
return contexts;
}
public void testEnqueueStores() {
Map<String, BlobStoreContext> stores = createBlobStores();
Queue taskQueue = createMock(Queue.class);
EnqueueStoresController function = new EnqueueStoresController(stores, taskQueue);
expect(taskQueue.add(withUrl("/store/do").header("context", "test1").method(Method.GET))).andReturn(null);
expect(taskQueue.add(withUrl("/store/do").header("context", "test2").method(Method.GET))).andReturn(null);
replay(taskQueue);
function.enqueueStoreTweetTasks();
verify(taskQueue);
}
}

View File

@ -1,120 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.util.Strings2;
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;
/**
* Tests behavior of {@code StoreTweetsController}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class StoreTweetsControllerTest {
Twitter createTwitter() {
return createMock(Twitter.class);
}
Map<String, BlobStoreContext> createBlobStores() throws InterruptedException, ExecutionException {
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext>of(
"test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class),
"test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class));
for (BlobStoreContext blobstore : contexts.values()) {
blobstore.getAsyncBlobStore().createContainerInLocation(null, "favo").get();
}
return contexts;
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
Map<String, BlobStoreContext> stores = createBlobStores();
StoreTweetsController function = new StoreTweetsController(stores, "favo", createTwitter());
User frank = createMock(User.class);
expect(frank.getScreenName()).andReturn("frank").atLeastOnce();
Status frankStatus = createMock(Status.class);
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();
Status jimmyStatus = createMock(Status.class);
expect(jimmyStatus.getId()).andReturn(2l).atLeastOnce();
expect(jimmyStatus.getUser()).andReturn(jimmy).atLeastOnce();
expect(jimmyStatus.getText()).andReturn("cloud is king").atLeastOnce();
replay(frank);
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()) {
BlobMap map = entry.getValue().createBlobMap("favo");
Blob frankBlob = map.get("1");
assertEquals(frankBlob.getMetadata().getName(), "1");
assertEquals(frankBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "frank");
assertEquals(frankBlob.getMetadata().getContentMetadata().getContentType(), "text/plain");
assertEquals(Strings2.toString(frankBlob.getPayload()), "I love beans!");
Blob jimmyBlob = map.get("2");
assertEquals(jimmyBlob.getMetadata().getName(), "2");
assertEquals(jimmyBlob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME), "jimmy");
assertEquals(jimmyBlob.getMetadata().getContentMetadata().getContentType(), "text/plain");
assertEquals(Strings2.toString(jimmyBlob.getPayload()), "cloud is king");
}
}
}

View File

@ -1,69 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code KeyToStoredTweetStatus}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class KeyToStoredTweetStatusTest {
BlobMap createMap() throws InterruptedException, ExecutionException {
BlobStoreContext context =
ContextBuilder.newBuilder(TransientApiMetadata.builder().build()).build(BlobStoreContext.class);
context.getBlobStore().createContainerInLocation(null, "test1");
return context.createBlobMap("test1");
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
BlobMap map = createMap();
Blob blob = map.blobBuilder().name("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
map.put("1", blob);
String host = "localhost";
String service = "stub";
String container = "tweetstore";
KeyToStoredTweetStatus function = new KeyToStoredTweetStatus(map, service, host, container);
StoredTweetStatus result = function.apply("1");
StoredTweetStatus expected = new StoredTweetStatus(service, host, container, "1", "frank",
"I love beans!", null);
assertEquals(result, expected);
}
}

View File

@ -1,75 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
import org.testng.collections.Maps;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code ServiceToStoredTweetStatuses}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ServiceToStoredTweetStatusesTest {
Map<String, BlobStoreContext> createServices(String container) throws InterruptedException,
ExecutionException {
Map<String, BlobStoreContext> services = Maps.newHashMap();
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
for (String name : new String[] { "1", "2" }) {
BlobStoreContext context = ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class);
context.getAsyncBlobStore().createContainerInLocation(null, container).get();
Blob blob = context.getAsyncBlobStore().blobBuilder("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
context.getAsyncBlobStore().putBlob(container, blob).get();
services.put(name, context);
}
return services;
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
String container = "container";
Map<String, BlobStoreContext> contexts = createServices(container);
ServiceToStoredTweetStatuses function = new ServiceToStoredTweetStatuses(contexts, container);
assertEquals(Iterables.getLast(function.apply("1")), new StoredTweetStatus("1", "localhost",
container, "1", "frank", "I love beans!", null));
assertEquals(Iterables.getLast(function.apply("2")), new StoredTweetStatus("2", "localhost",
container, "1", "frank", "I love beans!", null));
}
}

View File

@ -1,87 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.integration;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.Closeables.closeQuietly;
import static java.lang.String.format;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import com.google.appengine.tools.KickStart;
import com.google.appengine.tools.info.SdkInfo;
/**
* Basic functionality to start a local google app engine instance.
*
* @author Adrian Cole
*/
public class GoogleDevServer {
Thread server;
public void writePropertiesAndStartServer(final String address,
final String port, final String warfile, Properties props)
throws IOException, InterruptedException {
String filename = String.format(
"%1$s/WEB-INF/jclouds.properties", warfile);
System.err.println("file: " + filename);
storeProperties(filename, props);
assert new File(filename).exists();
this.server = new Thread(new Runnable() {
public void run() {
String sdkRoot = checkNotNull(System.getProperty(SdkInfo.SDK_ROOT_PROPERTY), SdkInfo.SDK_ROOT_PROPERTY);
KickStart.main(new String[] {
KickStarter.systemProperty("java.util.logging.config.file",
format("%s/WEB-INF/logging.properties", warfile)),
KickStarter.systemProperty(SdkInfo.SDK_ROOT_PROPERTY, sdkRoot),
"com.google.appengine.tools.development.DevAppServerMain",
"--disable_update_check",
format("--sdk_root=%s", sdkRoot),
"-a", address, "-p", port, warfile });
}
});
server.start();
TimeUnit.SECONDS.sleep(30);
}
private static void storeProperties(String filename, Properties props) throws IOException {
FileOutputStream targetFile = new FileOutputStream(filename);
try {
props.store(targetFile, "test");
} finally {
closeQuietly(targetFile);
}
}
public void stop() throws Exception {
// KickStart.main opens a process and calls process.waitFor(), which is interruptable
server.interrupt();
}
private static class KickStarter {
private static String systemProperty(String key, String value) {
return format("--jvm_flag=-D%s=%s", key, value);
}
}
}

View File

@ -1,234 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.integration;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_BLOBSTORES;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN_SECRET;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_KEY;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_SECRET;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.Context;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.config.SpringServletConfig;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.util.Strings2;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.inject.Module;
/**
* Starts up the Google App Engine for Java Development environment and deploys an application which
* tests accesses twitter and blobstores.
*
* @author Adrian Cole
*/
@Test(groups = "live", singleThreaded = true)
public class TweetStoreLiveTest {
GoogleDevServer server;
private URL url;
private Map<String, BlobStoreContext> contexts;
private String container;
private static final Iterable<String> blobstores =
Splitter.on(',').split(System.getProperty(PROPERTY_TWEETSTORE_BLOBSTORES,
"cloudfiles-us,aws-s3,azureblob"));
private static final Properties props = new Properties();
@BeforeTest
void clearAndCreateContainers() throws InterruptedException, ExecutionException, TimeoutException, IOException,
TwitterException {
container = getRequiredSystemProperty(PROPERTY_TWEETSTORE_CONTAINER);
props.setProperty(PROPERTY_TWEETSTORE_CONTAINER, container);
props.setProperty(SpringServletConfig.PROPERTY_BLOBSTORE_CONTEXTS, Joiner.on(',').join(blobstores));
// put all identity/credential pairs into the client
addCredentialsForBlobStores(props);
// example of an ad-hoc client configuration
addConfigurationForTwitter(props);
// for testing, capture logs.
final Set<Module> wiring = ImmutableSet.<Module> of(new Log4JLoggingModule());
this.contexts = Maps.newConcurrentMap();
for (String provider : blobstores) {
contexts.put(provider, ContextBuilder.newBuilder(provider)
.modules(wiring).overrides(props).build(BlobStoreContext.class));
}
Configuration conf = new ConfigurationBuilder()
.setOAuthConsumerKey(props.getProperty(PROPERTY_TWITTER_CONSUMER_KEY))
.setOAuthConsumerSecret(props.getProperty(PROPERTY_TWITTER_CONSUMER_SECRET))
.setOAuthAccessToken(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN))
.setOAuthAccessTokenSecret(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET))
.build();
Twitter client = new TwitterFactory(conf).getInstance();
StoreTweetsController controller = new StoreTweetsController(contexts, container, client);
ResponseList<Status> statuses = client.getMentions();
boolean deleted = false;
for (BlobStoreContext context : contexts.values()) {
if (context.getBlobStore().containerExists(container)) {
System.err.printf("deleting container %s at %s%n", container,
context.unwrap(Context.class).getProviderMetadata().getEndpoint());
context.getBlobStore().deleteContainer(container);
deleted = true;
}
}
if (deleted) {
System.err.println("sleeping 60 seconds to allow containers to clear");
Thread.sleep(60000);
}
for (BlobStoreContext context : contexts.values()) {
System.err.printf("creating container %s at %s%n", container,
context.unwrap(Context.class).getProviderMetadata().getEndpoint());
context.getBlobStore().createContainerInLocation(null, container);
}
if (deleted) {
System.err.println("sleeping 5 seconds to allow containers to create");
Thread.sleep(5000);
}
for (Entry<String, BlobStoreContext> entry : contexts.entrySet()) {
System.err.printf("filling container %s at %s%n", container, entry.getKey());
controller.addMyTweets(entry.getKey(), statuses);
}
}
private static String getRequiredSystemProperty(String key) {
return checkNotNull(System.getProperty(key), key);
}
private void addConfigurationForTwitter(Properties props) {
props.setProperty(PROPERTY_TWITTER_CONSUMER_KEY,
getRequiredSystemProperty("test." + PROPERTY_TWITTER_CONSUMER_KEY));
props.setProperty(PROPERTY_TWITTER_CONSUMER_SECRET,
getRequiredSystemProperty("test." + PROPERTY_TWITTER_CONSUMER_SECRET));
props.setProperty(PROPERTY_TWITTER_ACCESSTOKEN,
getRequiredSystemProperty("test." + PROPERTY_TWITTER_ACCESSTOKEN));
props.setProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET,
getRequiredSystemProperty("test." + PROPERTY_TWITTER_ACCESSTOKEN_SECRET));
}
private void addCredentialsForBlobStores(Properties props) {
for (String provider : blobstores) {
props.setProperty(provider + ".identity",
getRequiredSystemProperty("test." + provider + ".identity"));
props.setProperty(provider + ".credential",
getRequiredSystemProperty("test." + provider + ".credential"));
}
}
@BeforeTest
@Parameters({ "warfile", "devappserver.address", "devappserver.port" })
public void startDevAppServer(final String warfile, final String address, final String port) throws Exception {
url = new URL(String.format("http://%s:%s", address, port));
server = new GoogleDevServer();
server.writePropertiesAndStartServer(address, port, warfile, props);
}
@Test
public void shouldPass() throws InterruptedException, IOException {
InputStream i = url.openStream();
String string = Strings2.toStringAndClose(i);
assert string.indexOf("Welcome") >= 0 : string;
}
@Test(dependsOnMethods = "shouldPass", expectedExceptions = IOException.class)
public void shouldFail() throws InterruptedException, IOException {
new URL(url, "/store/do").openStream();
}
@Test(dependsOnMethods = "shouldFail")
public void testPrimeContainers() throws IOException, InterruptedException {
URL gurl = new URL(url, "/store/do");
// WATCH THIS, you need to add a context each time
for (String context : blobstores) {
System.out.println("storing at context: " + context);
HttpURLConnection connection = (HttpURLConnection) gurl.openConnection();
connection.addRequestProperty("X-AppEngine-QueueName", "twitter");
connection.addRequestProperty("context", context);
InputStream i = connection.getInputStream();
String string = Strings2.toStringAndClose(i);
assert string.indexOf("Done!") >= 0 : string;
connection.disconnect();
}
System.err.println("sleeping 20 seconds to allow for eventual consistency delay");
Thread.sleep(20000);
for (BlobStoreContext context : contexts.values()) {
assert context.createInputStreamMap(container).size() > 0 : context.unwrap(Context.class).getProviderMetadata().getEndpoint();
}
}
@Test(invocationCount = 5, dependsOnMethods = "testPrimeContainers")
public void testSerial() throws InterruptedException, IOException {
URL gurl = new URL(url, "/tweets/get");
InputStream i = gurl.openStream();
String string = Strings2.toStringAndClose(i);
assert string.indexOf("Tweets in Clouds") >= 0 : string;
}
@Test(invocationCount = 10, dependsOnMethods = "testPrimeContainers", threadPoolSize = 3)
public void testParallel() throws InterruptedException, IOException {
URL gurl = new URL(url, "/tweets/get");
InputStream i = gurl.openStream();
String string = Strings2.toStringAndClose(i);
assert string.indexOf("Tweets in Clouds") >= 0 : string;
}
@AfterTest
public void stopDevAppServer() throws Exception {
server.stop();
}
}

View File

@ -1,95 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<!--
<category name="jclouds.wire"> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> </category> <category
name="jclouds.signature"> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> </category>
-->
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -1,56 +0,0 @@
====
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
====
A guide to generating Twitter consumer keys and access tokens is at http://tinyurl.com/2fhebgb
This sample uses the Google App Engine for Java SDK located at
http://code.google.com/p/googleappengine/downloads/list
Please unzip the above file and modify your maven settings.xml like below before
attempting to run 'mvn -Plive install'
<profile>
<id>appengine</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<appengine.sdk.root>/path/to/appengine-java-sdk-1.4.2</appengine.home>
<appengine.applicationid>yourappid</appengine.applicationid>
</properties>
</profile>
<profile>
<id>keys</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<test.aws-s3.identity>YOUR_ACCESS_KEY_ID</test.aws-s3.identity>
<test.aws-s3.credential>YOUR_SECRET_KEY</test.aws-s3.credential>
<test.cloudfiles-us.identity>YOUR_USER</test.cloudfiles-us.identity>
<test.cloudfiles-us.credential>YOUR_HEX_KEY</test.cloudfiles-us.credential>
<test.azureblob.identity>YOUR_ACCOUNT</test.azureblob.identity>
<test.azureblob.credential>YOUR_BASE64_ENCODED_KEY</test.azureblob.credential>
<test.twitter.gae-tweetstore.consumer.identity>YOUR_TWITTER_CONSUMER_KEY</test.twitter.gae-tweetstore.consumer.identity>
<test.twitter.gae-tweetstore.consumer.credential>YOUR_TWITTER_CONSUMER_SECRET</test.twitter.gae-tweetstore.consumer.credential>
<test.twitter.gae-tweetstore.access.identity>YOUR_TWITTER_ACCESSTOKEN</test.twitter.gae-tweetstore.access.identity>
<test.twitter.gae-tweetstore.access.credential>YOUR_TWITTER_ACCESSTOKEN_SECRET</test.twitter.gae-tweetstore.access.credential>
</properties>
</profile>

View File

@ -1,138 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<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-demos-tweetstore-project</artifactId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<artifactId>jclouds-demo-gae-tweetstore</artifactId>
<packaging>war</packaging>
<name>jclouds TweetStore for Google App Engine</name>
<description>jclouds TweetStore for Google App Engine using Guice for Dependency Injection</description>
<properties>
<!--
note you must set the property ${appengine.sdk.root} to a valid
extraction of appengine-java-sdk
-->
<appengine.applicationid>jclouds-tweetstore</appengine.applicationid>
<appengine.sdk.version>1.6.1</appengine.sdk.version>
<devappserver.address>localhost</devappserver.address>
<devappserver.port>8088</devappserver.port>
<jclouds.tweetstore.container>jclouds-gae-tweetstore</jclouds.tweetstore.container>
</properties>
<dependencies>
<dependency>
<groupId>org.jclouds.driver</groupId>
<artifactId>jclouds-gae</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
<version>3.0</version>
</dependency>
<!-- Google App Engine API -->
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-1.0-sdk</artifactId>
<version>${appengine.sdk.version}</version>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-tools-sdk</artifactId>
<version>${appengine.sdk.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<test.twitter.consumer.identity>${test.twitter.gae-tweetstore.consumer.identity}</test.twitter.consumer.identity>
<test.twitter.consumer.credential>${test.twitter.gae-tweetstore.consumer.credential}</test.twitter.consumer.credential>
<test.twitter.access.identity>${test.twitter.gae-tweetstore.access.identity}</test.twitter.access.identity>
<test.twitter.access.credential>${test.twitter.gae-tweetstore.access.credential}</test.twitter.access.credential>
<test.azureblob.identity>${test.azureblob.identity}</test.azureblob.identity>
<test.azureblob.credential>${test.azureblob.credential}</test.azureblob.credential>
<test.cloudfiles-us.identity>${test.cloudfiles-us.identity}</test.cloudfiles-us.identity>
<test.cloudfiles-us.credential>${test.cloudfiles-us.credential}</test.cloudfiles-us.credential>
<test.aws-s3.identity>${test.aws-s3.identity}</test.aws-s3.identity>
<test.aws-s3.credential>${test.aws-s3.credential}</test.aws-s3.credential>
<appengine.sdk.root>${appengine.sdk.root}</appengine.sdk.root>
<test.cloudonestorage.identity>${test.cloudonestorage.identity}</test.cloudonestorage.identity>
<test.cloudonestorage.credential>${test.cloudonestorage.credential}</test.cloudonestorage.credential>
<test.ninefold-storage.identity>${test.ninefold-storage.identity}</test.ninefold-storage.identity>
<test.ninefold-storage.credential>${test.ninefold-storage.credential}</test.ninefold-storage.credential>
<devappserver.address>${devappserver.address}</devappserver.address>
<devappserver.port>${devappserver.port}</devappserver.port>
<jclouds.tweetstore.blobstores>${jclouds.tweetstore.blobstores}</jclouds.tweetstore.blobstores>
<jclouds.tweetstore.container>test.${jclouds.tweetstore.container}</jclouds.tweetstore.container>
<warfile>${project.build.directory}/${project.artifactId}</warfile>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>deploy</id>
<properties>
<!-- classifier to choose the correct jclouds.properties file -->
<tweetstore.instance>gae-tweetstore</tweetstore.instance>
</properties>
<build>
<plugins>
<plugin>
<groupId>net.kindleit</groupId>
<artifactId>maven-gae-plugin</artifactId>
<version>0.9.2</version>
<configuration>
<serverId>google-appengine</serverId>
<sdkDir>${appengine.sdk.root}</sdkDir>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -1,165 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.in;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Sets.filter;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_BLOBSTORES;
import static org.jclouds.demo.tweetstore.reference.TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_ACCESSTOKEN_SECRET;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_KEY;
import static org.jclouds.demo.tweetstore.reference.TwitterConstants.PROPERTY_TWITTER_CONSUMER_SECRET;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.servlet.ServletContextEvent;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector;
import org.jclouds.demo.tweetstore.controller.AddTweetsController;
import org.jclouds.demo.tweetstore.controller.ClearTweetsController;
import org.jclouds.demo.tweetstore.controller.EnqueueStoresController;
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
import org.jclouds.gae.config.GoogleAppEngineConfigurationModule;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.repackaged.com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.io.Closeables;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
import com.google.inject.servlet.GuiceServletContextListener;
import com.google.inject.servlet.ServletModule;
/**
* Setup Logging and create Injector for use in testing S3.
*
* @author Adrian Cole
*/
public class GuiceServletConfig extends GuiceServletContextListener {
public static final String PROPERTY_BLOBSTORE_CONTEXTS = "blobstore.contexts";
private Map<String, BlobStoreContext> providerTypeToBlobStoreMap;
private Twitter twitterClient;
private String container;
private Queue queue;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
Properties props = loadJCloudsProperties(servletContextEvent);
Module googleModule = new GoogleAppEngineConfigurationModule();
Set<Module> modules = ImmutableSet.<Module> of(googleModule);
// shared across all blobstores and used to retrieve tweets
try {
Configuration twitterConf = new ConfigurationBuilder()
.setOAuthConsumerKey(props.getProperty(PROPERTY_TWITTER_CONSUMER_KEY))
.setOAuthConsumerSecret(props.getProperty(PROPERTY_TWITTER_CONSUMER_SECRET))
.setOAuthAccessToken(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN))
.setOAuthAccessTokenSecret(props.getProperty(PROPERTY_TWITTER_ACCESSTOKEN_SECRET))
.build();
twitterClient = new TwitterFactory(twitterConf).getInstance();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("properties for twitter not configured properly in " + props.toString(), e);
}
// common namespace for storing tweets
container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), PROPERTY_TWEETSTORE_CONTAINER);
// instantiate and store references to all blobstores by provider name
providerTypeToBlobStoreMap = Maps.newHashMap();
for (String hint : getBlobstoreContexts(props)) {
providerTypeToBlobStoreMap.put(hint, ContextBuilder.newBuilder(hint)
.modules(modules).overrides(props).build(BlobStoreContext.class));
}
// get a queue for submitting store tweet requests
queue = QueueFactory.getQueue("twitter");
super.contextInitialized(servletContextEvent);
}
private static Iterable<String> getBlobstoreContexts(Properties props) {
Set<String> contexts = new CredentialsCollector().apply(props).keySet();
String explicitContexts = props.getProperty(PROPERTY_TWEETSTORE_BLOBSTORES);
if (explicitContexts != null) {
contexts = filter(contexts, in(copyOf(Splitter.on(',').split(explicitContexts))));
}
checkState(!contexts.isEmpty(), "no credentials available for any requested context");
return contexts;
}
private Properties loadJCloudsProperties(ServletContextEvent servletContextEvent) {
InputStream input = servletContextEvent.getServletContext().getResourceAsStream("/WEB-INF/jclouds.properties");
Properties props = new Properties();
try {
props.load(input);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
Closeables.closeQuietly(input);
}
return props;
}
@Override
protected Injector getInjector() {
return Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(new TypeLiteral<Map<String, BlobStoreContext>>() {
}).toInstance(providerTypeToBlobStoreMap);
bind(Twitter.class).toInstance(twitterClient);
bind(Queue.class).toInstance(queue);
bindConstant().annotatedWith(Names.named(PROPERTY_TWEETSTORE_CONTAINER)).to(container);
serve("/store/*").with(StoreTweetsController.class);
serve("/tweets/*").with(AddTweetsController.class);
serve("/stores/*").with(EnqueueStoresController.class);
serve("/clear/*").with(ClearTweetsController.class);
}
});
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
for (BlobStoreContext context : providerTypeToBlobStoreMap.values()) {
context.close();
}
queue.purge();
super.contextDestroyed(servletContextEvent);
}
}

View File

@ -1,153 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.Collections2.filter;
import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Maps.filterValues;
import static org.jclouds.util.Maps2.fromKeys;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector.Credential;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
/**
* Reads provider credentials from a {@link Properties} bag.
*
* @author Andrew Phillips
*
*/
public class CredentialsCollector implements Function<Properties, Map<String, Credential>> {
private static final String IDENTITY_PROPERTY_SUFFIX = ".identity";
private static final String CREDENTIAL_PROPERTY_SUFFIX = ".credential";
// using the identity for provider name extraction
private static final Pattern IDENTITY_PROPERTY_PATTERN =
Pattern.compile("([a-zA-Z0-9-]+)" + Pattern.quote(IDENTITY_PROPERTY_SUFFIX));
@Override
public Map<String, Credential> apply(final Properties properties) {
Collection<String> providerNames = transform(
filter(properties.stringPropertyNames(), MatchesPattern.matches(IDENTITY_PROPERTY_PATTERN)),
new Function<String, String>() {
@Override
public String apply(String input) {
Matcher matcher = IDENTITY_PROPERTY_PATTERN.matcher(input);
// as a side-effect, sets the matching group!
checkState(matcher.matches(), "'%s' should match '%s'", input, IDENTITY_PROPERTY_PATTERN);
return matcher.group(1);
}
});
/*
* Providers without a credential property result in null values, which are
* removed from the returned map.
*/
return filterValues(fromKeys(copyOf(providerNames), new Function<String, Credential>() {
@Override
public Credential apply(String providerName) {
String identity = properties.getProperty(providerName + IDENTITY_PROPERTY_SUFFIX);
String credential = properties.getProperty(providerName + CREDENTIAL_PROPERTY_SUFFIX);
return (((identity != null) && (credential != null))
? new Credential(identity, credential)
: null);
}
}), notNull());
}
public static class Credential {
private final String identity;
private final String credential;
public Credential(String identity, String credential) {
this.identity = checkNotNull(identity, "identity");
this.credential = checkNotNull(credential, "credential");
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((credential == null) ? 0 : credential.hashCode());
result = prime * result
+ ((identity == null) ? 0 : identity.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;
Credential other = (Credential) obj;
if (credential == null) {
if (other.credential != null)
return false;
} else if (!credential.equals(other.credential))
return false;
if (identity == null) {
if (other.identity != null)
return false;
} else if (!identity.equals(other.identity))
return false;
return true;
}
public String getIdentity() {
return identity;
}
public String getCredential() {
return credential;
}
}
@GwtIncompatible(value = "java.util.regex.Pattern")
private static class MatchesPattern implements Predicate<String> {
private final Pattern pattern;
private MatchesPattern(Pattern pattern) {
this.pattern = pattern;
}
@Override
public boolean apply(String input) {
return pattern.matcher(input).matches();
}
private static MatchesPattern matches(Pattern pattern) {
return new MatchesPattern(pattern);
}
}
}

View File

@ -1,96 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.logging.Logger;
import com.google.appengine.repackaged.com.google.common.collect.Lists;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
/**
* Shows an example of how to use @{link BlobStoreContext} injected with Guice.
*
* @author Adrian Cole
*/
@Singleton
public class AddTweetsController extends HttpServlet implements
Function<Set<String>, List<StoredTweetStatus>> {
/** The serialVersionUID */
private static final long serialVersionUID = 3888348023150822683L;
private final Map<String, BlobStoreContext> contexts;
private final ServiceToStoredTweetStatuses blobStoreContextToContainerResult;
@Resource
protected Logger logger = Logger.NULL;
@Inject
AddTweetsController(Map<String, BlobStoreContext> contexts,
ServiceToStoredTweetStatuses blobStoreContextToContainerResult) {
this.contexts = contexts;
this.blobStoreContextToContainerResult = blobStoreContextToContainerResult;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
addMyTweetsToRequest(request);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/tweets.jsp");
dispatcher.forward(request, response);
} catch (Exception e) {
logger.error(e, "Error listing containers");
throw new ServletException(e);
}
}
void addMyTweetsToRequest(HttpServletRequest request) throws InterruptedException,
ExecutionException, TimeoutException {
request.setAttribute("tweets", apply(contexts.keySet()));
}
public List<StoredTweetStatus> apply(Set<String> in) {
List<StoredTweetStatus> statuses = Lists.newArrayList();
for (Iterable<StoredTweetStatus> list : Iterables.transform(in,
blobStoreContextToContainerResult)) {
Iterables.addAll(statuses, list);
}
return statuses;
}
}

View File

@ -1,96 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.nullToEmpty;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import com.google.common.annotations.VisibleForTesting;
/**
* Grab tweets related to me and store them into blobstores
*
* @author Adrian Cole
*/
@Singleton
public class ClearTweetsController extends HttpServlet {
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Map<String, BlobStoreContext> contexts;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
@Inject
@VisibleForTesting
public ClearTweetsController(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container) {
this.container = container;
this.contexts = contexts;
}
@VisibleForTesting
public void clearContainer(String contextName) {
BlobStoreContext context = checkNotNull(contexts.get(contextName),
"no context for %s in %s", contextName, contexts.keySet());
try {
context.getBlobStore().clearContainer(container);
} catch (Exception e) {
logger.error(e, "Error clearing tweets in %s/%s", container, context);
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (nullToEmpty(request.getHeader("X-Originator")).equals("admin")) {
try {
String contextName = checkNotNull(request.getHeader("context"), "missing header context");
logger.info("clearing tweets in %s/%s", container, contextName);
clearContainer(contextName);
logger.debug("done clearing tweets");
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error clearing tweets");
throw new ServletException(e);
}
} else {
response.sendError(401);
}
}
}

View File

@ -1,92 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
import static com.google.appengine.repackaged.com.google.common.base.Strings.nullToEmpty;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.logging.Logger;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.common.annotations.VisibleForTesting;
/**
* Adds tasks to retrieve and store tweets in all registered contexts to an async
* task queue.
*
* @author Andrew Phillips
* @see StoreTweetsController
*/
@Singleton
public class EnqueueStoresController extends HttpServlet {
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Set<String> contextNames;
private final Queue taskQueue;
@Resource
protected Logger logger = Logger.NULL;
@Inject
public EnqueueStoresController(Map<String, BlobStoreContext> contexts,
Queue taskQueue) {
contextNames = contexts.keySet();
this.taskQueue = taskQueue;
}
@VisibleForTesting
void enqueueStoreTweetTasks() {
for (String contextName : contextNames) {
logger.debug("enqueuing task to store tweets in blobstore '%s'", contextName);
taskQueue.add(withUrl("/store/do").header("context", contextName).method(Method.GET));
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (!nullToEmpty(request.getHeader("X-AppEngine-Cron")).equals("true")) {
response.sendError(401);
}
try {
enqueueStoreTweetTasks();
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error storing tweets");
throw new ServletException(e);
}
}
}

View File

@ -1,129 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import twitter4j.Status;
import twitter4j.Twitter;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
/**
* Grab tweets related to me and store them into blobstores
*
* @author Adrian Cole
*/
@Singleton
public class StoreTweetsController extends HttpServlet {
private static final class StatusToBlob implements Function<Status, Blob> {
private final BlobMap map;
private StatusToBlob(BlobMap map) {
this.map = map;
}
public Blob apply(Status from) {
Blob to = map.blobBuilder().name(from.getId() + "").build();
to.setPayload(from.getText());
to.getPayload().getContentMetadata().setContentType(MediaType.TEXT_PLAIN);
to.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, from.getUser().getScreenName());
return to;
}
}
/** The serialVersionUID */
private static final long serialVersionUID = 7215420527854203714L;
private final Map<String, BlobStoreContext> contexts;
private final Twitter client;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
@Inject
@VisibleForTesting
public StoreTweetsController(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container, Twitter client) {
this.container = container;
this.contexts = contexts;
this.client = client;
}
@VisibleForTesting
public void addMyTweets(String contextName, Iterable<Status> responseList) {
BlobStoreContext context = checkNotNull(contexts.get(contextName), "no context for " + contextName + " in "
+ contexts.keySet());
BlobMap map = context.createBlobMap(container);
for (Status status : responseList) {
Blob blob = null;
try {
blob = new StatusToBlob(map).apply(status);
map.put(status.getId() + "", blob);
} catch (AuthorizationException e) {
throw e;
} catch (Exception e) {
logger.error(e, "Error storing tweet %s (blob[%s]) on map %s/%s", status.getId(), blob, context, container);
}
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (request.getHeader("X-AppEngine-QueueName") != null
&& request.getHeader("X-AppEngine-QueueName").equals("twitter")) {
try {
String contextName = checkNotNull(request.getHeader("context"), "missing header context");
logger.info("retrieving tweets");
addMyTweets(contextName, client.getMentions());
logger.debug("done storing tweets");
response.setContentType(MediaType.TEXT_PLAIN);
response.getWriter().println("Done!");
} catch (Exception e) {
logger.error(e, "Error storing tweets");
throw new ServletException(e);
}
} else {
response.sendError(401);
}
}
}

View File

@ -1,149 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.domain;
import java.io.Serializable;
/**
*
* @author Adrian Cole
*/
public class StoredTweetStatus implements Comparable<StoredTweetStatus>, Serializable {
/** The serialVersionUID */
private static final long serialVersionUID = -3257496189689220018L;
private final String service;
private final String host;
private final String container;
private final String id;
private final String from;
private final String tweet;
private final String status;
@Override
public String toString() {
return "StoredTweetStatus [container=" + container + ", from=" + from + ", host=" + host
+ ", id=" + id + ", service=" + service + ", status=" + status + ", tweet=" + tweet
+ "]";
}
public StoredTweetStatus(String service, String host, String container, String id, String from,
String tweet, String status) {
this.service = service;
this.host = host;
this.container = container;
this.id = id;
this.from = from;
this.tweet = tweet;
this.status = status;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((container == null) ? 0 : container.hashCode());
result = prime * result + ((from == null) ? 0 : from.hashCode());
result = prime * result + ((host == null) ? 0 : host.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((service == null) ? 0 : service.hashCode());
result = prime * result + ((tweet == null) ? 0 : tweet.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;
StoredTweetStatus other = (StoredTweetStatus) obj;
if (container == null) {
if (other.container != null)
return false;
} else if (!container.equals(other.container))
return false;
if (from == null) {
if (other.from != null)
return false;
} else if (!from.equals(other.from))
return false;
if (host == null) {
if (other.host != null)
return false;
} else if (!host.equals(other.host))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (service == null) {
if (other.service != null)
return false;
} else if (!service.equals(other.service))
return false;
if (tweet == null) {
if (other.tweet != null)
return false;
} else if (!tweet.equals(other.tweet))
return false;
return true;
}
public String getService() {
return service;
}
public String getHost() {
return host;
}
public String getContainer() {
return container;
}
public String getFrom() {
return from;
}
public String getTweet() {
return tweet;
}
public String getStatus() {
return status;
}
public int compareTo(StoredTweetStatus o) {
if (id == null)
return -1;
return (int) ((this == o) ? 0 : id.compareTo(o.id));
}
public String getId() {
return id;
}
}

View File

@ -1,70 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import javax.annotation.Resource;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import org.jclouds.util.Strings2;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
public class KeyToStoredTweetStatus implements Function<String, StoredTweetStatus> {
private final String host;
private final BlobMap map;
private final String service;
private final String container;
@Resource
protected Logger logger = Logger.NULL;
KeyToStoredTweetStatus(BlobMap map, String service, String host, String container) {
this.host = host;
this.map = map;
this.service = service;
this.container = container;
}
public StoredTweetStatus apply(String id) {
String status;
String from;
String tweet;
try {
long start = System.currentTimeMillis();
Blob blob = map.get(id);
status = ((System.currentTimeMillis() - start) + "ms");
from = blob.getMetadata().getUserMetadata().get(TweetStoreConstants.SENDER_NAME);
tweet = Strings2.toString(blob.getPayload());
} catch (Exception e) {
logger.error(e, "Error listing container %s//%s/%s", service, container, id);
status = (e.getMessage());
tweet = "";
from = "";
}
return new StoredTweetStatus(service, host, container, id, from, tweet, status);
}
}

View File

@ -1,73 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.functions;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Context;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
@Singleton
public class ServiceToStoredTweetStatuses implements Function<String, Iterable<StoredTweetStatus>> {
private final Map<String, BlobStoreContext> contexts;
private final String container;
@Inject
public ServiceToStoredTweetStatuses(Map<String, BlobStoreContext> contexts,
@Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container) {
this.contexts = contexts;
this.container = container;
}
@Resource
protected Logger logger = Logger.NULL;
public Iterable<StoredTweetStatus> apply(String service) {
BlobStoreContext context = contexts.get(service);
String host = URI.create(context.unwrap(Context.class).getProviderMetadata()
.getEndpoint()).getHost();
try {
BlobMap blobMap = context.createBlobMap(container);
Set<String> blobs = blobMap.keySet();
return Iterables.transform(blobs, new KeyToStoredTweetStatus(blobMap, service, host,
container));
} catch (Exception e) {
StoredTweetStatus result = new StoredTweetStatus(service, host, container, null, null,
null, e.getMessage());
logger.error(e, "Error listing service %s", service);
return ImmutableList.of(result);
}
}
}

View File

@ -1,34 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.reference;
/**
* Configuration properties and constants used in TweetStore connections.
*
* @author Adrian Cole
*/
public interface TweetStoreConstants {
static final String PROPERTY_TWEETSTORE_BLOBSTORES = "jclouds.tweetstore.blobstores";
static final String PROPERTY_TWEETSTORE_CONTAINER = "jclouds.tweetstore.container";
/**
* Note that this has to conform to restrictions of all blobstores. for example, azure doesn't
* support periods.
*/
static final String SENDER_NAME = "sendername";
}

View File

@ -1,31 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.reference;
/**
* Configuration properties and constants used in Twitter connections.
*
* @author Andrew Phillips
*/
public interface TwitterConstants {
static final String PROPERTY_TWITTER_CONSUMER_KEY = "twitter.consumer.identity";
static final String PROPERTY_TWITTER_CONSUMER_SECRET = "twitter.consumer.credential";
static final String PROPERTY_TWITTER_ACCESSTOKEN = "twitter.access.identity";
static final String PROPERTY_TWITTER_ACCESSTOKEN_SECRET = "twitter.access.credential";
}

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>${appengine.applicationid}</application>
<version>1</version>
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
</system-properties>
</appengine-web-app>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<cronentries>
<cron>
<url>/stores/do</url>
<description>Enqueue 'store tweet' tasks for all contexts</description>
<schedule>every 10 minutes</schedule>
</cron>
</cronentries>

View File

@ -1,37 +0,0 @@
#
# Licensed to jclouds, Inc. (jclouds) under one or more
# contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. jclouds 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.
#
# Set the default logging level for all loggers to WARNING
.level = INFO
# Set the default logging level for ORM, specifically, to WARNING
org.jclouds.level=INFO
DataNucleus.JDO.level=WARNING
DataNucleus.Persistence.level=WARNING
DataNucleus.Cache.level=WARNING
DataNucleus.MetaData.level=WARNING
DataNucleus.General.level=WARNING
DataNucleus.Utility.level=WARNING
DataNucleus.Transaction.level=WARNING
DataNucleus.Datastore.level=WARNING
DataNucleus.ClassLoading.level=WARNING
DataNucleus.Plugin.level=WARNING
DataNucleus.ValueGeneration.level=WARNING
DataNucleus.Enhancer.level=WARNING
DataNucleus.SchemaTool.level=WARNING

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<queue-entries>
<queue>
<name>twitter</name>
<!-- poll every 30s, but only allow one request at a time to save CPU -->
<rate>2/m</rate>
<max-concurrent-requests>1</max-concurrent-requests>
</queue>
</queue-entries>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
-->
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
version="2.5">
<display-name>jclouds-tweetstore</display-name>
<!-- Servlets -->
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.jclouds.demo.tweetstore.config.GuiceServletConfig
</listener-class>
</listener>
<!-- limit submission of storage tasks to the cron job -->
<security-constraint>
<web-resource-collection>
<url-pattern>/stores/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

View File

@ -1,31 +0,0 @@
<%--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
--%>
<html>
<head>
<title>jclouds: anyweight cloudware for java</title>
</head>
<body>
<h2>Welcome!</h2>
<p>Click <a href="/tweets/get">here</a> to see tweets about jclouds.</p>
<p><img src="http://code.google.com/appengine/images/appengine-noborder-120x30.gif"
alt="Powered by Google App Engine" /></p>
</body>
</html>

View File

@ -1,109 +0,0 @@
<%--
Licensed to jclouds, Inc. (jclouds) under one or more
contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. jclouds 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.
--%>
<%@ page buffer="20kb"%>
<%@ taglib uri="http://displaytag.sf.net" prefix="display"%>
<html>
<head>
<title>jclouds: anyweight cloudware for java</title>
<style type="text/css">
<!--
table.staticheader {
text-decoration: none;
border: 1px solid #CCC;
width: 98%;
}
table.staticheader th {
padding: 3px 3px 3px 3px !important;
text-align:center;
}
table.staticheader td {
padding: 3px 3px 3px 3px !important;
}
table.staticheader thead tr {
position: relative;
height: 10px;
background-color: #D7E5F3;
}
table.staticheader tbody {
height:800px;
overflow-x:hidden;
overflow-y: auto;
overflow:scroll;
}
table.staticheader tbody tr {
height: auto;
white-space: nowrap;
}
table.staticheader tbody tr.odd {
background-color: #eee
}
table.staticheader tbody tr.tableRowEven,tr.even {
background-color: #ddd
}
table.staticheader tbody tr td:last-child {
padding-right: 20px;
}
table.staticheader tbody td {
padding: 2px 4px 2px 4px !important;
}
div.TableContainer {
height: 800px;
overflow-x:hidden;
overflow-y:auto;
}
-->
</style>
</head>
<body>
<h2>Tweets in Clouds</h2>
<table width="100%" border="0">
<tr>
<td>
<div class="TableContainer">
<display:table name="tweets" defaultsort="1" cellpadding="5" cellspacing="1" class="staticheader">
<display:column property="id" title="Tweet ID" />
<display:column property="from" title="Who Said it" />
<display:column property="tweet" title="Tweet" />
<display:column property="service" title="Cloud" />
<display:column property="host" title="Host" />
<display:column property="status" title="Status" />
</display:table>
</div>
</td>
</tr>
<tr>
<td><img src="http://code.google.com/appengine/images/appengine-noborder-120x30.gif"
alt="Powered by Google App Engine" /></td>
</tr>
</table>
</body>
</html>

View File

@ -1,82 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.config.util;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Map;
import java.util.Properties;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector;
import org.jclouds.demo.tweetstore.config.util.CredentialsCollector.Credential;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@code CredentialsCollector}
*
* @author Andrew Phillips
*/
@Test(groups = "unit")
public class CredentialsCollectorTest {
private CredentialsCollector collector = new CredentialsCollector();
public void testEmptyProperties() {
assertTrue(collector.apply(new Properties()).isEmpty(),
"Expected returned map to be empty");
}
public void testNoCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("not-an-identity",
"v1", "not-a-credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
private static Properties propertiesOf(Map<String, String> entries) {
Properties properties = new Properties();
properties.putAll(entries);
return properties;
}
public void testNonMatchingCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("non_matching.identity", "v1",
"non_matching.credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
public void testIncompleteCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("acme.identity", "v1",
"acme-2.credential", "v2"));
assertTrue(collector.apply(properties).isEmpty(),
"Expected returned map to be empty");
}
public void testCredentials() {
Properties properties = propertiesOf(ImmutableMap.of("acme.identity", "v1",
"acme.credential", "v2", "acme-2.identity", "v3",
"acme-2.credential", "v4"));
assertEquals(collector.apply(properties),
ImmutableMap.of("acme", new Credential("v1", "v2"),
"acme-2", new Credential("v3", "v4")));
}
}

View File

@ -1,78 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.domain.StoredTweetStatus;
import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
import org.testng.collections.Maps;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code AddTweetsController}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class AddTweetsControllerTest {
Map<String, BlobStoreContext> createServices(String container) throws InterruptedException,
ExecutionException {
Map<String, BlobStoreContext> services = Maps.newHashMap();
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
for (String name : new String[] { "1", "2" }) {
BlobStoreContext context = ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class);
context.getAsyncBlobStore().createContainerInLocation(null, container).get();
Blob blob = context.getAsyncBlobStore().blobBuilder("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
context.getAsyncBlobStore().putBlob(container, blob).get();
services.put(name, context);
}
return services;
}
public void testStoreTweets() throws IOException, InterruptedException, ExecutionException {
String container = "container";
Map<String, BlobStoreContext> contexts = createServices(container);
ServiceToStoredTweetStatuses function = new ServiceToStoredTweetStatuses(contexts, container);
AddTweetsController controller = new AddTweetsController(contexts, function);
List<StoredTweetStatus> list = controller.apply(ImmutableSet.of("1", "2"));
assertEquals(list.size(), 2);
assertEquals(list, ImmutableList.of(new StoredTweetStatus("1", "localhost", container, "1",
"frank", "I love beans!", null), new StoredTweetStatus("2", "localhost", container,
"1", "frank", "I love beans!", null)));
}
}

View File

@ -1,72 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@code AddTweetsController}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class ClearTweetsControllerTest {
Map<String, BlobStoreContext> createBlobStores(String container) throws InterruptedException, ExecutionException {
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext>of(
"test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class),
"test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class));
for (BlobStoreContext blobstore : contexts.values()) {
blobstore.getBlobStore().createContainerInLocation(null, container);
Blob blob = blobstore.getAsyncBlobStore().blobBuilder("1").build();
blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank");
blob.setPayload("I love beans!");
blobstore.getBlobStore().putBlob(container, blob);
}
return contexts;
}
public void testClearTweets() throws IOException, InterruptedException, ExecutionException {
String container = ClearTweetsControllerTest.class.getName() + "#container";
Map<String, BlobStoreContext> contexts = createBlobStores(container);
ClearTweetsController controller = new ClearTweetsController(contexts,
container);
controller.clearContainer("test1");
controller.clearContainer("test2");
for (BlobStoreContext context : contexts.values()) {
assertEquals(context.getBlobStore().countBlobs(container), 0, context.toString());
}
}
}

View File

@ -1,67 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.demo.tweetstore.controller;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.util.Map;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientApiMetadata;
import org.testng.annotations.Test;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.google.common.collect.ImmutableMap;
/**
* Tests behavior of {@link EnqueueStoresController}
*
* @author Andrew Phillips
*/
@Test(groups = "unit")
public class EnqueueStoresControllerTest {
Map<String, BlobStoreContext> createBlobStores() {
TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build();
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext>of(
"test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class),
"test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class));
return contexts;
}
public void testEnqueueStores() {
Map<String, BlobStoreContext> stores = createBlobStores();
Queue taskQueue = createMock(Queue.class);
EnqueueStoresController function = new EnqueueStoresController(stores, taskQueue);
expect(taskQueue.add(withUrl("/store/do").header("context", "test1").method(Method.GET))).andReturn(null);
expect(taskQueue.add(withUrl("/store/do").header("context", "test2").method(Method.GET))).andReturn(null);
replay(taskQueue);
function.enqueueStoreTweetTasks();
verify(taskQueue);
}
}

Some files were not shown because too many files have changed in this diff Show More