mirror of https://github.com/apache/jclouds.git
Added OpenShift Express TweetStore (no live integration tests yet - will try Arquillian)
This commit is contained in:
parent
6ef96f0de5
commit
9a783b1291
|
@ -0,0 +1,41 @@
|
|||
====
|
||||
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.rhcloud-tweetstore.consumer.identity>YOUR_TWITTER_CONSUMER_KEY</test.twitter.rhcloud-tweetstore.consumer.identity>
|
||||
<test.twitter.rhcloud-tweetstore.consumer.credential>YOUR_TWITTER_CONSUMER_SECRET</test.twitter.rhcloud-tweetstore.consumer.credential>
|
||||
<test.twitter.rhcloud-tweetstore.access.identity>YOUR_TWITTER_ACCESSTOKEN</test.twitter.rhcloud-tweetstore.access.identity>
|
||||
<test.twitter.rhcloud-tweetstore.access.credential>YOUR_TWITTER_ACCESSTOKEN_SECRET</test.twitter.rhcloud-tweetstore.access.credential>
|
||||
</properties>
|
||||
</profile>
|
|
@ -0,0 +1,122 @@
|
|||
<?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.5.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>jclouds-demo-rhcloud-tweetstore</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>jclouds TweetStore for OpenShift Express</name>
|
||||
<description>jclouds TweetStore for RedHat's OpenShift Express using Guice for Dependency Injection</description>
|
||||
|
||||
<properties>
|
||||
<test.rhcloud.address>localhost</test.rhcloud.address>
|
||||
<test.rhcloud.port>8088</test.rhcloud.port>
|
||||
<jclouds.tweetstore.container>jclouds-rhcloud-tweetstore</jclouds.tweetstore.container>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-servlet</artifactId>
|
||||
<version>3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- OpenShift Express uses JBoss AS 7 -->
|
||||
<!--dependency>
|
||||
<groupId>org.jboss.embedded</groupId>
|
||||
<artifactId>jboss-embedded</artifactId>
|
||||
<version>beta3.SP12</version>
|
||||
<scope>test</scope>
|
||||
</dependency-->
|
||||
</dependencies>
|
||||
|
||||
<!--repositories>
|
||||
<!- - net.stax:stax-appserver is not in central - ->
|
||||
<repository>
|
||||
<id>bees-snapshots</id>
|
||||
<url>http://repository-cloudbees.forge.cloudbees.com/public-snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</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.runatcloud-tweetstore.consumer.identity}</test.twitter.consumer.identity>
|
||||
<test.twitter.consumer.credential>${test.twitter.runatcloud-tweetstore.consumer.credential}</test.twitter.consumer.credential>
|
||||
<test.twitter.access.identity>${test.twitter.runatcloud-tweetstore.access.identity}</test.twitter.access.identity>
|
||||
<test.twitter.access.credential>${test.twitter.runatcloud-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>
|
||||
<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>
|
||||
<rhcloud.address>${test.rhcloud.address}</rhcloud.address>
|
||||
<rhcloud.port>${test.rhcloud.port}</rhcloud.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>rhcloud-tweetstore</tweetstore.instance>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* 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.taskqueue.TaskQueue;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* @author Andrew Phillips
|
||||
*/
|
||||
public class PlatformServices {
|
||||
protected final String baseUrl;
|
||||
private ImmutableMap<String, TaskQueue> taskQueues;
|
||||
|
||||
public PlatformServices(String baseUrl, Map<String, TaskQueue> taskQueues) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.taskQueues = ImmutableMap.copyOf(taskQueues);
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* 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 java.lang.String.format;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
import org.jclouds.PropertiesBuilder;
|
||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||
import org.jclouds.demo.paas.PlatformServices;
|
||||
import org.jclouds.demo.paas.service.taskqueue.TaskQueue;
|
||||
import org.jclouds.demo.tweetstore.config.util.PropertiesLoader;
|
||||
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.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.sun.jersey.api.uri.UriBuilderImpl;
|
||||
|
||||
/**
|
||||
* @author Andrew Phillips
|
||||
*/
|
||||
public class PlatformServicesInitializer implements ServletContextListener {
|
||||
public static final String PLATFORM_SERVICES_ATTRIBUTE_NAME = PlatformServicesInitializer.class.getName();
|
||||
|
||||
// from .openshift/config/standalone.xml
|
||||
protected static final String HOST_VARIABLE = "OPENSHIFT_INTERNAL_IP";
|
||||
protected static final String PORT_VARIABLE = "OPENSHIFT_INTERNAL_PORT";
|
||||
|
||||
@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), createTaskQueues(httpClient));
|
||||
}
|
||||
|
||||
protected static HttpCommandExecutorService createHttpClient(
|
||||
final ServletContext context) {
|
||||
return Guice.createInjector(new ExecutorServiceModule(),
|
||||
new JavaUrlHttpCommandExecutorServiceModule(),
|
||||
new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
// URL connection defaults
|
||||
Properties toBind = new PropertiesBuilder().build();
|
||||
toBind.putAll(checkNotNull(new PropertiesLoader(context).get(), "properties"));
|
||||
toBind.putAll(System.getProperties());
|
||||
bindProperties(binder(), toBind);
|
||||
bind(UriBuilder.class).to(UriBuilderImpl.class);
|
||||
}
|
||||
}).getInstance(HttpCommandExecutorService.class);
|
||||
}
|
||||
|
||||
protected static String getBaseUrl(ServletContext context) {
|
||||
return format("http://%s:%s%s", checkNotNull(System.getenv(HOST_VARIABLE), HOST_VARIABLE),
|
||||
checkNotNull(System.getenv(PORT_VARIABLE), PORT_VARIABLE), 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* 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";
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* 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.paas.reference.PaasConstants.PROPERTY_PLATFORM_BASE_URL;
|
||||
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.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||
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.config.util.PropertiesLoader;
|
||||
import org.jclouds.demo.tweetstore.controller.AddTweetsController;
|
||||
import org.jclouds.demo.tweetstore.controller.EnqueueStoresController;
|
||||
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
|
||||
|
||||
import twitter4j.Twitter;
|
||||
import twitter4j.TwitterFactory;
|
||||
import twitter4j.conf.Configuration;
|
||||
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.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 {
|
||||
private Map<String, BlobStoreContext> providerTypeToBlobStoreMap;
|
||||
private Twitter twitterClient;
|
||||
private String container;
|
||||
private TaskQueue queue;
|
||||
private String baseUrl;
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent servletContextEvent) {
|
||||
BlobStoreContextFactory blobStoreContextFactory = new BlobStoreContextFactory();
|
||||
ServletContext servletContext = servletContextEvent.getServletContext();
|
||||
|
||||
Properties props = new PropertiesLoader(servletContext).get();
|
||||
Set<Module> modules = ImmutableSet.<Module>of();
|
||||
// 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, blobStoreContextFactory.createContext(hint, modules, props));
|
||||
}
|
||||
|
||||
// get a queue for submitting store tweet requests and the application's base URL
|
||||
PlatformServices platform = PlatformServices.get(servletContext);
|
||||
queue = platform.getTaskQueue("twitter");
|
||||
baseUrl = platform.getBaseUrl();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@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(TaskQueue.class).toInstance(queue);
|
||||
bindConstant().annotatedWith(Names.named(PROPERTY_PLATFORM_BASE_URL))
|
||||
.to(baseUrl);
|
||||
bindConstant().annotatedWith(Names.named(PROPERTY_TWEETSTORE_CONTAINER))
|
||||
.to(container);
|
||||
serve("/store/*").with(StoreTweetsController.class);
|
||||
serve("/tweets/*").with(AddTweetsController.class);
|
||||
serve("/stores/*").with(EnqueueStoresController.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent servletContextEvent) {
|
||||
for (BlobStoreContext context : providerTypeToBlobStoreMap.values()) {
|
||||
context.close();
|
||||
}
|
||||
queue.destroy();
|
||||
super.contextDestroyed(servletContextEvent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* 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
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* 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 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("X-Rhcloud-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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* 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.jclouds.util.Strings2.toStringAndClose;
|
||||
|
||||
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 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 = toStringAndClose(blob.getPayload().getInput());
|
||||
} 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* 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.util.Collections;
|
||||
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.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 = context.getProviderSpecificContext().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 Collections.singletonList(result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* 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";
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* 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";
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?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>
|
||||
|
||||
<!-- must be started first -->
|
||||
<listener>
|
||||
<listener-class>org.jclouds.demo.paas.config.PlatformServicesInitializer</listener-class>
|
||||
</listener>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.jclouds.demo.tweetstore.config.GuiceServletConfig</listener-class>
|
||||
</listener>
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
</web-app>
|
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,30 @@
|
|||
<%--
|
||||
|
||||
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/openshift-logo.png" alt="Powered by OpenShift Express" /></p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,108 @@
|
|||
<%--
|
||||
|
||||
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/openshift-logo.png" alt="Powered by OpenShift Express" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* 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")));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* 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.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||
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();
|
||||
for (String name : new String[] { "1", "2" }) {
|
||||
BlobStoreContext context = new BlobStoreContextFactory().createContext("transient", "dummy", "dummy");
|
||||
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)));
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* 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.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||
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() {
|
||||
Map<String, BlobStoreContext> contexts = ImmutableMap.of(
|
||||
"test1", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"),
|
||||
"test2", new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"));
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* 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.expect;
|
||||
import static org.easymock.classextension.EasyMock.createMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.jclouds.util.Strings2.toStringAndClose;
|
||||
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.blobstore.BlobMap;
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.demo.tweetstore.reference.TweetStoreConstants;
|
||||
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 {
|
||||
Map<String, BlobStoreContext> contexts = ImmutableMap.<String, BlobStoreContext> of("test1",
|
||||
new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"), "test2",
|
||||
new BlobStoreContextFactory().createContext("transient", "dummy", "dummy"));
|
||||
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(toStringAndClose(frankBlob.getPayload().getInput()), "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(toStringAndClose(jimmyBlob.getPayload().getInput()), "cloud is king");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* 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.blobstore.BlobMap;
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||
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 = new BlobStoreContextFactory().createContext("transient", "dummy", "dummy");
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* 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.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||
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();
|
||||
for (String name : new String[] { "1", "2" }) {
|
||||
BlobStoreContext context = new BlobStoreContextFactory().createContext("transient",
|
||||
"dummy", "dummy");
|
||||
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));
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* 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 java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
/**
|
||||
* Basic functionality to start a local JBoss 7 AS (as used by OpenShift Express) instance.
|
||||
*
|
||||
* @author Andrew Phillips
|
||||
*/
|
||||
public class RhcloudServer {
|
||||
//protected StaxSdkAppServer2 server;
|
||||
|
||||
public void writePropertiesAndStartServer(final String address, final String port,
|
||||
final String warfile, final String environments,
|
||||
final String serverBaseDirectory, Properties props) throws IOException, InterruptedException, ServletException {
|
||||
String filename = String.format(
|
||||
"%1$s/WEB-INF/jclouds.properties", warfile);
|
||||
System.err.println("file: " + filename);
|
||||
props.store(new FileOutputStream(filename), "test");
|
||||
assert new File(filename).exists();
|
||||
// server = StaxSdkAppServer2.createServer(new String[] { "-web", warfile, "-port", port, "-env", environments,
|
||||
// "-dir", serverBaseDirectory }, new String[0], Thread.currentThread().getContextClassLoader());
|
||||
// server.start();
|
||||
TimeUnit.SECONDS.sleep(30);
|
||||
}
|
||||
|
||||
public void stop() throws Exception {
|
||||
// server.stop();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
/**
|
||||
* 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.paas.RunnableHttpRequest.PLATFORM_REQUEST_ORIGINATOR_HEADER;
|
||||
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.blobstore.BlobStoreContext;
|
||||
import org.jclouds.blobstore.BlobStoreContextFactory;
|
||||
import org.jclouds.demo.tweetstore.controller.StoreTweetsController;
|
||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.util.Strings2;
|
||||
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.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 {
|
||||
|
||||
RhcloudServer server;
|
||||
private URL url;
|
||||
private Map<String, BlobStoreContext> contexts;
|
||||
private String container;
|
||||
private static final Iterable<String> blobstores =
|
||||
Splitter.on(',').split(getRequiredSystemProperty(PROPERTY_TWEETSTORE_BLOBSTORES));
|
||||
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);
|
||||
|
||||
// put all identity/credential pairs into the client
|
||||
addCredentialsForBlobStores(props);
|
||||
|
||||
// example of an ad-hoc client configuration
|
||||
addConfigurationForTwitter(props);
|
||||
|
||||
final BlobStoreContextFactory factory = new BlobStoreContextFactory();
|
||||
// for testing, capture logs.
|
||||
final Set<Module> wiring = ImmutableSet.<Module> of(new Log4JLoggingModule());
|
||||
this.contexts = Maps.newConcurrentMap();
|
||||
|
||||
for (String provider : blobstores) {
|
||||
contexts.put(provider, factory.createContext(provider, wiring, props));
|
||||
}
|
||||
|
||||
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()) {
|
||||
try {
|
||||
if (context.getBlobStore().containerExists(container)) {
|
||||
System.err.printf("deleting container %s at %s%n", container, context.getProviderSpecificContext()
|
||||
.getEndpoint());
|
||||
context.getBlobStore().deleteContainer(container);
|
||||
deleted = true;
|
||||
}
|
||||
} catch (AuthorizationException e) {
|
||||
throw new AuthorizationException("for context: " + context, e);
|
||||
}
|
||||
}
|
||||
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.getProviderSpecificContext()
|
||||
.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(dependsOnMethods = "clearAndCreateContainers")
|
||||
@Parameters({ "warfile", "rhcloud.address", "rhcloud.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 RhcloudServer();
|
||||
// server.writePropertiesAndStartServer(address, port, warfile, "itest",
|
||||
// serverBaseDirectory, props);
|
||||
}
|
||||
|
||||
@Test(enabled = false)
|
||||
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, enabled = false)
|
||||
public void shouldFail() throws InterruptedException, IOException {
|
||||
new URL(url, "/store/do").openStream();
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "shouldFail", enabled = false)
|
||||
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(PLATFORM_REQUEST_ORIGINATOR_HEADER, "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.getProviderSpecificContext().getEndpoint();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(invocationCount = 5, dependsOnMethods = "testPrimeContainers", enabled = false)
|
||||
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, enabled = false)
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
<?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>
|
Loading…
Reference in New Issue