You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by za...@apache.org on 2015/05/18 19:43:04 UTC

jclouds-labs git commit: JCLOUDS-826: Add skeleton and container operations

Repository: jclouds-labs
Updated Branches:
  refs/heads/master 969951d9b -> 83218e32d


JCLOUDS-826: Add skeleton and container operations


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/83218e32
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/83218e32
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/83218e32

Branch: refs/heads/master
Commit: 83218e32ddb8667f1752e552e64ea4887a5e9e7d
Parents: 969951d
Author: Roman Coedo <ro...@gmail.com>
Authored: Tue Apr 28 23:32:54 2015 +0200
Committer: Zack Shoylev <za...@rackspace.com>
Committed: Mon May 18 12:40:34 2015 -0500

----------------------------------------------------------------------
 .gitignore                                      |   1 +
 jdbc/pom.xml                                    | 149 ++++++++++++++
 .../java/org/jclouds/jdbc/JdbcApiMetadata.java  |  74 +++++++
 .../org/jclouds/jdbc/config/JPAInitializer.java |  29 +++
 .../jdbc/config/JdbcBlobStoreContextModule.java |  44 +++++
 .../java/org/jclouds/jdbc/entity/Container.java | 120 ++++++++++++
 .../validators/JdbcBlobKeyValidator.java        |  38 ++++
 .../validators/JdbcContainerNameValidator.java  |  38 ++++
 .../jdbc/repository/ContainerRepository.java    |  50 +++++
 .../jdbc/repository/GenericRepository.java      |  55 ++++++
 .../org/jclouds/jdbc/service/JdbcService.java   |  69 +++++++
 .../jdbc/strategy/JdbcStorageStrategy.java      | 194 +++++++++++++++++++
 .../org/jclouds/jdbc/util/JdbcBlobUtils.java    |  70 +++++++
 .../org/jclouds/jdbc/JdbcApiMetadataTest.java   |  28 +++
 .../org/jclouds/jdbc/JdbcBlobStoreTest.java     |  72 +++++++
 .../jclouds/jdbc/module/TestContextModule.java  |  29 +++
 .../jdbc/strategy/JdbcStorageStrategyTest.java  | 101 ++++++++++
 .../src/test/resources/META-INF/persistence.xml |  23 +++
 jdbc/src/test/resources/log4j.properties        |  25 +++
 pom.xml                                         |   1 +
 20 files changed, 1210 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 50f3821..336ad47 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,4 @@ atlassian-ide-plugin.xml
 .java-version
 *nb-configuration.xml
 *nbactions.xml
