Merge branch 'master' of git@github.com:jclouds/jclouds

* 'master' of git@github.com:jclouds/jclouds:
  Merge branch 'json-client-cleanup'
  Line endings again.
  Updated project member details and added a bit more anti-spam protection.
  Removed some duplicate copyright header and made gogrid inherit from project, not multi.
  [issue 178] Added a Compute service template archetype.
  Line endings.
  Removed Twitter-specific classes from the JSON client archetype.
  Factor out service args into a fixture so other modules can reuse tests.
This commit is contained in:
Adrian Cole 2010-03-20 12:42:55 -07:00
commit 1ca3919442
39 changed files with 1689 additions and 1168 deletions

View File

@ -0,0 +1,9 @@
# use glob syntax.
syntax: glob
target
.settings
.classpath
.project
jclouds-compute-service-archetype.iml
jclouds-compute-service-archetype.ipr
jclouds-compute-service-archetype.iws

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
====================================================================
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
====================================================================
-->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-archetypes</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>jclouds-compute-service-archetype</artifactId>
<name>jclouds Compute service archetype</name>
<description>Maven archetype for a provider of a Computer service</description>
<packaging>maven-archetype</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-archetype-plugin</artifactId>
<version>2.0-alpha-4</version>
<extensions>true</extensions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>org.apache.maven.archetype</groupId>
<artifactId>archetype-packaging</artifactId>
<version>2.0-alpha-4</version>
</extension>
</extensions>
</build>
<distributionManagement>
<repository>
<uniqueVersion>false</uniqueVersion>
<id>jclouds-googlecode-deploy</id>
<url>svn:https://jclouds.googlecode.com/svn/repo</url>
</repository>
<snapshotRepository>
<id>jclouds-rimu-snapshots</id>
<url>dav:http://jclouds.rimuhosting.com/maven2/snapshots/</url>
</snapshotRepository>
<site>
<id>website</id>
<name>website</name>
<url>file://${basedir}/target/dist/site/jclouds-testing/</url>
</site>
</distributionManagement>
</project>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
====================================================================
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
====================================================================
-->
<archetype-descriptor name="jclouds-compute-service-archetype">
<requiredProperties>
<requiredProperty key="groupId">
<defaultValue>org.jclouds</defaultValue>
</requiredProperty>
<requiredProperty key="author">
<defaultValue>Adrian Cole</defaultValue>
</requiredProperty>
<requiredProperty key="providerName" />
<requiredProperty key="providerEndpoint" />
<requiredProperty key="providerUser" />
<requiredProperty key="providerPassword" />
</requiredProperties>
<fileSets>
<fileSet filtered="true" packaged="true" encoding="UTF-8">
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
</includes>
</fileSet>
<fileSet filtered="true" packaged="true" encoding="UTF-8">
<directory>src/test/java</directory>
<includes>
<include>**/*.java</include>
</includes>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/test/resources</directory>
<includes>
<include>**/*.xml</include>
</includes>
</fileSet>
<fileSet encoding="UTF-8">
<directory>src/test/resources</directory>
<includes>
<include>**/*.json</include>
</includes>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory />
<includes>
<include>.gitignore</include>
</includes>
</fileSet>
</fileSets>
</archetype-descriptor>

View File

@ -0,0 +1,9 @@
# use glob syntax.
syntax: glob
target
.settings
.classpath
.project
jclouds-${artifactId}.iml
jclouds-${artifactId}.ipr
jclouds-${artifactId}.iws

View File

@ -1,4 +1,4 @@
#set( $lcaseClientName = ${clientName.toLowerCase()} ) #set( $lcaseProviderName = ${providerName.toLowerCase()} )
#set( $symbol_dollar = '$' ) #set( $symbol_dollar = '$' )
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
@ -6,7 +6,7 @@
${symbol_dollar}Revision${symbol_dollar} ${symbol_dollar}Revision${symbol_dollar}
${symbol_dollar}Date${symbol_dollar} ${symbol_dollar}Date${symbol_dollar}
Copyright (C) 2009 Cloud Conscious, LLC <info@cloudconscious.com> Copyright (C) 2010 Cloud Conscious, LLC <info@cloudconscious.com>
==================================================================== ====================================================================
Licensed to the Apache Software Foundation (ASF) under one Licensed to the Apache Software Foundation (ASF) under one
@ -27,35 +27,43 @@
under the License. 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"> <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> <parent>
<groupId>org.jclouds</groupId> <groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId> <artifactId>jclouds-project</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<relativePath>../project/pom.xml</relativePath> <relativePath>../project/pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId> <groupId>${groupId}</groupId>
<artifactId>jclouds-${artifactId}</artifactId> <artifactId>jclouds-${artifactId}</artifactId>
<name>jclouds ${clientName} core</name> <name>jclouds ${providerName} compute service</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>jclouds components to access ${clientName}</description> <description>jclouds components to access ${providerName}</description>
<scm> <scm>
<connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/${lcaseClientName}</connection> <connection>scm:svn:http://jclouds.googlecode.com/svn/trunk/${lcaseProviderName}</connection>
<developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/${lcaseClientName}</developerConnection> <developerConnection>scm:svn:https://jclouds.googlecode.com/svn/trunk/${lcaseProviderName}</developerConnection>
<url>http://jclouds.googlecode.com/svn/trunk/${lcaseClientName}</url> <url>http://jclouds.googlecode.com/svn/trunk/${lcaseProviderName}</url>
</scm> </scm>
<properties> <properties>
<jclouds.test.user>${clientUser}</jclouds.test.user> <jclouds.test.user>${providerUser}</jclouds.test.user>
<jclouds.test.key>${clientPassword}</jclouds.test.key> <jclouds.test.key>${providerPassword}</jclouds.test.key>
<jclouds.test.endpoint>${providerEndpoint}</jclouds.test.endpoint>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${symbol_dollar}{project.groupId}</groupId> <groupId>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-core</artifactId> <artifactId>jclouds-compute</artifactId>
<version>${symbol_dollar}{project.version}</version> <version>${symbol_dollar}{project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-compute</artifactId>
<version>${symbol_dollar}{project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>${symbol_dollar}{project.groupId}</groupId> <groupId>${symbol_dollar}{project.groupId}</groupId>
<artifactId>jclouds-core</artifactId> <artifactId>jclouds-core</artifactId>
@ -64,9 +72,9 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>log4j</groupId> <groupId>${symbol_dollar}{project.groupId}</groupId>
<artifactId>log4j</artifactId> <artifactId>jclouds-jsch</artifactId>
<version>1.2.14</version> <version>${symbol_dollar}{project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -75,5 +83,11 @@
<version>${symbol_dollar}{project.version}</version> <version>${symbol_dollar}{project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,47 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package};
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* Related to a ${providerName} resource.
*
* @author ${author}
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface ${providerName} {
}

View File

@ -0,0 +1,40 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package};
import com.google.inject.ImplementedBy;
import ${package}.internal.${providerName}AsyncClientImpl;
/**
* @author ${author}
*/
@ImplementedBy(${providerName}AsyncClientImpl.class)
public interface ${providerName}AsyncClient {
/*
* TODO: define interface methods for ${providerName}
*/
}