+Makefile

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/pom.xml
----------------------------------------------------------------------
diff --git a/jdbc/pom.xml b/jdbc/pom.xml
new file mode 100644
index 0000000..6b00c10
--- /dev/null
+++ b/jdbc/pom.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.jclouds.labs</groupId>
+    <artifactId>jclouds-labs</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.apache.jclouds.labs</groupId>
+  <artifactId>jdbc</artifactId>
+  <name>jclouds jdbc core</name>
+  <description>jclouds components to access jdbc</description>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <!-- This api has been written in a manner which requires Java language level 7. -->
+    <maven.compile.source>1.6</maven.compile.source>
+    <maven.compile.target>1.6</maven.compile.target>
+    <jclouds.osgi.export>org.jclouds.jdbc*;version="${project.version}"</jclouds.osgi.export>
+    <jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-blobstore</artifactId>
+      <version>${project.version}</version>
+      <type>jar</type>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds</groupId>
+      <artifactId>jclouds-blobstore</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-log4j</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.auto.service</groupId>
+      <artifactId>auto-service</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.inject.extensions</groupId>
+      <artifactId>guice-persist</artifactId>
+      <version>4.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.hibernate.javax.persistence</groupId>
+      <artifactId>hibernate-jpa-2.1-api</artifactId>
+      <version>1.0.0.Final</version>
+    </dependency>
+
+
+    <!-- Test Dependencies -->
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-entitymanager</artifactId>
+      <version>4.3.9.Final</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.hsqldb</groupId>
+      <artifactId>hsqldb</artifactId>
+      <version>2.3.2</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>integration</id>
+            <phase>integration-test</phase>
+            <goals>
+              <goal>test</goal>
+            </goals>
+            <configuration>
+              <threadCount>1</threadCount>
+              <excludes>
+                <exclude>**/*LiveTest.java</exclude>
+                <exclude>**/Base*Test.java</exclude>
+              </excludes>
+              <includes>
+                <include>**/*IntegrationTest.java</include>
+              </includes>
+              <systemPropertyVariables>
+                <jclouds.blobstore.httpstream.url>${jclouds.blobstore.httpstream.url}</jclouds.blobstore.httpstream.url>
+                <jclouds.blobstore.httpstream.md5>${jclouds.blobstore.httpstream.md5}</jclouds.blobstore.httpstream.md5>
+              </systemPropertyVariables>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>animal-sniffer-maven-plugin</artifactId>
+        <configuration>
+          <signature>
+            <groupId>org.codehaus.mojo.signature</groupId>
+            <artifactId>java16</artifactId>
+            <version>1.0</version>
+          </signature>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
+

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/JdbcApiMetadata.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/JdbcApiMetadata.java b/jdbc/src/main/java/org/jclouds/jdbc/JdbcApiMetadata.java
new file mode 100644
index 0000000..b478505
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/JdbcApiMetadata.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.apis.internal.BaseApiMetadata;
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.jdbc.config.JdbcBlobStoreContextModule;
+
+import java.net.URI;
+
+/**
+ * Implementation of {@link ApiMetadata} for jclouds Jdbc BlobStore
+ */
+@AutoService(ApiMetadata.class)
+public class JdbcApiMetadata extends BaseApiMetadata {
+
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public JdbcApiMetadata() {
+      super(new Builder());
+   }
+
+   protected JdbcApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static class Builder extends BaseApiMetadata.Builder<Builder> {
+
+      protected Builder() {
+         id("jdbc")
+         .name("Jdbc BlobStore")
+         .identityName("Unused")
+         .credentialName("unused")
+         .defaultEndpoint("http://localhost/transient")
+         .defaultIdentity("unused")
+         .defaultCredential("unused")
+         .version("1")
+         .documentation(URI.create("http://www.jclouds.org/documentation/userguide/blobstore-guide"))
+         .view(BlobStoreContext.class)
+         .defaultModules(ImmutableSet.<Class<? extends Module>>of(JdbcBlobStoreContextModule.class));
+      }
+
+      @Override
+      public JdbcApiMetadata build() {
+         return new JdbcApiMetadata(this);
+      }
+
+      @Override
+      protected Builder self() {
+         return this;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/config/JPAInitializer.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/config/JPAInitializer.java b/jdbc/src/main/java/org/jclouds/jdbc/config/JPAInitializer.java
new file mode 100644
index 0000000..60c14d4
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/config/JPAInitializer.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.config;
+
+import com.google.inject.Inject;
+import com.google.inject.persist.PersistService;
+
+public class JPAInitializer {
+
+   @Inject
+   private JPAInitializer(PersistService service) {
+      service.start();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/config/JdbcBlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/config/JdbcBlobStoreContextModule.java b/jdbc/src/main/java/org/jclouds/jdbc/config/JdbcBlobStoreContextModule.java
new file mode 100644
index 0000000..3619eb6
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/config/JdbcBlobStoreContextModule.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.config;
+
+import com.google.inject.AbstractModule;
+import org.jclouds.blobstore.BlobRequestSigner;
+import org.jclouds.blobstore.BlobStore;
+import org.jclouds.blobstore.LocalBlobRequestSigner;
+import org.jclouds.blobstore.LocalStorageStrategy;
+import org.jclouds.blobstore.attr.ConsistencyModel;
+import org.jclouds.blobstore.config.BlobStoreObjectModule;
+import org.jclouds.blobstore.config.LocalBlobStore;
+import org.jclouds.blobstore.util.BlobUtils;
+import org.jclouds.jdbc.strategy.JdbcStorageStrategy;
+import org.jclouds.jdbc.util.JdbcBlobUtils;
+
+public class JdbcBlobStoreContextModule extends AbstractModule {
+
+   @Override
+   protected void configure() {
+      bind(JPAInitializer.class).asEagerSingleton();
+      bind(BlobStore.class).to(LocalBlobStore.class);
+      install(new BlobStoreObjectModule());
+      bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);
+      bind(LocalStorageStrategy.class).to(JdbcStorageStrategy.class);
+      bind(BlobUtils.class).to(JdbcBlobUtils.class);
+      bind(BlobRequestSigner.class).to(LocalBlobRequestSigner.class);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/entity/Container.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/entity/Container.java b/jdbc/src/main/java/org/jclouds/jdbc/entity/Container.java
new file mode 100644
index 0000000..dd003a6
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/entity/Container.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.entity;
+
+import org.jclouds.blobstore.domain.ContainerAccess;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.PrePersist;
+import javax.persistence.Table;
+import java.util.Date;
+
+@Entity
+@Table
+public class Container {
+
+   @Id
+   @GeneratedValue(strategy = GenerationType.IDENTITY)
+   private Long id;
+
+   @Column(unique = true)
+   private String name;
+
+   private Date creationDate;
+
+   private ContainerAccess containerAccess;
+
+   public Container() {
+   }
+
+   public Container(Long id, String name, Date creationDate, ContainerAccess containerAccess) {
+      this.id = id;
+      this.name = name;
+      this.creationDate = creationDate;
+      this.containerAccess = containerAccess;
+   }
+
+   @PrePersist
+   private void defaults() {
+      this.creationDate = new Date();
+      if (containerAccess == null) {
+         this.containerAccess = ContainerAccess.PRIVATE;
+      }
+   }
+
+   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 Date getCreationDate() {
+      return creationDate;
+   }
+
+   public void setCreationDate(Date creationDate) {
+      this.creationDate = creationDate;
+   }
+
+   public ContainerAccess getContainerAccess() {
+      return containerAccess;
+   }
+
+   public void setContainerAccess(ContainerAccess containerAccess) {
+      this.containerAccess = containerAccess;
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static class Builder {
+      private String name;
+      private ContainerAccess containerAccess;
+
+      public Builder() {
+      }
+
+      public Builder name(String name){
+         this.name = name;
+         return this;
+      }
+
+      public Builder containerAccess(ContainerAccess containerAccess){
+         this.containerAccess = containerAccess;
+         return this;
+      }
+
+      public Container build() {
+         return new Container(null, name, null, containerAccess);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/predicates/validators/JdbcBlobKeyValidator.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/predicates/validators/JdbcBlobKeyValidator.java b/jdbc/src/main/java/org/jclouds/jdbc/predicates/validators/JdbcBlobKeyValidator.java
new file mode 100644
index 0000000..7cd5bda
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/predicates/validators/JdbcBlobKeyValidator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.predicates.validators;
+
+import com.google.inject.Singleton;
+import org.jclouds.predicates.Validator;
+
+/**
+ * Validates name for jdbc container blob keys implementation
+ *
+ * @see org.jclouds.rest.InputParamValidator
+ * @see org.jclouds.predicates.Validator
+ */
+@Singleton
+public class JdbcBlobKeyValidator extends Validator<String> {
+
+    @Override
+    public void validate(String name) throws IllegalArgumentException {
+        //blob key cannot be null or empty
+        if (name == null || name.length() < 1)
+            throw new IllegalArgumentException("Blob key can't be null or empty");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/predicates/validators/JdbcContainerNameValidator.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/predicates/validators/JdbcContainerNameValidator.java b/jdbc/src/main/java/org/jclouds/jdbc/predicates/validators/JdbcContainerNameValidator.java
new file mode 100644
index 0000000..28d49ef
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/predicates/validators/JdbcContainerNameValidator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.predicates.validators;
+
+import com.google.inject.Singleton;
+import org.jclouds.predicates.Validator;
+
+/**
+ * Validates container name for jdbc provider implementation
+ *
+ * @see org.jclouds.rest.InputParamValidator
+ * @see org.jclouds.predicates.Validator
+ */
+@Singleton
+public class JdbcContainerNameValidator extends Validator<String> {
+
+    @Override
+    public void validate(String name) throws IllegalArgumentException {
+        //container name cannot be null or empty
+        if (name == null || name.length() < 1)
+            throw new IllegalArgumentException("Container name can't be null or empty");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/repository/ContainerRepository.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/repository/ContainerRepository.java b/jdbc/src/main/java/org/jclouds/jdbc/repository/ContainerRepository.java
new file mode 100644
index 0000000..759be2b
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/repository/ContainerRepository.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.repository;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import org.jclouds.jdbc.entity.Container;
+
+import javax.persistence.EntityManager;
+import java.util.List;
+
+@Singleton
+public class ContainerRepository extends GenericRepository<Container, Long> {
+
+   @Inject
+   private ContainerRepository(Provider<EntityManager> entityManager) {
+      super(entityManager);
+   }
+
+   public Container findContainerByName(String name) {
+      return entityManager.get().createQuery("SELECT c FROM " + entityClass.getName() + " c WHERE c.name = :name", entityClass)
+            .setParameter("name", name)
+            .getSingleResult();
+   }
+
+   public List<Container> findAllContainers() {
+      return entityManager.get().createQuery("SELECT c FROM " + entityClass.getName() + " c", entityClass)
+            .getResultList();
+   }
+
+   public void deleteContainerByName(String name) {
+      delete(findContainerByName(name));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/repository/GenericRepository.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/repository/GenericRepository.java b/jdbc/src/main/java/org/jclouds/jdbc/repository/GenericRepository.java
new file mode 100644
index 0000000..58964a8
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/repository/GenericRepository.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.repository;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import javax.persistence.EntityManager;
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+
+public abstract class GenericRepository<T, PK extends Serializable> {
+
+   protected final Class<T> entityClass;
+   protected final Provider<EntityManager> entityManager;
+
+   @Inject
+   @SuppressWarnings("unchecked")
+   protected GenericRepository(Provider<EntityManager> entityManager) {
+      this.entityManager = entityManager;
+      this.entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
+   }
+
+   public T create(T entity) {
+      entityManager.get().persist(entity);
+      return entity;
+   }
+
+   public T find(PK id) {
+      return entityManager.get().find(entityClass, id);
+   }
+
+   public T save(T entity) {
+      return entityManager.get().merge(entity);
+   }
+
+   public void delete(T entity) {
+      entityManager.get().remove(entityManager.get().contains(entity) ? entity : entityManager.get().merge(entity));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/service/JdbcService.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/service/JdbcService.java b/jdbc/src/main/java/org/jclouds/jdbc/service/JdbcService.java
new file mode 100644
index 0000000..08990ba
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/service/JdbcService.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.service;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import org.jclouds.blobstore.domain.ContainerAccess;
+import org.jclouds.jdbc.entity.Container;
+import org.jclouds.jdbc.repository.ContainerRepository;
+
+import java.util.List;
+
+@Singleton
+public class JdbcService {
+
+   private final ContainerRepository containerRepository;
+
+   @Inject
+   JdbcService(ContainerRepository containerRepository) {
+      this.containerRepository = containerRepository;
+   }
+
+   @Transactional
+   public void createContainer(String name, ContainerAccess access) {
+      containerRepository.create(Container.builder().name(name).containerAccess(access).build());
+   }
+
+   @Transactional
+   public void createContainer(String name) {
+      containerRepository.create(Container.builder().name(name).build());
+   }
+
+   @Transactional
+   public List<Container> findAllContainers() {
+      return containerRepository.findAllContainers();
+   }
+
+   @Transactional
+   public Container findContainerByName(String name) {
+      return containerRepository.findContainerByName(name);
+   }
+
+   @Transactional
+   public void deleteContainerByName(String name) {
+      containerRepository.deleteContainerByName(name);
+   }
+
+   @Transactional
+   public void setContainerAccessByName(String name, ContainerAccess access) {
+      Container container = containerRepository.findContainerByName(name);
+      container.setContainerAccess(access);
+      containerRepository.save(container);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/strategy/JdbcStorageStrategy.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/strategy/JdbcStorageStrategy.java b/jdbc/src/main/java/org/jclouds/jdbc/strategy/JdbcStorageStrategy.java
new file mode 100644
index 0000000..5fb2032
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/strategy/JdbcStorageStrategy.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.strategy;
+
+import com.google.common.collect.ImmutableList;
+import com.google.inject.persist.Transactional;
+import org.jclouds.blobstore.LocalStorageStrategy;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.domain.BlobAccess;
+import org.jclouds.blobstore.domain.BlobBuilder;
+import org.jclouds.blobstore.domain.ContainerAccess;
+import org.jclouds.blobstore.domain.MutableStorageMetadata;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.domain.StorageType;
+import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
+import org.jclouds.blobstore.options.CreateContainerOptions;
+import org.jclouds.blobstore.options.ListContainerOptions;
+import org.jclouds.domain.Location;
+import org.jclouds.jdbc.entity.Container;
+import org.jclouds.jdbc.predicates.validators.JdbcBlobKeyValidator;
+import org.jclouds.jdbc.predicates.validators.JdbcContainerNameValidator;
+import org.jclouds.jdbc.service.JdbcService;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.persistence.NoResultException;
+import javax.persistence.PersistenceException;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * JdbcStorageStrategy implements a blob store that stores objects
+ * on a jdbc supported database. Content metadata and user attributes are stored in
+ * the database as well.
+ */
+public class JdbcStorageStrategy implements LocalStorageStrategy {
+
+   @Resource
+   private Logger logger = Logger.NULL;
+
+   private final Provider<BlobBuilder> blobBuilders;
+   private final JdbcService jdbcService;
+   private final JdbcContainerNameValidator jdbcContainerNameValidator;
+   private final JdbcBlobKeyValidator jdbcBlobKeyValidator;
+
+   @Inject
+   JdbcStorageStrategy(Provider<BlobBuilder> blobBuilders,
+         JdbcContainerNameValidator jdbcContainerNameValidator, JdbcBlobKeyValidator jdbcBlobKeyValidator,
+         JdbcService jdbcService)
+         throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
+      this.jdbcService = jdbcService;
+      this.blobBuilders = blobBuilders;
+      this.jdbcContainerNameValidator = jdbcContainerNameValidator;
+      this.jdbcBlobKeyValidator = jdbcBlobKeyValidator;
+   }
+
+   @Override
+   public boolean containerExists(String container) {
+      jdbcContainerNameValidator.validate(container);
+      try {
+         jdbcService.findContainerByName(container);
+      } catch (NoResultException e) {
+         return false;
+      }
+      return true;
+   }
+
+   @Override
+   public Iterable<String> getAllContainerNames() {
+      List<Container> containers = jdbcService.findAllContainers();
+      ImmutableList.Builder<String> result = ImmutableList.builder();
+      for (Container c : containers) {
+         result.add(c.getName());
+      }
+      return result.build();
+   }
+
+   @Override
+   public boolean createContainerInLocation(String container, Location location,
+         CreateContainerOptions createContainerOptions) {
+      logger.debug("Creating container %s", container);
+      ContainerAccess containerAccess = createContainerOptions == null ? ContainerAccess.PRIVATE
+            : (createContainerOptions.isPublicRead() ? ContainerAccess.PUBLIC_READ
+            : ContainerAccess.PRIVATE);
+      try {
+         jdbcContainerNameValidator.validate(container);
+         jdbcService.createContainer(container, containerAccess);
+      } catch (PersistenceException e) {
+         return false;
+      } catch (IllegalArgumentException e) {
+         return false;
+      }
+      return true;
+   }
+
+   @Override
+   public ContainerAccess getContainerAccess(String container) {
+      return jdbcService.findContainerByName(container).getContainerAccess();
+   }
+
+   @Override
+   public void setContainerAccess(String container, ContainerAccess containerAccess) {
+      jdbcService.setContainerAccessByName(container, containerAccess);
+   }
+
+   @Override
+   public void deleteContainer(String container) {
+      jdbcContainerNameValidator.validate(container);
+      jdbcService.deleteContainerByName(container);
+   }
+
+   @Override
+   public void clearContainer(String s) {
+
+   }
+
+   @Override
+   public void clearContainer(String s, ListContainerOptions listContainerOptions) {
+
+   }
+
+   @Override
+   @Transactional
+   public StorageMetadata getContainerMetadata(String container) {
+      MutableStorageMetadata metadata = new MutableStorageMetadataImpl();
+      metadata.setName(container);
+      metadata.setType(StorageType.CONTAINER);
+      metadata.setLocation(null);
+      metadata.setCreationDate(jdbcService.findContainerByName(container).getCreationDate());
+      return metadata;
+   }
+
+   @Override
+   public boolean blobExists(String s, String s1) {
+      return false;
+   }
+
+   @Override
+   public Iterable<String> getBlobKeysInsideContainer(String s) throws IOException {
+      return null;
+   }
+
+   @Override
+   public Blob getBlob(String s, String s1) {
+      return null;
+   }
+
+   @Override
+   public String putBlob(String s, Blob blob) throws IOException {
+      return null;
+   }
+
+   @Override
+   public void removeBlob(String s, String s1) {
+
+   }
+
+   @Override
+   public BlobAccess getBlobAccess(String s, String s1) {
+      return null;
+   }
+
+   @Override
+   public void setBlobAccess(String s, String s1, BlobAccess blobAccess) {
+
+   }
+
+   @Override
+   public Location getLocation(String name) {
+      return null;
+   }
+
+   @Override
+   public String getSeparator() {
+      return "/";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/main/java/org/jclouds/jdbc/util/JdbcBlobUtils.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/jclouds/jdbc/util/JdbcBlobUtils.java b/jdbc/src/main/java/org/jclouds/jdbc/util/JdbcBlobUtils.java
new file mode 100644
index 0000000..dda6e01
--- /dev/null
+++ b/jdbc/src/main/java/org/jclouds/jdbc/util/JdbcBlobUtils.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.util;
+
+import javax.inject.Provider;
+
+import org.jclouds.blobstore.LocalStorageStrategy;
+import org.jclouds.blobstore.domain.BlobBuilder;
+import org.jclouds.blobstore.options.ListContainerOptions;
+import org.jclouds.blobstore.util.BlobUtils;
+import org.jclouds.jdbc.strategy.JdbcStorageStrategy;
+
+import com.google.inject.Inject;
+
+/**
+ * Implements the {@link BlobUtils} interfaced and act as a bridge to
+ * {@link LocalStorageStrategy} when used inside {@link BlobStore}
+ */
+public class JdbcBlobUtils implements BlobUtils {
+
+   protected final JdbcStorageStrategy storageStrategy;
+   protected final Provider<BlobBuilder> blobBuilders;
+
+   @Inject
+   JdbcBlobUtils(LocalStorageStrategy storageStrategy, Provider<BlobBuilder> blobBuilders) {
+      this.storageStrategy = (JdbcStorageStrategy) storageStrategy;
+      this.blobBuilders = blobBuilders;
+   }
+
+   @Override
+   public BlobBuilder blobBuilder() {
+      return blobBuilders.get();
+   }
+
+   @Override public boolean directoryExists(String s, String s1) {
+      return false;
+   }
+
+   @Override public void createDirectory(String s, String s1) {
+
+   }
+
+   @Override public long countBlobs(String s, ListContainerOptions listContainerOptions) {
+      return 0;
+   }
+
+   @Override
+   public void clearContainer(String container, ListContainerOptions options) {
+      storageStrategy.clearContainer(container, options);
+   }
+
+   @Override public void deleteDirectory(String s, String s1) {
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/test/java/org/jclouds/jdbc/JdbcApiMetadataTest.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/jclouds/jdbc/JdbcApiMetadataTest.java b/jdbc/src/test/java/org/jclouds/jdbc/JdbcApiMetadataTest.java
new file mode 100644
index 0000000..036612d
--- /dev/null
+++ b/jdbc/src/test/java/org/jclouds/jdbc/JdbcApiMetadataTest.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc;
+
+import org.jclouds.blobstore.internal.BaseBlobStoreApiMetadataTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "JdbcApiMetadataTest")
+public class JdbcApiMetadataTest extends BaseBlobStoreApiMetadataTest {
+
+   public JdbcApiMetadataTest() {
+      super(new JdbcApiMetadata());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/test/java/org/jclouds/jdbc/JdbcBlobStoreTest.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/jclouds/jdbc/JdbcBlobStoreTest.java b/jdbc/src/test/java/org/jclouds/jdbc/JdbcBlobStoreTest.java
new file mode 100644
index 0000000..270adca
--- /dev/null
+++ b/jdbc/src/test/java/org/jclouds/jdbc/JdbcBlobStoreTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+import com.google.inject.persist.jpa.JpaPersistModule;
+import org.jclouds.ContextBuilder;
+import org.jclouds.blobstore.BlobStore;
+import org.jclouds.blobstore.BlobStoreContext;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.util.Set;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "unit", testName = "JdbcBlobStoreTest", singleThreaded = true)
+public class JdbcBlobStoreTest {
+
+   private static final String CONTAINER_NAME = "test-container";
+   private static final Set<Module> MODULES = ImmutableSet.<Module> of(new JpaPersistModule("jclouds-test"));
+
+   private static final String PROVIDER = "jdbc";
+
+   private BlobStoreContext context = null;
+   private BlobStore blobStore = null;
+
+   @BeforeMethod
+   protected void setUp() throws Exception {
+      context = ContextBuilder.newBuilder(PROVIDER)
+            .modules(MODULES)
+            .build(BlobStoreContext.class);
+      blobStore = context.getBlobStore();
+   }
+
+   @AfterMethod
+   protected void tearDown() throws IOException {
+      context.close();
+   }
+
+   @Test
+   public void testCreateContainerInLocation() {
+      assertThat(blobStore.createContainerInLocation(null, CONTAINER_NAME)).isTrue();
+      assertThat(blobStore.containerExists(CONTAINER_NAME)).isTrue();
+   }
+
+   @Test
+   public void testDeleteContainer() {
+      assertThat(blobStore.createContainerInLocation(null, CONTAINER_NAME)).isTrue();
+      assertThat(blobStore.containerExists(CONTAINER_NAME)).isTrue();
+      blobStore.deleteContainer(CONTAINER_NAME);
+      assertThat(blobStore.containerExists(CONTAINER_NAME)).isFalse();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/test/java/org/jclouds/jdbc/module/TestContextModule.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/jclouds/jdbc/module/TestContextModule.java b/jdbc/src/test/java/org/jclouds/jdbc/module/TestContextModule.java
new file mode 100644
index 0000000..0798813
--- /dev/null
+++ b/jdbc/src/test/java/org/jclouds/jdbc/module/TestContextModule.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.module;
+
+import com.google.inject.AbstractModule;
+import org.jclouds.jdbc.config.JPAInitializer;
+
+public class TestContextModule extends AbstractModule {
+
+   @Override
+   protected void configure() {
+      bind(JPAInitializer.class).asEagerSingleton();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/test/java/org/jclouds/jdbc/strategy/JdbcStorageStrategyTest.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/jclouds/jdbc/strategy/JdbcStorageStrategyTest.java b/jdbc/src/test/java/org/jclouds/jdbc/strategy/JdbcStorageStrategyTest.java
new file mode 100644
index 0000000..ef72f61
--- /dev/null
+++ b/jdbc/src/test/java/org/jclouds/jdbc/strategy/JdbcStorageStrategyTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.jdbc.strategy;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+import com.google.inject.Module;
+import com.google.inject.persist.jpa.JpaPersistModule;
+import org.jclouds.blobstore.domain.ContainerAccess;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.domain.StorageType;
+import org.jclouds.blobstore.options.CreateContainerOptions;
+import org.jclouds.jdbc.module.TestContextModule;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.Date;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Test(groups = "unit", testName = "JdbcStorageStrategyTest", singleThreaded = true)
+public class JdbcStorageStrategyTest {
+
+   private static final String CONTAINER_NAME = "jclouds-test";
+   private JdbcStorageStrategy storageStrategy;
+
+   @BeforeMethod
+   protected void setUp() throws Exception {
+      storageStrategy = Guice.createInjector(ImmutableSet.<Module> of(new TestContextModule(), new JpaPersistModule("jclouds-test"))).getInstance(JdbcStorageStrategy.class);
+   }
+
+   @Test
+   public void testCreateContainerInLocation() {
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME, null, null)).isTrue();
+      assertThat(storageStrategy.containerExists(CONTAINER_NAME)).isTrue();
+   }
+
+   @Test
+   public void testCreateDuplicateContainerInLocation() {
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME, null, null)).isTrue();
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME, null, null)).isFalse();
+   }
+
+   @Test
+   public void testDefaultContainerAccess() {
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME, null, null)).isTrue();
+      assertThat(storageStrategy.getContainerAccess(CONTAINER_NAME)).isEqualTo(ContainerAccess.PRIVATE);
+   }
+
+   @Test
+   public void testOverridedPublicContainerAccess() {
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME, null, new CreateContainerOptions().publicRead())).isTrue();
+      assertThat(storageStrategy.getContainerAccess(CONTAINER_NAME)).isEqualTo(ContainerAccess.PUBLIC_READ);
+   }
+
+   @Test
+   public void testOverridedPrivateContainerAccess() {
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME, null, CreateContainerOptions.NONE)).isTrue();
+      assertThat(storageStrategy.getContainerAccess(CONTAINER_NAME)).isEqualTo(ContainerAccess.PRIVATE);
+   }
+
+   @Test
+   public void testDeleteContainer() {
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME, null, null)).isTrue();
+      assertThat(storageStrategy.containerExists(CONTAINER_NAME)).isTrue();
+      storageStrategy.deleteContainer(CONTAINER_NAME);
+      assertThat(storageStrategy.containerExists(CONTAINER_NAME)).isFalse();
+   }
+
+   @Test
+   public void testGetAllContainerNames() {
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME + "1", null, null)).isTrue();
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME + "2", null, null)).isTrue();
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME + "3", null, null)).isTrue();
+      assertThat(storageStrategy.getAllContainerNames()).containsExactly(CONTAINER_NAME + "1", CONTAINER_NAME + "2", CONTAINER_NAME + "3");
+   }
+
+   @Test
+   public void testGetContainerMetadata() {
+      assertThat(storageStrategy.createContainerInLocation(CONTAINER_NAME, null, null)).isTrue();
+      StorageMetadata storageMetadata = storageStrategy.getContainerMetadata(CONTAINER_NAME);
+      assertThat(storageMetadata.getName()).isEqualTo(CONTAINER_NAME);
+      assertThat(storageMetadata.getType()).isEqualTo(StorageType.CONTAINER);
+      assertThat(storageMetadata.getCreationDate()).isBefore(new Date());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/test/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/jdbc/src/test/resources/META-INF/persistence.xml b/jdbc/src/test/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..11b870e
--- /dev/null
+++ b/jdbc/src/test/resources/META-INF/persistence.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+             version="1.0">
+  <persistence-unit name="jclouds-test" transaction-type="RESOURCE_LOCAL">
+    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
+
+    <class>org.jclouds.jdbc.entity.Container</class>
+    <exclude-unlisted-classes>true</exclude-unlisted-classes>
+
+    <properties>
+      <property name="hibernate.archive.autodetection" value="class" />
+      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
+      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
+      <property name="hibernate.connection.url" value="jdbc:hsqldb:file:target/testdb;shutdown=true" />
+      <property name="hibernate.connection.user" value="sa" />
+      <!-- <property name="hibernate.show_sql" value="true"/> -->
+      <property name="hibernate.flushMode" value="FLUSH_AUTO" />
+      <property name="hibernate.hbm2ddl.auto" value="create" />
+    </properties>
+  </persistence-unit>
+</persistence>

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/jdbc/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/jdbc/src/test/resources/log4j.properties b/jdbc/src/test/resources/log4j.properties
new file mode 100644
index 0000000..0815baa
--- /dev/null
+++ b/jdbc/src/test/resources/log4j.properties
@@ -0,0 +1,25 @@
+#
+#
+# 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.
+#
+#
+log4j.rootLogger=WARN, A1
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+log4j.logger.org.hibernate = ERROR

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/83218e32/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index b5265bf..b632662 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,6 +75,7 @@
     <module>cloudsigma2-wdc</module>
     <module>cloudsigma2-zrh</module>
     <module>digitalocean</module>
+    <module>jdbc</module>
     <module>joyent-cloudapi</module>
     <module>joyentcloud</module>
     <module>abiquo</module>