View File

@ -0,0 +1,41 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package};
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
/**
* @author ${author}
*/
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
public interface ${providerName}Client {
/*
* TODO: define synchronous versions of methods in ${providerName}AsyncClient
*/
}

View File

@ -0,0 +1,69 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package};
import java.util.List;
import java.util.Properties;
import com.google.inject.Key;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextBuilder;
import org.jclouds.compute.internal.ComputeServiceContextImpl;
import ${package}.config.${providerName}ComputeServiceContextModule;
import ${package}.config.${providerName}RestClientModule;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* @author ${author}
*/
public class ${providerName}ContextBuilder extends ComputeServiceContextBuilder<${providerName}AsyncClient, ${providerName}Client> {
public ${providerName}ContextBuilder(Properties props) {
super(new TypeLiteral<${providerName}AsyncClient>() {},
new TypeLiteral<${providerName}Client>() {},
props);
}
protected void addClientModule(List<Module> modules) {
modules.add(new ${providerName}RestClientModule());
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new ${providerName}ComputeServiceContextModule());
}
@Override
public ComputeServiceContext buildComputeServiceContext() {
return this.buildInjector().getInstance(Key.get(
new TypeLiteral<ComputeServiceContextImpl<${providerName}AsyncClient, ${providerName}Client>>() {}));
}
}

View File

@ -0,0 +1,66 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package ${package};
import java.net.URI;
import java.util.Properties;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import com.google.inject.Module;
/**
* Creates {@link ComputeServiceContext} instances based on the most commonly
* requested arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author ${author}
* @see ComputeServiceContext
*/
public class ${providerName}ContextFactory {
public static ComputeServiceContext createContext(Properties properties, Module... modules) {
return new ${providerName}ContextBuilder(
new ${providerName}PropertiesBuilder(properties).build()).withModules(modules)
.buildComputeServiceContext();
}
public static ComputeServiceContext createContext(Properties properties, String user,
String key, Module... modules) {
return new ${providerName}ContextBuilder(
new ${providerName}PropertiesBuilder(properties).withCredentials(user, key)
.build()).withModules(modules).buildComputeServiceContext();
}
public static ComputeServiceContext createContext(URI endpoint, String user, String key,
Module... modules) {
return new ${providerName}ContextBuilder(
new ${providerName}PropertiesBuilder(endpoint, user, key).withEndpoint(endpoint).build())
.withModules(modules).buildComputeServiceContext();
}
}

View File

@ -0,0 +1,76 @@
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package};
import org.jclouds.PropertiesBuilder;
import static com.google.common.base.Preconditions.checkNotNull;
import static ${package}.reference.${providerName}Constants.*;
import java.net.URI;
import java.util.Properties;
/**
* Builds properties used in ${providerName} Clients
*
* @author ${author}
*
*/
public class ${providerName}PropertiesBuilder extends PropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_${ucaseProviderName}_ENDPOINT, "${providerEndpoint}");
properties.setProperty(PROPERTY_${ucaseProviderName}_SESSIONINTERVAL, 8 * 60 + "");
return properties;
}
public ${providerName}PropertiesBuilder(Properties properties) {
super(properties);
}
public ${providerName}PropertiesBuilder(URI endpoint, String id, String secret) {
super();
withCredentials(id, secret);
withEndpoint(endpoint);
}
public ${providerName}PropertiesBuilder withTokenExpiration(long seconds) {
properties.setProperty(PROPERTY_${ucaseProviderName}_SESSIONINTERVAL, seconds + "");
return this;
}
public ${providerName}PropertiesBuilder withCredentials(String id, String secret) {
properties.setProperty(PROPERTY_${ucaseProviderName}_USER, checkNotNull(id, "user"));
properties.setProperty(PROPERTY_${ucaseProviderName}_KEY, checkNotNull(secret, "key"));
return this;
}
public ${providerName}PropertiesBuilder withEndpoint(URI endpoint) {
properties.setProperty(PROPERTY_${ucaseProviderName}_ENDPOINT,
checkNotNull(endpoint, "endpoint").toString());
return this;
}
}

View File

@ -0,0 +1,256 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package ${package}.config;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.predicates.RunScriptRunning;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.DestroyNodeStrategy;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.logging.Logger;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.jclouds.ssh.SshClient;
import ${package}.${providerName}AsyncClient;
import ${package}.${providerName}Client;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Provides;
/**
* @author ${author}
*/
public class ${providerName}ComputeServiceContextModule extends ${providerName}ContextModule {
@Override
protected void configure() {
super.configure();
bind(AddNodeWithTagStrategy.class).to(${providerName}AddNodeWithTagStrategy.class);
bind(ListNodesStrategy.class).to(${providerName}ListNodesStrategy.class);
bind(GetNodeMetadataStrategy.class).to(${providerName}GetNodeMetadataStrategy.class);
bind(RebootNodeStrategy.class).to(${providerName}RebootNodeStrategy.class);
bind(DestroyNodeStrategy.class).to(${providerName}DestroyNodeStrategy.class);
}
@Provides
@Named("NAMING_CONVENTION")
@Singleton
String provideNamingConvention() {
return "%s-%d";
}
@Singleton
public static class ${providerName}AddNodeWithTagStrategy implements AddNodeWithTagStrategy {
@Inject
protected ${providerName}AddNodeWithTagStrategy() {
}
@Override
public NodeMetadata execute(String tag, String name, Template template) {
/*
* TODO: implement
*/
return null;
}
}
@Singleton
public static class ${providerName}RebootNodeStrategy implements RebootNodeStrategy {
@Inject
protected ${providerName}RebootNodeStrategy() {
}
@Override
public boolean execute(ComputeMetadata node) {
/*
* TODO: implement
*/
return false;
}
}
@Singleton
public static class ${providerName}ListNodesStrategy implements ListNodesStrategy {
@Inject
protected ${providerName}ListNodesStrategy() {
}
@Override
public Iterable<? extends ComputeMetadata> execute() {
/*
* TODO: implement
*/
return null;
}
}
@Singleton
public static class ${providerName}GetNodeMetadataStrategy implements GetNodeMetadataStrategy {
@Inject
protected ${providerName}GetNodeMetadataStrategy() {
}
@Override
public NodeMetadata execute(ComputeMetadata node) {
/*
* TODO: implement
*/
return null;
}
}
@Singleton
public static class ${providerName}DestroyNodeStrategy implements DestroyNodeStrategy {
@Inject
protected ${providerName}DestroyNodeStrategy() {
}
@Override
public boolean execute(ComputeMetadata node) {
/*
* TODO: implement
*/
return false;
}
}
@Provides
@Singleton
ComputeServiceContext provideContext(ComputeService computeService,
RestContext<${providerName}AsyncClient, ${providerName}Client> context) {
return new ComputeServiceContextImpl<${providerName}AsyncClient, ${providerName}Client>(computeService, context);
}
@Provides
@Singleton
@Named("NOT_RUNNING")
protected Predicate<SshClient> runScriptRunning(RunScriptRunning stateRunning) {
return new RetryablePredicate<SshClient>(Predicates.not(stateRunning), 600, 3,
TimeUnit.SECONDS);
}
@Provides
@Singleton
Location getDefaultLocation(Map<String, ? extends Location> locations) {
return locations.get("SANFRANCISCO");
}
@Provides
@Singleton
Map<String, ? extends Location> getDefaultLocations(${providerName}Client sync, LogHolder holder,
Function<ComputeMetadata, String> indexer) {
final Set<Location> locations = Sets.newHashSet();
holder.logger.debug(">> providing locations");
locations.add(new LocationImpl(LocationScope.ZONE, "SANFRANCISCO", "San Francisco, CA", null,
true));
holder.logger.debug("<< locations(%d)", locations.size());
return Maps.uniqueIndex(locations, new Function<Location, String>() {
@Override
public String apply(Location from) {
return from.getId();
}
});
}
@Provides
@Singleton
protected Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
protected Map<String, ? extends Size> provideSizes(${providerName}Client sync,
Map<String, ? extends Image> images, LogHolder holder,
Function<ComputeMetadata, String> indexer) throws InterruptedException,
TimeoutException, ExecutionException {
final Set<Size> sizes = Sets.newHashSet();
holder.logger.debug(">> providing sizes");
/*
* TODO: implement
*/
holder.logger.debug("<< sizes(%d)", sizes.size());
return Maps.uniqueIndex(sizes, indexer);
}
private static class LogHolder {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
}
@Provides
@Singleton
protected Map<String, ? extends Image> provideImages(final ${providerName}Client sync, LogHolder holder,
Function<ComputeMetadata, String> indexer, Location location)
throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
/*
* TODO: implement
*/
holder.logger.debug("<< images(%d)", images.size());
return Maps.uniqueIndex(images, indexer);
}
}

View File

@ -0,0 +1,78 @@
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package}.config;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.Date;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.gson.*;
import ${package}.${providerName}AsyncClient;
import ${package}.${providerName}Client;
import org.jclouds.http.functions.config.ParserModule.DateAdapter;
import org.jclouds.lifecycle.Closer;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl;
import ${package}.${providerName};
import ${package}.reference.${providerName}Constants;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* Configures the ${providerName} connection, including logging and http transport.
*
* @author ${author}
*/
public class ${providerName}ContextModule extends AbstractModule {
@Override
protected void configure() {
bind(DateAdapter.class).to(DateSecondsAdapter.class);
}
@Provides
@Singleton
RestContext<${providerName}AsyncClient, ${providerName}Client> provideContext(Closer closer, ${providerName}AsyncClient asyncApi,
${providerName}Client syncApi, @${providerName} URI endPoint, @Named(${providerName}Constants.PROPERTY_${ucaseProviderName}_USER) String account) {
return new RestContextImpl<${providerName}AsyncClient, ${providerName}Client>(closer, asyncApi, syncApi, endPoint, account);
}
@Singleton
public static class DateSecondsAdapter implements DateAdapter {
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.getTime());
}
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String toParse = json.getAsJsonPrimitive().getAsString();
return new Date(Long.valueOf(toParse));
}
}
}

View File

@ -0,0 +1,87 @@
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package}.config;
import java.net.URI;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.GridO;
import org.jclouds.concurrent.ExpirableSupplier;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.RequiresHttp;
import org.jclouds.logging.Logger;
import org.jclouds.reference.GridOConstants;
import org.jclouds.rest.ConfiguresRestClient;
import com.google.common.base.Supplier;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import static ${package}.reference.${providerName}Constants.*;
/**
* Configures the ${providerName} connection.
*
* @author ${author}
*/
@RequiresHttp
@ConfiguresRestClient
public class ${providerName}RestClientModule extends AbstractModule {
/*
* TODO: modify configuration for ${providerName}Client
*/
@Resource
protected Logger logger = Logger.NULL;
@Override
protected void configure() {
requestInjection(this);
}
@Provides
@Singleton
@${providerName}
protected URI provideURI(@Named(${providerName}Constants.PROPERTY_${ucaseProviderName}_ENDPOINT) String endpoint) {
return URI.create(endpoint);
}
// borrowing concurrency code to ensure that caching takes place properly
@Provides
@TimeStamp
Supplier<Long> provideTimeStampCache(
@Named(PROPERTY_${ucaseProviderName}_SESSIONINTERVAL) long seconds) {
return new ExpirableSupplier<Long>(new Supplier<Long>() {
public Long get() {
return System.currentTimeMillis() / 1000;
}
}, seconds, TimeUnit.SECONDS);
}
}

View File

@ -0,0 +1,46 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package}.internal;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import ${package}.${providerName}AsyncClient;
/**
* @author ${author}
*/
@Singleton
public class ${providerName}AsyncClientImpl implements ${providerName}AsyncClient {
@Inject
public ${providerName}AsyncClientImpl() {
}
/*
* TODO: implement ${providerName}AsyncClient
*/
}

View File

@ -0,0 +1,42 @@
#set( $lcaseProviderName = ${providerName.toLowerCase()} )
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package}.reference;
/**
* Configuration properties and constants used in ${providerName} connections.
*
* @author Adrian Cole
*/
public interface ${providerName}Constants {
public static final String PROPERTY_${ucaseProviderName}_ENDPOINT = "jclouds.${lcaseProviderName}.endpoint";
public static final String PROPERTY_${ucaseProviderName}_USER = "jclouds.${lcaseProviderName}.user";
public static final String PROPERTY_${ucaseProviderName}_KEY = "jclouds.${lcaseProviderName}.key";
/**
* how long do we wait before obtaining a new timestamp for requests.
*/
public static final String PROPERTY_${ucaseProviderName}_SESSIONINTERVAL = "jclouds.${lcaseProviderName}.sessioninterval";
}

View File

@ -0,0 +1,53 @@
#set( $lcaseProviderName = ${providerName.toLowerCase()} )
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package ${package};
import com.google.common.io.Resources;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.Properties;
import static org.testng.Assert.assertEquals;
/**
* @author ${author}
*/
@Test(groups = "unit", testName = "compute.PropertiesTest")
public class PropertiesTest {
private Properties properties;
@BeforeTest
public void setUp() throws IOException {
properties = new Properties();
properties.load(Resources.newInputStreamSupplier(Resources.getResource("compute.properties"))
.getInput());
}
public void test${providerName}() {
assertEquals(properties.getProperty("${lcaseProviderName}.contextbuilder"),
${providerName}ContextBuilder.class.getName());
assertEquals(properties.getProperty("${lcaseProviderName}.propertiesbuilder"),
${providerName}PropertiesBuilder.class.getName());
}
}

View File

@ -0,0 +1,109 @@
#set( $lcaseProviderName = ${providerName.toLowerCase()} )
#set( $camelCaseProviderName = "${providerName.substring(0, 1).toLowerCase()}${providerName.substring(1)}" )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package ${package};
import static org.jclouds.compute.domain.OsFamily.CENTOS;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Map;
import org.jclouds.compute.BaseComputeServiceLiveTest;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.rest.RestContext;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
/**
* @author ${author}
*/
@Test(groups = "live", enabled = true, sequential = true, testName = "${lcaseProviderName}.${providerName}ComputeServiceLiveTest")
public class ${providerName}ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
@BeforeClass
@Override
public void setServiceDefaults() {
service = "${lcaseProviderName}";
}
@Override
public String buildScript() {
return new StringBuilder()
.append("TODO: define build script")
.toString();
}
protected Template buildTemplate(TemplateBuilder templateBuilder) {
return templateBuilder.osFamily(CENTOS).imageDescriptionMatches("TODO: insert image description").smallest()
.build();
}
@Override
protected JschSshClientModule getSshModule() {
return new JschSshClientModule();
}
public void testAssignability() throws Exception {
@SuppressWarnings("unused")
RestContext<${providerName}AsyncClient, ${providerName}Client> ${camelCaseProviderName}Context =
new ComputeServiceContextFactory().createContext(service, user, password).getProviderSpecificContext();
}
@Test(enabled = true)
public void endToEndComputeServiceTest() {
/*
* TODO: adapt the following sample test for ${providerName}
*/
ComputeService service = context.getComputeService();
Template t = service.templateBuilder().minRam(1024).imageId("1532").build();
assertEquals(t.getImage().getId(), "1532");
service.runNodesWithTag(this.service, 1, t);
Map<String, ? extends ComputeMetadata> nodes = service.getNodes();
ComputeMetadata node = Iterables.find(nodes.values(), new Predicate<ComputeMetadata>() {
@Override
public boolean apply(ComputeMetadata computeMetadata) {
return computeMetadata.getName().startsWith(${providerName}ComputeServiceLiveTest.this.service);
}
});
NodeMetadata nodeMetadata = service.getNodeMetadata(node);
assertEquals(nodeMetadata.getPublicAddresses().size(), 1,
"There must be 1 public address for the node");
assertTrue(nodeMetadata.getName().startsWith(this.service));
service.rebootNode(nodeMetadata); // blocks until finished
assertEquals(service.getNodeMetadata(nodeMetadata).getState(), NodeState.RUNNING);
service.destroyNode(nodeMetadata);
}
}

View File

@ -0,0 +1,94 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package ${package};
import java.io.IOException;
import java.net.URI;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* End to end live test for ${providerName}
*
* @author ${author}
*/
@Test(groups = "live", testName = "${lcaseProviderName}.${providerName}LiveTest")
public class ${providerName}LiveTest {
private ${providerName}Client client;
@BeforeGroups(groups = { "live" })
public void setupClient() {
String endpoint = checkNotNull(System.getProperty("jclouds.test.endpoint"),
"jclouds.test.endpoint");
String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
client = new ${providerName}ContextBuilder(
new ${providerName}PropertiesBuilder(URI.create(endpoint), user, password).build())
.withModules(new Log4JLoggingModule()).buildContext().getApi();
}
/**
* Tests server start, reboot and deletion.
* TODO: describe additional services tested
*/
@Test(enabled=true)
public void testServerLifecycle() {
/*
* TODO: implement
*/
}
/**
* Tests common server image operations.
*/
@Test(enabled=true)
public void testImageLifecycle() {
/*
* TODO: implement
*/
}
@Test(enabled=true)
public void testShellAccess() throws IOException {
/*
* TODO: implement
*/
}
/**
* In case anything went wrong during the tests, removes the objects
* created in the tests.
*/
@AfterTest
public void cleanup() {
/*
* TODO: implement
*/
}
}

View File

@ -0,0 +1,117 @@
#set( $lcaseProviderName = ${providerName.toLowerCase()} )
#set( $ucaseProviderName = ${providerName.toUpperCase()} )
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package ${package}.config;
import static org.testng.Assert.assertEquals;
import static com.google.common.util.concurrent.Executors.sameThreadExecutor;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.http.functions.config.ParserModule.DateAdapter;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.http.handlers.RedirectionRetryHandler;
import org.jclouds.logging.Logger;
import org.jclouds.logging.Logger.LoggerFactory;
import ${package}.reference.${providerName}Constants;
import org.jclouds.util.Jsr330;
import org.jclouds.Constants;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* @author ${author}
*/
@Test(groups = "unit", testName = "${lcaseProviderName}.${providerName}ContextModule")
public class ${providerName}ContextModuleTest {
Injector createInjector() {
return Guice.createInjector(new ${providerName}RestClientModule(), new ${providerName}ContextModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Jsr330.named(${providerName}Constants.PROPERTY_${ucaseProviderName}_USER)).to(
"user");
bindConstant().annotatedWith(Jsr330.named(${providerName}Constants.PROPERTY_${ucaseProviderName}_KEY))
.to("password");
bindConstant().annotatedWith(Jsr330.named(${providerName}Constants.PROPERTY_${ucaseProviderName}_ENDPOINT))
.to("http://localhost");
bindConstant().annotatedWith(Jsr330.named(${providerName}Constants.PROPERTY_${ucaseProviderName}_SESSIONINTERVAL))
.to("30");
bindConstant().annotatedWith(Jsr330.named(Constants.PROPERTY_MAX_CONNECTIONS_PER_HOST))
.to("1");
bindConstant().annotatedWith(Jsr330.named(Constants.PROPERTY_MAX_CONNECTIONS_PER_CONTEXT))
.to("0");
bindConstant().annotatedWith(Jsr330.named(Constants.PROPERTY_IO_WORKER_THREADS))
.to("1");
bindConstant().annotatedWith(Jsr330.named(Constants.PROPERTY_USER_THREADS))
.to("1");
bindConstant().annotatedWith(Jsr330.named(Constants.PROPERTY_CONNECTION_TIMEOUT))
.to("30");
bindConstant().annotatedWith(Jsr330.named(Constants.PROPERTY_SO_TIMEOUT))
.to("10");
bind(Logger.LoggerFactory.class).toInstance(new LoggerFactory() {
public Logger getLogger(String category) {
return Logger.NULL;
}
});
super.configure();
}
}, new ParserModule(), new JavaUrlHttpCommandExecutorServiceModule(),
new ExecutorServiceModule(sameThreadExecutor(), sameThreadExecutor()));
}
@Test
void testServerErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getServerErrorHandler().getClass(),
"TODO: insert expected error handler class");
}
@Test
void testDateTimeAdapter() {
assertEquals(this.createInjector().getInstance(DateAdapter.class).getClass(),
${providerName}ContextModule.DateSecondsAdapter.class);
}
@Test
void testClientErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getClientErrorHandler().getClass(),
"TODO: insert expected error handler class");
}
@Test
void testClientRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getClientErrorRetryHandler(), HttpRetryHandler.NEVER_RETRY);
}
@Test
void testRedirectionRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getRedirectionRetryHandler().getClass(), RedirectionRetryHandler.class);
}
}

View File

@ -0,0 +1,145 @@
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
====================================================================
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
====================================================================
-->
<!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="COMPUTEFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="target/test-data/jclouds-compute.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${symbol_escape}n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category]
(Thread:NDC) Message${symbol_escape}n <param name="ConversionPattern"
value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
-->
</layout>
</appender>
<appender name="ASYNCCOMPUTE" class="org.apache.log4j.AsyncAppender">
<appender-ref ref="COMPUTEFILE" />
</appender>
<!-- 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${symbol_dollar}{symbol_escape}n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_dollar}{symbol_escape}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${symbol_dollar}{symbol_escape}n -->
<param name="ConversionPattern" value="%d %-5p [%c] (%t) %m%n" />
<!--
The full pattern: Date MS Priority [Category] (Thread:NDC) Message${symbol_dollar}{symbol_escape}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.compute">
<priority value="TRACE" />
<appender-ref ref="ASYNCCOMPUTE" />
</category>
<!-- ======================= -->
<!-- Setup the Root category -->
<!-- ======================= -->
<root>
<priority value="WARN" />
</root>
</log4j:configuration>

View File

@ -49,7 +49,6 @@
<directory>src/test/resources</directory> <directory>src/test/resources</directory>
<includes> <includes>
<include>**/*.xml</include> <include>**/*.xml</include>
<include>**/*.json</include>
</includes> </includes>
</fileSet> </fileSet>
<fileSet filtered="true" encoding="UTF-8"> <fileSet filtered="true" encoding="UTF-8">

View File

@ -44,18 +44,9 @@
*/ */
package ${package}; package ${package};
import java.util.SortedSet;
import com.google.common.util.concurrent.ListenableFuture;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.annotations.Endpoint; import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
import ${package}.domain.Status;
import ${package}.functions.ParseStatusesFromJsonResponse;
/** /**
* Provides asynchronous access to ${clientName} via their REST API. * Provides asynchronous access to ${clientName} via their REST API.
@ -68,10 +59,7 @@ import ${package}.functions.ParseStatusesFromJsonResponse;
@Endpoint(${clientName}.class) @Endpoint(${clientName}.class)
@RequestFilters(BasicAuthentication.class) @RequestFilters(BasicAuthentication.class)
public interface ${clientName}AsyncClient { public interface ${clientName}AsyncClient {
/*
@GET * TODO: define interface methods for ${clientName}
@ResponseParser(ParseStatusesFromJsonResponse.class) */
@Path("/statuses/mentions.json")
ListenableFuture<SortedSet<Status>> getMyMentions();
} }

View File

@ -44,23 +44,21 @@
*/ */
package ${package}; package ${package};
import java.util.SortedSet;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import ${package}.domain.Status;
/** /**
* Provides synchronous access to ${clientName}. * Provides synchronous access to ${clientName}.
* <p/> * <p/>
* *
* @see ${clientName}AsyncClient * @see ${clientName}AsyncClient
* @see <a href="TODO: insert URL of client documentation" /> * @see <a href="TODO: insert URL of ${clientName} documentation" />
* @author ${author} * @author ${author}
*/ */
@Timeout(duration = 4, timeUnit = TimeUnit.SECONDS) @Timeout(duration = 4, timeUnit = TimeUnit.SECONDS)
public interface ${clientName}Client { public interface ${clientName}Client {
/*
SortedSet<Status> getMyMentions(); * TODO: define interface methods for ${clientName}
*/
} }

View File

@ -49,7 +49,6 @@ import javax.inject.Singleton;
import org.jclouds.http.functions.config.ParserModule.CDateAdapter; import org.jclouds.http.functions.config.ParserModule.CDateAdapter;
import org.jclouds.http.functions.config.ParserModule.DateAdapter; import org.jclouds.http.functions.config.ParserModule.DateAdapter;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.lifecycle.Closer; import org.jclouds.lifecycle.Closer;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl; import org.jclouds.rest.internal.RestContextImpl;

View File

@ -1,223 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*Date
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package}.domain;
import java.util.Date;
import com.google.gson.annotations.SerializedName;
/**
*
* @author ${author}
*
*/
public class Status implements Comparable<Status> {
@SerializedName("created_at")
private Date createdAt;
private boolean favorited;
private String geo;
private long id;
@SerializedName("in_reply_to_screen_name")
private String inReplyToScreenName;
@SerializedName("in_reply_to_status_id")
private Integer inReplyToStatusId;
@SerializedName("in_reply_to_user_id")
private Integer inReplyToUserId;
private String source;
private String text;
private boolean truncated;
private User user;
public Status() {
}
public Status(Date createdAt, boolean favorited, String geo, long id,
String inReplyToScreenName, Integer inReplyToStatusId, Integer inReplyToUserId,
String source, String text, boolean truncated, User user) {
this.createdAt = createdAt;
this.favorited = favorited;
this.geo = geo;
this.id = id;
this.inReplyToScreenName = inReplyToScreenName;
this.inReplyToStatusId = inReplyToStatusId;
this.inReplyToUserId = inReplyToUserId;
this.source = source;
this.text = text;
this.truncated = truncated;
this.user = user;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((createdAt == null) ? 0 : createdAt.hashCode());
result = prime * result + (int) (id ^ (id >>> 32));
result = prime * result + ((text == null) ? 0 : text.hashCode());
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Status other = (Status) obj;
if (createdAt == null) {
if (other.createdAt != null)
return false;
} else if (!createdAt.equals(other.createdAt))
return false;
if (id != other.id)
return false;
if (text == null) {
if (other.text != null)
return false;
} else if (!text.equals(other.text))
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public boolean isTruncated() {
return truncated;
}
public void setTruncated(boolean truncated) {
this.truncated = truncated;
}
public Integer getInReplyToStatusId() {
return inReplyToStatusId;
}
public void setInReplyToStatusId(Integer inReplyToStatusId) {
this.inReplyToStatusId = inReplyToStatusId;
}
public Integer getInReplyToUserId() {
return inReplyToUserId;
}
public void setInReplyToUserId(Integer inReplyToUserId) {
this.inReplyToUserId = inReplyToUserId;
}
public boolean isFavorited() {
return favorited;
}
public void setFavorited(boolean favorited) {
this.favorited = favorited;
}
public String getInReplyToScreenName() {
return inReplyToScreenName;
}
public void setInReplyToScreenName(String inReplyToScreenName) {
this.inReplyToScreenName = inReplyToScreenName;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public int compareTo(Status o) {
return (int) ((this == o) ? 0 : id + "".compareTo(o.id + ""));
}
public void setGeo(String geo) {
this.geo = geo;
}
public String getGeo() {
return geo;
}
}

View File

@ -1,390 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package}.domain;
import java.net.URI;
import java.util.Date;
import com.google.gson.annotations.SerializedName;
/**
*
* @author ${author}
*/
public class User implements Comparable<User> {
@SerializedName("created_at")
private Date createdAt;
private String description;
@SerializedName("favourites_count")
private int favouritesCount;
@SerializedName("followers_count")
private int followersCount;
private boolean following;
@SerializedName("friends_count")
private int friendsCount;
@SerializedName("geo_enabled")
private boolean geoEnabled;
private long id;
private String location;
private String name;
private boolean notifications;
@SerializedName("profile_background_color")
private String profileBackgroundColor;
@SerializedName("profile_background_image_url")
private URI profileBackgroundImageUrl;
@SerializedName("profile_background_tile")
private boolean profileBackgroundTile;
@SerializedName("profile_image_url")
private URI profileImageUrl;
@SerializedName("profile_link_color")
private String profileLinkColor;
@SerializedName("profile_sidebar_border_color")
private String profileSidebarBorderColor;
@SerializedName("profile_sidebar_fill_color")
private String profileSidebarFillColor;
@SerializedName("profile_text_color")
private String profileTextColor;
@SerializedName("protected")
private boolean isProtected;
@SerializedName("screen_name")
private String screenName;
@SerializedName("statuses_count")
private int statusesCount;
@SerializedName("time_zone")
private String timeZone;
private URI url;
@SerializedName("utc_offset")
private int utcOffset;
private boolean verified;
public User() {
}
public User(Date createdAt, String description, int favouritesCount, int followersCount,
boolean following, int friendsCount, boolean geoEnabled, long id, String location,
String name, boolean notifications, String profileBackgroundColor,
URI profileBackgroundImageUrl, boolean profileBackgroundTile, URI profileImageUrl,
String profileLinkColor, String profileSidebarBorderColor,
String profileSidebarFillColor, String profileTextColor, boolean isProtected,
String screenName, int statusesCount, String timeZone, URI url, int utcOffset,
boolean verified) {
this.createdAt = createdAt;
this.description = description;
this.favouritesCount = favouritesCount;
this.followersCount = followersCount;
this.following = following;
this.friendsCount = friendsCount;
this.setGeoEnabled(geoEnabled);
this.id = id;
this.location = location;
this.name = name;
this.notifications = notifications;
this.profileBackgroundColor = profileBackgroundColor;
this.profileBackgroundImageUrl = profileBackgroundImageUrl;
this.profileBackgroundTile = profileBackgroundTile;
this.profileImageUrl = profileImageUrl;
this.profileLinkColor = profileLinkColor;
this.profileSidebarBorderColor = profileSidebarBorderColor;
this.profileSidebarFillColor = profileSidebarFillColor;
this.profileTextColor = profileTextColor;
this.isProtected = isProtected;
this.screenName = screenName;
this.statusesCount = statusesCount;
this.timeZone = timeZone;
this.url = url;
this.utcOffset = utcOffset;
this.verified = verified;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((screenName == null) ? 0 : screenName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (screenName == null) {
if (other.screenName != null)
return false;
} else if (!screenName.equals(other.screenName))
return false;
return true;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getScreenName() {
return screenName;
}
public void setScreenName(String screenName) {
this.screenName = screenName;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public URI getProfileImageUrl() {
return profileImageUrl;
}
public void setProfileImageUrl(URI profileImageUrl) {
this.profileImageUrl = profileImageUrl;
}
public URI getUrl() {
return url;
}
public void setUrl(URI url) {
this.url = url;
}
public boolean isProtected() {
return isProtected;
}
public void setProtected(boolean isProtected) {
this.isProtected = isProtected;
}
public int getFollowersCount() {
return followersCount;
}
public void setFollowersCount(int followersCount) {
this.followersCount = followersCount;
}
public String getProfileBackgroundColor() {
return profileBackgroundColor;
}
public void setProfileBackgroundColor(String profileBackgroundColor) {
this.profileBackgroundColor = profileBackgroundColor;
}
public String getProfileTextColor() {
return profileTextColor;
}
public void setProfileTextColor(String profileTextColor) {
this.profileTextColor = profileTextColor;
}
public String getProfileLinkColor() {
return profileLinkColor;
}
public void setProfileLinkColor(String profileLinkColor) {
this.profileLinkColor = profileLinkColor;
}
public String getProfileSidebarFillColor() {
return profileSidebarFillColor;
}
public void setProfileSidebarFillColor(String profileSidebarFillColor) {
this.profileSidebarFillColor = profileSidebarFillColor;
}
public String getProfileSidebarBorderColor() {
return profileSidebarBorderColor;
}
public void setProfileSidebarBorderColor(String profileSidebarBorderColor) {
this.profileSidebarBorderColor = profileSidebarBorderColor;
}
public int getFriendsCount() {
return friendsCount;
}
public void setFriendsCount(int friendsCount) {
this.friendsCount = friendsCount;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public int getFavouritesCount() {
return favouritesCount;
}
public void setFavouritesCount(int favouritesCount) {
this.favouritesCount = favouritesCount;
}
public int getUtcOffset() {
return utcOffset;
}
public void setUtcOffset(int utcOffset) {
this.utcOffset = utcOffset;
}
public String getTimeZone() {
return timeZone;
}
public void setTimeZone(String timeZone) {
this.timeZone = timeZone;
}
public URI getProfileBackgroundImageUrl() {
return profileBackgroundImageUrl;
}
public void setProfileBackgroundImageUrl(URI profileBackgroundImageUrl) {
this.profileBackgroundImageUrl = profileBackgroundImageUrl;
}
public boolean isProfileBackgroundTile() {
return profileBackgroundTile;
}
public void setProfileBackgroundTile(boolean profileBackgroundTile) {
this.profileBackgroundTile = profileBackgroundTile;
}
public int getStatusesCount() {
return statusesCount;
}
public void setStatusesCount(int statusesCount) {
this.statusesCount = statusesCount;
}
public boolean isNotifications() {
return notifications;
}
public void setNotifications(boolean notifications) {
this.notifications = notifications;
}
public boolean isFollowing() {
return following;
}
public void setFollowing(boolean following) {
this.following = following;
}
public boolean isVerified() {
return verified;
}
public void setVerified(boolean verified) {
this.verified = verified;
}
public int compareTo(User o) {
if (screenName == null)
return -1;
return (this == o) ? 0 : screenName.compareTo(o.screenName);
}
public void setGeoEnabled(boolean geoEnabled) {
this.geoEnabled = geoEnabled;
}
public boolean isGeoEnabled() {
return geoEnabled;
}
}

View File

@ -1,84 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package}.functions;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.util.SortedSet;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ParseJson;
import ${package}.domain.Status;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* This parses {@link Status} from a json string.
*
* @author ${author}
*/
@Singleton
public class ParseStatusesFromJsonResponse extends ParseJson<SortedSet<Status>> {
@Inject
public ParseStatusesFromJsonResponse(Gson gson) {
super(gson);
}
public SortedSet<Status> apply(InputStream stream) {
Type setType = new TypeToken<SortedSet<Status>>() {
}.getType();
try {
return gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e);
}
}
}

View File

@ -60,7 +60,6 @@ import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.rest.RestClientTest; import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import ${package}.functions.ParseStatusesFromJsonResponse;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -85,7 +84,7 @@ public class ${clientName}AsyncClientTest extends RestClientTest<${clientName}As
assertHeadersEqual(httpMethod, ""); assertHeadersEqual(httpMethod, "");
assertPayloadEquals(httpMethod, null); assertPayloadEquals(httpMethod, null);
assertResponseParserClassEquals(method, httpMethod, ParseStatusesFromJsonResponse.class); assertResponseParserClassEquals(method, httpMethod, "TODO: insert expected response class");
assertSaxResponseParserClassEquals(method, null); assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null); assertExceptionParserClassEquals(method, null);

View File

@ -47,10 +47,7 @@ package ${package};
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.SortedSet;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import ${package}.domain.Status;
import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -73,10 +70,7 @@ public class ${clientName}ClientLiveTest {
.getApi(); .getApi();
} }
@Test /*
public void testGetMyMentions() { * TODO: add tests for ${clientName} interface methods
SortedSet<Status> response = connection.getMyMentions(); */
assert (response.size() > 0);
}
} }

View File

@ -1,170 +0,0 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package ${package}.functions;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.SortedSet;
import org.jclouds.http.functions.config.ParserModule;
import ${package}.domain.Status;
import ${package}.domain.User;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSortedSet;
import com.google.gson.Gson;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseStatusesFromJsonResponse}
*
* @author ${author}
*/
@Test(groups = "unit", testName = "twitter.ParseStatusesFromJsonResponseTest")
public class ParseStatusesFromJsonResponseTest {
Injector i = Guice.createInjector(new ParserModule() {
@Override
protected void configure() {
bind(DateAdapter.class).to(CDateAdapter.class);
super.configure();
}
});
DateService dateService = new SimpleDateFormatDateService();
public void testApplyInputStreamDetails() throws UnknownHostException {
InputStream is = getClass().getResourceAsStream("/test_mentions.json");
SortedSet<Status> expects = ImmutableSortedSet
.of(
new Status(
dateService.cDateParse("Sat Oct 31 01:45:14 +0000 2009"),
false,
null,
5303839785l,
null,
null,
null,
"<a href=${symbol_escape}"http://www.tweetdeck.com/${symbol_escape}" rel=${symbol_escape}"nofollow${symbol_escape}">TweetDeck</a>",
"RT @jclouds: come find out about ${symbol_pound}cloud storage and how to access it from ${symbol_pound}java in palo alto this Tuesday: http://is.gd/4IFA9",
false,
new User(
dateService.cDateParse("Sat Apr 26 06:13:08 +0000 2008"),
"Jack of All Trades: Dad to anZel and Arden, VMware, vCloud, Security, Compliance, Former Developer",
0,
474,
false,
199,
false,
14540593,
"Bay Area, CA",
"Jian Zhen",
false,
"C6E2EE",
URI
.create("http://s.twimg.com/a/1256778767/images/themes/theme2/bg.gif"),
false,
URI
.create("http://a3.twimg.com/profile_images/64445411/30b8b19_bigger_normal.jpg"),
"1F98C7", "C6E2EE", "DAECF4", "663B12", false, "zhenjl",
1981, "Pacific Time (US & Canada)", URI
.create("http://zhen.org"), -28800, false)),
new Status(
dateService.cDateParse("Sat Oct 31 09:35:27 +0000 2009"),
false,
null,
5310690603l,
null,
null,
null,
"<a href=${symbol_escape}"http://www.tweetdeck.com/${symbol_escape}" rel=${symbol_escape}"nofollow${symbol_escape}">TweetDeck</a>",
"RT @jclouds: live multi ${symbol_pound}cloud demo of jclouds connecting to 3 storage clouds from google appengine http://is.gd/4IXMh",
false,
new User(
dateService.cDateParse("Tue Apr 28 15:29:42 +0000 2009"),
"Some random guy who seems to care about cloud collisions at siliconANGLE.com",
245,
572,
false,
325,
false,
36093693,
"San Francisco ",
"James Watters",
false,
"C6E2EE",
URI
.create("http://a1.twimg.com/profile_background_images/24067016/17361976.jpg"),
true,
URI
.create("http://a3.twimg.com/profile_images/445071063/tiktaalik-transitional-fossil_normal.png"),
"1F98C7",
"C6E2EE",
"DAECF4",
"663B12",
false,
"wattersjames",
1964,
"Pacific Time (US & Canada)",
URI
.create("http://siliconangle.net/ver2/author/jwatters/"),
-28800, false))
);
ParseStatusesFromJsonResponse parser = new ParseStatusesFromJsonResponse(i
.getInstance(Gson.class));
SortedSet<Status> response = parser.apply(is);
assertEquals(response, expects);
}
}

View File

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

View File

@ -33,5 +33,6 @@
<name>jclouds Maven archetypes</name> <name>jclouds Maven archetypes</name>
<modules> <modules>
<module>json-client-archetype</module> <module>json-client-archetype</module>
<module>compute-service-archetype</module>
</modules> </modules>
</project> </project>

View File

@ -4,49 +4,39 @@
(:import [org.jclouds.blobstore BlobStoreContextFactory] (:import [org.jclouds.blobstore BlobStoreContextFactory]
[java.io ByteArrayOutputStream])) [java.io ByteArrayOutputStream]))
(def stub-context (.createContext (BlobStoreContextFactory.) "transient" "" "")) (defn clean-stub-fixture
(def stub-blobstore (.getBlobStore stub-context)) "This should allow basic tests to easily be run with another service."
[service account key & options]
(fn [f]
(with-blobstore [(apply blobstore service account key options)]
(doseq [container (containers)]
(delete-container (.getName container)))
(f))))
(defn clean-stub-fixture [f] (use-fixtures :each (clean-stub-fixture "transient" "" ""))
(with-blobstore [stub-blobstore]
(doseq [container (containers)]
(delete-container (.getName container)))
(f)))
(use-fixtures :each clean-stub-fixture)
(deftest blobstore?-test (deftest blobstore?-test
(is (blobstore? stub-blobstore))) (is (blobstore? *blobstore*)))
(deftest blobstore-context?-test
(is (blobstore-context? stub-context)))
(deftest blobstore-context-test
(is (= stub-context (blobstore-context stub-blobstore))))
(deftest as-blobstore-test (deftest as-blobstore-test
(is (blobstore? (blobstore "transient" "user" "password"))) (is (blobstore? (blobstore "transient" "user" "password")))
(is (blobstore? (as-blobstore stub-blobstore))) (is (blobstore? (as-blobstore *blobstore*)))
(is (blobstore? (as-blobstore stub-context)))) (is (blobstore? (as-blobstore (blobstore-context *blobstore*)))))
(deftest with-blobstore-test
(with-blobstore [stub-blobstore]
(is (= stub-blobstore *blobstore*))))
(deftest create-existing-container-test (deftest create-existing-container-test
(is (not (container-exists? stub-blobstore ""))) (is (not (container-exists? *blobstore* "")))
(is (not (container-exists? ""))) (is (not (container-exists? "")))
(is (create-container stub-blobstore "fred")) (is (create-container *blobstore* "fred"))
(is (container-exists? stub-blobstore "fred"))) (is (container-exists? *blobstore* "fred")))
(deftest create-container-test (deftest create-container-test
(is (create-container stub-blobstore "fred")) (is (create-container *blobstore* "fred"))
(is (container-exists? stub-blobstore "fred"))) (is (container-exists? *blobstore* "fred")))
(deftest containers-test (deftest containers-test
(is (empty? (containers stub-blobstore))) (is (empty? (containers *blobstore*)))
(is (create-container stub-blobstore "fred")) (is (create-container *blobstore* "fred"))
(is (= 1 (count (containers stub-blobstore))))) (is (= 1 (count (containers *blobstore*)))))
(deftest list-container-test (deftest list-container-test
(is (create-container "container")) (is (create-container "container"))
@ -92,28 +82,24 @@
;; TODO: more tests involving blob-specific functions ;; TODO: more tests involving blob-specific functions
(deftest corruption-hunt (deftest corruption-hunt
(let [service "transient" (let [container-name "test"
account ""
secret-key ""
container-name "test"
name "work-file" name "work-file"
upload-filename "/home/phil/work-file"
total-downloads 100 total-downloads 100
threads 10 threads 10]
blob-s (blobstore service account secret-key)]
;; upload ;; upload
(create-container blob-s container-name) (create-container container-name)
(when-not (blob-exists? blob-s container-name name) (when-not (blob-exists? container-name name)
(create-blob blob-s container-name name (let [data-stream (java.io.ByteArrayOutputStream.)]
(java.io.File. upload-filename))) (dotimes [i 5000000] (.write data-stream i))
(create-blob container-name name (.toByteArray data-stream))))
;; download ;; download
(let [total (atom total-downloads)] (let [total (atom total-downloads)]
(defn new-agent [] (defn new-agent []
(agent name)) (agent name))
(defn dl-and-restart [file] (defn dl-and-restart [blob-s file]
(when-not (<= @total 0) (when-not (<= @total 0)
(with-open [baos (java.io.ByteArrayOutputStream.)] (with-open [baos (java.io.ByteArrayOutputStream.)]
(try (try
@ -124,14 +110,14 @@
(.write of (.toByteArray baos))) (.write of (.toByteArray baos)))
(throw e)))) (throw e))))
(swap! total dec) (swap! total dec)
(send *agent* dl-and-restart) (send *agent* (partial dl-and-restart blob-s))
file)) file))
(defn start-agents [] (defn start-agents []
(let [agents (map (fn [_] (new-agent)) (let [agents (map (fn [_] (new-agent))
(range threads))] (range threads))]
(doseq [a agents] (doseq [a agents]
(send-off a dl-and-restart)) (send-off a (partial dl-and-restart *blobstore*)))
agents)) agents))
(let [agents (start-agents)] (let [agents (start-agents)]

View File

@ -25,17 +25,15 @@
under the License. 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"> --><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> <parent>
<groupId>org.jclouds</groupId> <groupId>org.jclouds</groupId>
<artifactId>jclouds-multi</artifactId> <artifactId>jclouds-project</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../project/pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-gogrid</artifactId> <artifactId>jclouds-gogrid</artifactId>
<name>jclouds GoGrid compute</name> <name>jclouds GoGrid compute</name>
<packaging>jar</packaging>
<description>jclouds components to access GoGrid</description> <description>jclouds components to access GoGrid</description>
<scm> <scm>
@ -53,6 +51,11 @@
<artifactId>jclouds-compute</artifactId> <artifactId>jclouds-compute</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-jsch</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>jclouds-compute</artifactId> <artifactId>jclouds-compute</artifactId>
@ -79,10 +82,5 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-jsch</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,21 +1,3 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
/** /**
* *
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com> * Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>

View File

@ -1,21 +1,3 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
/** /**
* *
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com> * Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>

View File

@ -279,7 +279,7 @@ public class GoGridLiveTest {
} }
@Test(enabled=true) @Test(enabled=true)
private void testShellAccess() throws IOException { public void testShellAccess() throws IOException {
final String nameOfServer = "Server" + String.valueOf(new Date().getTime()).substring(6); final String nameOfServer = "Server" + String.valueOf(new Date().getTime()).substring(6);
serversToDeleteAfterTheTests.add(nameOfServer); serversToDeleteAfterTheTests.add(nameOfServer);

View File

@ -135,7 +135,7 @@
<developer> <developer>
<name>Adrian Cole</name> <name>Adrian Cole</name>
<id>ferncam1</id> <id>ferncam1</id>
<email>adrian -at- jclouds.org</email> <email>adrian -at- jclouds -dot- org</email>
<organization>jclouds</organization> <organization>jclouds</organization>
<roles> <roles>
<role>Java Developer</role> <role>Java Developer</role>
@ -147,7 +147,7 @@
<developer> <developer>
<name>Hugo Duncan</name> <name>Hugo Duncan</name>
<id>hugoduncan</id> <id>hugoduncan</id>
<email>tabcdef -at- hugoduncan.org</email> <email>tabcdef -at- hugoduncan -dot- org</email>
<roles> <roles>
<role>Clojure Developer</role> <role>Clojure Developer</role>
</roles> </roles>
@ -156,7 +156,7 @@
<developer> <developer>
<name>Phil Hagelberg</name> <name>Phil Hagelberg</name>
<id>technomancy</id> <id>technomancy</id>
<email>phil -at- technomancy.us</email> <email>phil -at- technomancy -dot- us</email>
<roles> <roles>
<role>Clojure Developer</role> <role>Clojure Developer</role>
</roles> </roles>
@ -165,7 +165,7 @@
<developer> <developer>
<name>Ivan Meredith</name> <name>Ivan Meredith</name>
<id>barefootnz</id> <id>barefootnz</id>
<email>ivan -at- ivan.com</email> <email>ivan -at- ivan -dot- net -dot- nz</email>
<roles> <roles>
<role>Java Developer</role> <role>Java Developer</role>
</roles> </roles>
@ -174,7 +174,7 @@
<developer> <developer>
<name>Andrew Phillips</name> <name>Andrew Phillips</name>
<id>demobox</id> <id>demobox</id>
<email>aphillips -at- qrmedia.com</email> <email>aphillips -at- qrmedia -dot- com</email>
<roles> <roles>
<role>Apprentice</role> <role>Apprentice</role>
</roles> </roles>
@ -183,7 +183,7 @@
<developer> <developer>
<name>Alex Yarmuda</name> <name>Alex Yarmuda</name>
<id>alexstaytuned</id> <id>alexstaytuned</id>
<email>oleksiy.yarmula -at- gmail.com</email> <email>oleksiy -dot- yarmula -at- gmail -dot- com</email>
<roles> <roles>
<role>Java Developer</role> <role>Java Developer</role>
</roles> </roles>