You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2017/10/29 09:41:49 UTC

[8/8] polygene-java git commit: Added Berkeley DB (Java Edition) Entity Store.

Added Berkeley DB (Java Edition) Entity Store.


Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/879580c3
Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/879580c3
Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/879580c3

Branch: refs/heads/es-bdbje
Commit: 879580c3d7201fb59fac92d3567dfea8b3b91370
Parents: e0825fe
Author: niclas <ni...@hedhman.org>
Authored: Sun Oct 29 17:34:44 2017 +0800
Committer: niclas <ni...@hedhman.org>
Committed: Sun Oct 29 17:34:44 2017 +0800

----------------------------------------------------------------------
 dependencies.gradle                             |   3 +
 extensions/entitystore-bdbje/build.gradle       |  41 ++
 extensions/entitystore-bdbje/dev-status.xml     |  38 ++
 .../bdbje/BdbJeEntityStoreActivation.java       |  59 +++
 .../bdbje/BdbJeEntityStoreConfiguration.java    | 383 +++++++++++++++++++
 .../bdbje/BdbJeEntityStoreMixin.java            | 342 +++++++++++++++++
 .../bdbje/BdbJeEntityStoreService.java          |  52 +++
 .../assembly/BdbJeEntityStoreAssembler.java     |  45 +++
 .../entitystore/bdbje/assembly/package.html     |  24 ++
 .../polygene/entitystore/bdbje/package.html     |  24 ++
 .../entitystore/bdbje/BdbJeEntityStoreTest.java |  60 +++
 .../bdbje/BdbJeEntityStoreTestSuite.java        |  47 +++
 settings.gradle                                 |   1 +
 13 files changed, 1119 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/dependencies.gradle
----------------------------------------------------------------------
diff --git a/dependencies.gradle b/dependencies.gradle
index 0664ace..b4a8c86 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -27,6 +27,7 @@ dependencies.repositoriesUrls << [
   mavenCentral: "https://repo1.maven.org/maven2/",
   restlet     : 'https://maven.restlet.com/',
   clojars     : "https://clojars.org/repo/",
+  oracle      : "http://download.oracle.com/maven/"
 ]
 
 // Core dependencies
@@ -42,6 +43,7 @@ dependencies.libraries << [
 ]
 
 // Extensions, Libraries and Tools dependencies
+def bdbjeVersion = '7.4.5'
 def bonecpVersion = '0.8.0.RELEASE'
 def bouncyVersion = '1.57'
 def cassandraClientVersion = '3.3.0'
@@ -81,6 +83,7 @@ def springVersion = '4.3.9.RELEASE'
 def spymemcachedVersion = '2.12.3'
 def velocityVersion = '1.7'
 dependencies.libraries << [
+  bdb_je              : "com.sleepycat:je:$bdbjeVersion",
   bonecp              : "com.jolbox:bonecp:$bonecpVersion",
   bouncy_castle       : [
           "org.bouncycastle:bcprov-jdk15on:$bouncyVersion",

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/build.gradle
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/build.gradle b/extensions/entitystore-bdbje/build.gradle
new file mode 100644
index 0000000..ea14aef
--- /dev/null
+++ b/extensions/entitystore-bdbje/build.gradle
@@ -0,0 +1,41 @@
+/*
+ *  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.
+ *
+ *
+ */
+
+apply plugin: 'polygene-extension'
+
+description = "Apache Polygene™ Berkeley DB (Java Edition) EntityStore Extension"
+
+jar { manifest { name = "Apache Polygene™ Extension - EntityStore - BDB/JE" } }
+
+dependencies {
+    api polygene.core.bootstrap
+    api libraries.bdb_je
+    api polygene.library( 'constraints' )
+    api polygene.library( 'fileconfig' )
+
+    implementation polygene.library( 'locking' )
+    implementation libraries.jackson_mapper
+
+    runtimeOnly polygene.core.runtime
+
+    testImplementation polygene.internals.testsupport
+
+    testRuntimeOnly libraries.logback
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/dev-status.xml
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/dev-status.xml b/extensions/entitystore-bdbje/dev-status.xml
new file mode 100644
index 0000000..fcc2930
--- /dev/null
+++ b/extensions/entitystore-bdbje/dev-status.xml
@@ -0,0 +1,38 @@
+<?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.
+  ~
+  ~
+  -->
+<module xmlns="http://polygene.apache.org/schemas/2008/dev-status/1"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://polygene.apache.org/schemas/2008/dev-status/1
+        http://polygene.apache.org/schemas/2008/dev-status/1/dev-status.xsd">
+  <status>
+        <!--none,early,beta,stable,mature-->
+        <codebase>beta</codebase>
+
+        <!-- none, brief, good, complete -->
+        <documentation>none</documentation>
+
+        <!-- none, some, good, complete -->
+        <unittests>good</unittests>
+    </status>
+    <licenses>
+        <license>ALv2</license>
+    </licenses>
+</module>

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreActivation.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreActivation.java b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreActivation.java
new file mode 100644
index 0000000..92b829a
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreActivation.java
@@ -0,0 +1,59 @@
+/*
+ *  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.apache.polygene.entitystore.bdbje;
+
+import org.apache.polygene.api.activation.ActivatorAdapter;
+import org.apache.polygene.api.activation.Activators;
+import org.apache.polygene.api.service.ServiceReference;
+
+/**
+ * Activation for BdbJeEntityStoreMixin.
+ */
+@Activators( { BdbJeEntityStoreActivation.Activator.class } )
+public interface BdbJeEntityStoreActivation
+{
+
+    void setUpBdbJe()
+            throws Exception;
+
+    void tearDownBdbJe()
+            throws Exception;
+
+    class Activator
+            extends ActivatorAdapter<ServiceReference<BdbJeEntityStoreActivation>>
+    {
+
+        @Override
+        public void afterActivation( ServiceReference<BdbJeEntityStoreActivation> activated )
+                throws Exception
+        {
+            activated.get().setUpBdbJe();
+        }
+
+        @Override
+        public void beforePassivation( ServiceReference<BdbJeEntityStoreActivation> passivating )
+                throws Exception
+        {
+            passivating.get().tearDownBdbJe();
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreConfiguration.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreConfiguration.java b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreConfiguration.java
new file mode 100644
index 0000000..82fb682
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreConfiguration.java
@@ -0,0 +1,383 @@
+/*
+ *  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.apache.polygene.entitystore.bdbje;
+
+import com.sleepycat.je.CacheMode;
+import com.sleepycat.je.Durability;
+import org.apache.polygene.api.common.Optional;
+import org.apache.polygene.api.common.UseDefaults;
+import org.apache.polygene.api.property.Property;
+
+/**
+ * Configuration for the BdbJeEntityStoreService.
+ */
+// START SNIPPET: config
+public interface BdbJeEntityStoreConfiguration
+{
+    /**
+     * Name of the database containing the Polygene entities.
+     */
+    @UseDefaults("polygene")
+    Property<String> databaseName();
+
+    /**
+     * The file where the BDB JE data will be stored
+     * <p>
+     * Default: System.getProperty( "user.dir" ) + "/polygene/bdbjestore.data";
+     * </p>
+     *
+     * @return path to data file relative to current path
+     */
+    @Optional
+    Property<String> homeDirectory();
+
+    /**
+     * If true, creates the database environment if it doesn't already exist.
+     */
+    @UseDefaults("true")
+    Property<Boolean> allowCreate();
+
+    /**
+     * Configures the database environment for no locking.
+     * <p>
+     * If true, create the environment with record locking. This property should be set to false only in special
+     * circumstances when it is safe to run without record locking.
+     * </p>
+     * <p>
+     * This configuration option should be used when locking guarantees such as consistency and isolation are not
+     * important. If locking mode is disabled (it is enabled by default), the cleaner is automatically disabled.
+     * The user is responsible for invoking the cleaner and ensuring that there are no concurrent operations while
+     * the cleaner is running.
+     * </p>
+     */
+    @UseDefaults("true")
+    Property<Boolean> locking();
+
+    /**
+     * Configures the default lock timeout.
+     * <p>
+     * A value of zero disables lock timeouts. This is not recommended, even when the application expects that
+     * deadlocks will not occur or will be easily resolved. A lock timeout is a fall-back that guards against
+     * unexpected "live lock", unresponsive threads, or application failure to close a cursor or to commit or
+     * abort a transaction.
+     * </p>
+     * <p>
+     * Expressed in milliseconds. Default: 500ms
+     * </p>
+     */
+    @UseDefaults("500")
+    Property<Long> lockTimeout();
+
+    /**
+     * Sets the user defined nodeName for the Environment.
+     * <p>
+     * If set, exception messages, logging messages, and thread names will have this nodeName included in them.
+     * If a user has multiple Environments in a single JVM, setting this to a string unique to each Environment
+     * may make it easier to diagnose certain exception conditions as well as thread dumps.
+     * </p>
+     */
+    @Optional
+    Property<String> nodeName();
+
+    /**
+     * Configures the database environment to be read-only, and any attempt to modify a database will fail.
+     * <p>
+     * A read-only environment has several limitations and is recommended only in special circumstances. Note that
+     * there is no performance advantage to opening an environment read-only.
+     * </p>
+     * <p>
+     * The primary reason for opening an environment read-only is to open a single environment in multiple JVM
+     * processes. Only one JVM process at a time may open the environment read-write. See EnvironmentLockedException.
+     * </p>
+     * <p>
+     * When the environment is open read-only, the following limitations apply.
+     * </p>
+     * <p>
+     * In the read-only environment no writes may be performed, as expected, and databases must be opened read-only
+     * using DatabaseConfig.setReadOnly.
+     * </p>
+     * <p>
+     * The read-only environment receives a snapshot of the data that is effectively frozen at the time the environment
+     * is opened. If the application has the environment open read-write in another JVM process and modifies the
+     * environment's databases in any way, the read-only version of the data will not be updated until the read-only
+     * JVM process closes and reopens the environment (and by extension all databases in that environment).
+     * </p>
+     * <p>
+     * If the read-only environment is opened while the environment is in use by another JVM process in read-write mode,
+     * opening the environment read-only (recovery) is likely to take longer than it does after a clean shutdown. This
+     * is due to the fact that the read-write JVM process is writing and checkpoints are occurring that are not
+     * coordinated with the read-only JVM process. The effect is similar to opening an environment after a crash.
+     * </p>
+     * <p>
+     * In a read-only environment, the JE cache will contain information that cannot be evicted because it was
+     * reconstructed by recovery and cannot be flushed to disk. This means that the read-only environment may not be
+     * suitable for operations that use large amounts of memory, and poor performance may result if this is attempted.
+     * </p>
+     * <p>
+     * In a read-write environment, the log cleaner will be prohibited from deleting log files for as long as the
+     * environment is open read-only in another JVM process. This may cause disk usage to rise, and for this reason
+     * it is not recommended that an environment is kept open read-only in this manner for long periods.
+     * </p>
+     * <p>
+     * For these reasons, it is recommended that a read-only environment be used only for short periods and for
+     * operations that are not performance critical or memory intensive. With few exceptions, all application functions
+     * that require access to a JE environment should be built into a single application so that they can be performed
+     * in the JVM process where the environment is open read-write.
+     * </p>
+     * <p>
+     * In most applications, opening an environment read-only can and should be avoided.
+     * </p>
+     */
+    @UseDefaults
+    Property<Boolean> readOnly();
+
+    /**
+     * If true, the shared cache is used by this environment.
+     * <p>
+     * By default this parameter is false and this environment uses a private cache. If this parameter is set to true,
+     * this environment will use a cache that is shared with all other open environments in this process that also set
+     * this parameter to true. There is a single shared cache per process.
+     * </p>
+     * <p>
+     * By using the shared cache, multiple open environments will make better use of memory because the cache LRU
+     * algorithm is applied across all information in all environments sharing the cache. For example, if one
+     * environment is open but not recently used, then it will only use a small portion of the cache, leaving the rest
+     * of the cache for environments that have been recently used.
+     * </p>
+     */
+    @UseDefaults
+    Property<Boolean> sharedCache();
+
+    /**
+     * Configures the use of transactions.
+     * <p>
+     * This should be set to true when transactional guarantees such as atomicity of multiple operations and durability
+     * are important.
+     * </p>
+     * <p>
+     * If true, create an environment that is capable of performing transactions. If true is not passed, transactions
+     * may not be used. For licensing purposes, the use of this method distinguishes the use of the Transactional
+     * product. Note that if transactions are not used, specifying true does not create additional overhead in the
+     * environment.
+     * </p>
+     */
+    @UseDefaults("true")
+    Property<Boolean> transactional();
+
+    /**
+     * The transaction timeout.
+     * <p>
+     * A value of 0 turns off transaction timeouts.
+     * </p>
+     * <p>
+     * Expressed in milliseconds.
+     * </p>
+     */
+    @UseDefaults
+    Property<Long> txnTimeout();
+
+    /**
+     * Configures all transactions for this environment to have Serializable (Degree 3) isolation.
+     * <p>
+     * By setting Serializable isolation, phantoms will be prevented. By default transactions provide Repeatable Read
+     * isolation. The default is false for the database environment.
+     * </p>
+     */
+    @UseDefaults
+    Property<Boolean> txnSerializableIsolation();
+
+    /**
+     * The default CacheMode used for operations performed in this environment.
+     * <p>
+     * The default cache mode may be overridden on a per-database basis using DatabaseConfig.setCacheMode, and on a
+     * per-record or per-operation basis using Cursor.setCacheMode, ReadOptions.setCacheMode(CacheMode) or
+     * WriteOptions.setCacheMode(CacheMode).
+     * </p>
+     */
+    @UseDefaults("DEFAULT")
+    Property<CacheMode> cacheMode();
+
+    /**
+     * Configures the memory available to the database system, as a percentage of the JVM maximum memory.
+     * <p>
+     * The system will evict database objects when it comes within a prescribed margin of the limit.
+     * </p>
+     * <p>
+     * By default, JE sets the cache size to:
+     * </p>
+     * <p>
+     * <code>(MAX_MEMORY_PERCENT * JVM maximum memory) / 100</code>
+     * </p>
+     * <p>
+     * where JVM maximum memory is specified by the JVM -Xmx flag. However, setting MAX_MEMORY to a non-zero value
+     * overrides the percentage based calculation and sets the cache size explicitly.
+     * </p>
+     * <p>
+     * The following details apply to setting the cache size to a percentage of the JVM heap size byte size (this
+     * parameter) as well as to a byte size (MAX_MEMORY
+     * </p>
+     * <p>
+     * Note that the log buffer cache may be cleared if the cache size is changed after the environment has been opened.
+     * </p>
+     * <p>
+     * If SHARED_CACHE is set to true, MAX_MEMORY and MAX_MEMORY_PERCENT specify the total size of the shared cache,
+     * and changing these parameters will change the size of the shared cache.
+     * </p>
+     * <p>
+     * When using the shared cache feature, new environments that join the cache may alter the cache percent setting
+     * if their configuration is set to a different value.
+     * </p>
+     * <p>
+     * To take full advantage of JE cache memory, it is strongly recommended that compressed oops
+     * (-XX:+UseCompressedOops) is specified when a 64-bit JVM is used and the maximum heap size is less than 32 GB.
+     * As described in the referenced documentation, compressed oops is sometimes the default JVM mode even when it is
+     * not explicitly specified in the Java command. However, if compressed oops is desired then it must be explicitly
+     * specified in the Java command when running DbCacheSize or a JE application. If it is not explicitly specified
+     * then JE will not aware of it, even if it is the JVM default setting, and will not take it into account when
+     * calculating cache memory sizes.
+     * </p>
+     */
+    @UseDefaults("60")
+    Property<Integer> cachePercent();
+
+    /**
+     * Configures the memory available to the database system, in bytes.
+     * <p>
+     * See MAX_MEMORY_PERCENT for more information.
+     * </p>
+     */
+    @UseDefaults
+    Property<Long> cacheSize();
+
+    /**
+     * Configures the number of bytes to be used as a secondary, off-heap cache.
+     * <p>
+     * The off-heap cache is used to hold record data and Btree nodes when these are evicted from the "main cache"
+     * because it overflows. Eviction occurs according to an LRU algorithm and takes into account the user- specified
+     * CacheMode. When the off-heap cache overflows, eviction occurs there also according to the same algorithm.
+     * </p>
+     * <p>
+     * The main cache is in the Java heap and consists primarily of the Java objects making up the in-memory Btree
+     * data structure. Btree objects are not serialized the main cache, so no object materialization is needed to
+     * access the Btree there. Access to records in the main cache is therefore very fast, but the main cache has
+     * drawbacks as well:
+     * <ol>
+     * <li>
+     * The larger the main cache, the more likely it is to have Java GC performance problems.
+     * </li>
+     * <li>
+     * When the Java heap exceeds 32GB, the "compressed OOPs" setting no longer applies and less data will fit in the
+     * same amount of memory. For these reasons, JE applications often configure a heap of 32GB or less, and a main
+     * cache that is significantly less than 32GB, leaving any additional machine memory for use by the file system
+     * cache.
+     * </li>
+     * </ol>
+     * </p>
+     * <p>
+     * The use of the file system cache has performance benefits, but also has its own drawbacks:
+     * <ol>
+     * <li>
+     * There is a significant redundancy between the main cache and the file system cache because all data and Btree
+     * information that is logged (written) by JE appears in the file system and may also appear in the main cache.
+     * </li>
+     * <li>
+     * It is not possible for dirty Btree information to be placed in the file system cache without logging it, this
+     * logging may be otherwise unnecessary, and the logging creates additional work for the JE cleaner; in other
+     * words, the size of the main cache alone determines the maximum size of the in-memory "dirty set".
+     * </li>
+     * </ol>
+     * </p>
+     * <p>
+     * The off-heap cache is stored outside the Java heap using a native platform memory allocator. The current
+     * implementation relies on internals that are specific to the Oracle and IBM JDKs; however, a memory allocator
+     * interface that can be implemented for other situations is being considered for a future release. Records and
+     * Btree objects are serialized when they are placed in the off-heap cache, and they must be materialized when
+     * they are moved back to the main cache in order to access them. This serialization and materialization adds
+     * some CPU overhead and thread contention, as compared to accessing data directly in the main cache. The off-heap
+     * cache can contain dirty Btree information, so it can be used to increase the maximum size of the in-memory
+     * "dirty set".
+     * </p>
+     * <p>
+     * NOTE: If an off-heap cache is configured but cannot be used because that native allocator is not available in
+     * the JDK that is used, an IllegalStateException will be thrown by the Environment or
+     * com.sleepycat.je.rep.ReplicatedEnvironment constructor. In the current release, this means that the
+     * sun.misc.Unsafe class must contain the allocateMemory method and related methods, as defined in the Oracle JDK.
+     * </p>
+     * <p>
+     * When configuring an off-heap cache you can think of the performance trade-offs in two ways. First, if the
+     * off-heap cache is considered to be a replacement for the file system cache, the serialization and
+     * materialization overhead is not increased. In this case, the use of the off-heap cache is clearly beneficial,
+     * and using the off-heap cache "instead of" the file system cache is normally recommended. Second, the off-heap
+     * cache can be used along with a main cache that is reduced in size in order to compensate for Java GC problems.
+     * In this case, the trade-off is between the additional serialization, materialization and contention overheads
+     * of the off-heap cache, as compared to the Java GC overhead.
+     * </p>
+     * <p>
+     * When dividing up available memory for the JVM heap, the off-heap cache, and for other uses, please be aware
+     * that the file system cache and the off-heap cache are different in one important respect. The file system cache
+     * automatically shrinks when memory is needed by the OS or other processes, while the off-heap cache does not.
+     * Therefore, it is best to be conservative about leaving memory free for other uses, and it is not a good idea to
+     * size the off-heap cache such that all machine memory will be allocated. If off-heap allocations or other
+     * allocations fail because there is no available memory, the process is likely to die without any exception
+     * being thrown. In one test on Linux, for example, the process was killed abruptly by the OS and the only
+     * indication of the problem was the following shown by dmesg.
+     * </p>
+     * <pre><code>
+     * Out of memory: Kill process 28768 (java) score 974 or sacrifice child
+     * Killed process 28768 (java)
+     * total-vm:278255336kB, anon-rss:257274420kB, file-rss:0kB
+     * </code></pre>
+     * WARNING: Although this configuration property is mutable, it cannot be changed from zero to non-zero, or
+     * non-zero to zero. In other words, the size of the off-heap cache can be changed after initially configuring
+     * a non-zero size, but the off-heap cache cannot be turned on and off dynamically. An attempt to do so will
+     * cause an IllegalArgumentException to be thrown by the Environment or com.sleepycat.je.rep.ReplicatedEnvironment
+     * constructor.
+     */
+    @UseDefaults
+    Property<Long> cacheHeapCacheSize();
+
+    /**
+     * Configures the default durability associated with transactions.
+     * <p>
+     * The string must have the following format:
+     * </p>
+     * <pre><code>
+     * SyncPolicy[,SyncPolicy[,ReplicaAckPolicy]]
+     * </code></pre>
+     * <p>
+     * The first SyncPolicy in the above format applies to the Master, and the optional second SyncPolicy to the
+     * replica. Specific SyncPolicy or ReplicaAckPolicy values are denoted by the name of the enumeration value.
+     * </p>
+     * <p>
+     * For example, the string:sync,sync,quorum describes a durability policy where the master and replica both use
+     * Durability.SyncPolicy.SYNC to commit transactions and Durability.ReplicaAckPolicy.SIMPLE_MAJORITY to acknowledge
+     * a transaction commit.
+     * </p>
+     * <p>
+     * Durability.SyncPolicy.NO_SYNC, is the default value for a node's SyncPolicy.
+     * </p>
+     * <p>
+     * Durability.ReplicaAckPolicy.SIMPLE_MAJORITY is the default for the ReplicaAckPolicy.
+     * </p>
+     */
+    @Optional
+    Property<String> durability();
+}
+// END SNIPPET: config

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreMixin.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreMixin.java b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreMixin.java
new file mode 100644
index 0000000..8459161
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreMixin.java
@@ -0,0 +1,342 @@
+/*
+ *  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.apache.polygene.entitystore.bdbje;
+
+import com.sleepycat.je.Cursor;
+import com.sleepycat.je.Database;
+import com.sleepycat.je.DatabaseConfig;
+import com.sleepycat.je.DatabaseEntry;
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Durability;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+import com.sleepycat.je.LockMode;
+import com.sleepycat.je.OperationStatus;
+import com.sleepycat.je.Transaction;
+import com.sleepycat.je.TransactionConfig;
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import org.apache.polygene.api.common.Optional;
+import org.apache.polygene.api.configuration.Configuration;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.injection.scope.Service;
+import org.apache.polygene.api.injection.scope.This;
+import org.apache.polygene.api.injection.scope.Uses;
+import org.apache.polygene.api.service.ServiceDescriptor;
+import org.apache.polygene.library.fileconfig.FileConfiguration;
+import org.apache.polygene.library.locking.ReadLock;
+import org.apache.polygene.library.locking.WriteLock;
+import org.apache.polygene.spi.entitystore.EntityNotFoundException;
+import org.apache.polygene.spi.entitystore.EntityStoreException;
+import org.apache.polygene.spi.entitystore.helpers.MapEntityStore;
+
+/**
+ * BDB JE implementation of MapEntityStore.
+ */
+public class BdbJeEntityStoreMixin
+    implements BdbJeEntityStoreActivation, MapEntityStore
+{
+    @Optional
+    @Service
+    private FileConfiguration fileConfiguration;
+
+    @This
+    private Configuration<BdbJeEntityStoreConfiguration> config;
+
+    @Uses
+    private ServiceDescriptor descriptor;
+
+    private Database database;
+    private Environment envHandle;
+
+    @Override
+    public void setUpBdbJe()
+        throws Exception
+    {
+        initialize();
+    }
+
+    @Override
+    public void tearDownBdbJe()
+        throws Exception
+    {
+        closeDown();
+    }
+
+    @ReadLock
+    @Override
+    public Reader get( EntityReference entityReference )
+        throws EntityStoreException
+    {
+        try
+        {
+            String indexKey = entityReference.toString();
+            DatabaseEntry key = new DatabaseEntry( indexKey.getBytes( "UTF-8" ) );
+            DatabaseEntry result = new DatabaseEntry();
+            OperationStatus operationStatus = database.get( null, key, result, LockMode.DEFAULT );
+            if( operationStatus == OperationStatus.NOTFOUND )
+            {
+                throw new EntityNotFoundException( entityReference );
+            }
+            return new StringReader( new String( result.getData(), "UTF-8" ) );
+        }
+        catch( IOException e )
+        {
+            throw new EntityStoreException( e );
+        }
+    }
+
+    @WriteLock
+    @Override
+    public void applyChanges( MapChanges changes )
+        throws IOException
+    {
+        Transaction transaction = envHandle.beginTransaction( null, TransactionConfig.DEFAULT );
+        try
+        {
+            changes.visitMap( new MapChanger()
+            {
+                @Override
+                public Writer newEntity( EntityReference ref, EntityDescriptor descriptor )
+                    throws IOException
+                {
+                    return new StringWriter( 1000 )
+                    {
+                        @Override
+                        public void close()
+                            throws IOException
+                        {
+                            super.close();
+                            String indexKey = ref.toString();
+                            DatabaseEntry theKey = new DatabaseEntry( indexKey.getBytes( "UTF-8" ) );
+                            DatabaseEntry theData = new DatabaseEntry( toString().getBytes( "UTF-8" ) );
+                            database.put( transaction, theKey, theData );
+                        }
+                    };
+                }
+
+                @Override
+                public Writer updateEntity( MapChange mapChange )
+                    throws IOException
+                {
+                    return new StringWriter( 1000 )
+                    {
+                        @Override
+                        public void close()
+                            throws IOException
+                        {
+                            super.close();
+                            String indexKey = mapChange.reference().identity().toString();
+                            DatabaseEntry theKey = new DatabaseEntry( indexKey.getBytes( "UTF-8" ) );
+                            DatabaseEntry theData = new DatabaseEntry( toString().getBytes( "UTF-8" ) );
+                            database.put( transaction, theKey, theData );
+                        }
+                    };
+                }
+
+                @Override
+                public void removeEntity( EntityReference ref, EntityDescriptor descriptor )
+                    throws EntityNotFoundException
+                {
+                    try
+                    {
+                        String indexKey = ref.toString();
+                        DatabaseEntry theKey = new DatabaseEntry( indexKey.getBytes( "UTF-8" ) );
+                        database.delete( transaction, theKey );
+                    }
+                    catch( IOException e )
+                    {
+                        throw new EntityStoreException( e );
+                    }
+                }
+            } );
+            transaction.commit();
+        }
+        catch( Exception e )
+        {
+            e.printStackTrace();
+            transaction.abort();
+            if( ( e instanceof IOException ) )
+            {
+                throw (IOException) e;
+            }
+            else if( !( e instanceof EntityStoreException ) )
+            {
+                throw new IOException( e );
+            }
+            else
+            {
+                throw (EntityStoreException) e;
+            }
+        }
+    }
+
+    @Override
+    public Stream<Reader> entityStates()
+        throws IOException
+    {
+        return StreamSupport.stream( new RecordIterable( database ).spliterator(), false );
+    }
+
+    private File getDatabaseHome()
+    {
+        String pathname = config.get().homeDirectory().get();
+        if( pathname == null )
+        {
+            if( fileConfiguration != null )
+            {
+                File dataDir = fileConfiguration.dataDirectory();
+                File bdbJeDir = new File( dataDir, descriptor.identity() + "/bdbje_data" );
+                pathname = bdbJeDir.getAbsolutePath();
+            }
+            else
+            {
+                pathname = System.getProperty( "user.dir" ) + "/polygene/bdbje_data";
+            }
+        }
+
+        File directory = new File( pathname ).getAbsoluteFile();
+        //noinspection ResultOfMethodCallIgnored
+        directory.mkdirs();
+        return directory;
+    }
+
+    private void closeDown()
+    {
+        if( database != null )
+        {
+            database.close();
+        }
+        if( envHandle != null )
+        {
+            envHandle.close();
+        }
+    }
+
+    private void initialize()
+        throws IOException
+    {
+        File homeDir = getDatabaseHome();
+        EnvironmentConfig configuration = createConfiguration();
+
+        envHandle = new Environment( homeDir, configuration );
+        DatabaseConfig dbConfig = new DatabaseConfig();
+        dbConfig.setAllowCreate( configuration.getAllowCreate() );
+        dbConfig.setTransactional( configuration.getTransactional() );
+        database = envHandle.openDatabase( null, config.get().databaseName().get(), dbConfig );
+    }
+
+    private EnvironmentConfig createConfiguration()
+    {
+        EnvironmentConfig environmentConfig = new EnvironmentConfig();
+        BdbJeEntityStoreConfiguration storeConfiguration = config.get();
+        Boolean allowCreate = storeConfiguration.allowCreate().get();
+        environmentConfig.setAllowCreate( allowCreate );
+        environmentConfig.setLocking( storeConfiguration.locking().get() );
+        environmentConfig.setLockTimeout( storeConfiguration.lockTimeout().get(), TimeUnit.MILLISECONDS );
+        environmentConfig.setNodeName( storeConfiguration.nodeName().get() );
+        environmentConfig.setReadOnly( storeConfiguration.readOnly().get() );
+        environmentConfig.setSharedCache( storeConfiguration.sharedCache().get() );
+        environmentConfig.setTransactional( storeConfiguration.transactional().get() );
+        environmentConfig.setTxnTimeout( storeConfiguration.txnTimeout().get(), TimeUnit.MILLISECONDS );
+        environmentConfig.setTxnSerializableIsolation( storeConfiguration.txnSerializableIsolation().get() );
+        environmentConfig.setCacheMode( storeConfiguration.cacheMode().get() );
+        environmentConfig.setCachePercent( storeConfiguration.cachePercent().get() );
+        environmentConfig.setCacheSize( storeConfiguration.cacheSize().get() );
+        environmentConfig.setOffHeapCacheSize( storeConfiguration.cacheHeapCacheSize().get() );
+        environmentConfig.setDurability( Durability.parse( storeConfiguration.durability().get() ) );
+        return environmentConfig;
+    }
+
+    private static class RecordIterable
+        implements Iterable<Reader>, Iterator<Reader>
+    {
+        private Cursor cursor;
+        private DatabaseEntry foundKey;
+        private DatabaseEntry foundData;
+        private boolean success;
+
+        private RecordIterable( Database db )
+            throws IOException
+        {
+            try
+            {
+                cursor = db.openCursor( null, null );
+                foundKey = new DatabaseEntry();
+                foundData = new DatabaseEntry();
+            }
+            catch( DatabaseException e )
+            {
+                throw new IOException( "Unknown problem in Berkeley DB", e );
+            }
+        }
+
+        @Override
+        @SuppressWarnings( "NullableProblems" )
+        public Iterator<Reader> iterator()
+        {
+            forward();
+            return this;
+        }
+
+        @Override
+        public boolean hasNext()
+        {
+            return success;
+        }
+
+        @Override
+        public Reader next()
+        {
+            byte[] data = foundData.getData();
+            forward();
+            try
+            {
+                return new StringReader( new String( data, "UTF-8" ) );
+            }
+            catch( UnsupportedEncodingException e )
+            {
+                // can not happen.
+                return new StringReader( "" );
+            }
+        }
+
+        private void forward()
+        {
+            OperationStatus status = cursor.getNext( foundKey, foundData, LockMode.DEFAULT );
+            if( status == OperationStatus.NOTFOUND )
+            {
+                // End of Cursor, and need to close.
+                cursor.close();
+            }
+            success = status == OperationStatus.SUCCESS;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreService.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreService.java b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreService.java
new file mode 100644
index 0000000..a45994f
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreService.java
@@ -0,0 +1,52 @@
+/*
+ *  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.apache.polygene.entitystore.bdbje;
+
+import org.apache.polygene.api.concern.Concerns;
+import org.apache.polygene.api.configuration.Configuration;
+import org.apache.polygene.api.mixin.Mixins;
+import org.apache.polygene.library.locking.LockingAbstractComposite;
+import org.apache.polygene.library.locking.ReadLockConcern;
+import org.apache.polygene.library.locking.WriteLockConcern;
+import org.apache.polygene.spi.entitystore.BackupRestore;
+import org.apache.polygene.spi.entitystore.ConcurrentModificationCheckConcern;
+import org.apache.polygene.spi.entitystore.EntityStateVersions;
+import org.apache.polygene.spi.entitystore.EntityStore;
+import org.apache.polygene.spi.entitystore.StateChangeNotificationConcern;
+import org.apache.polygene.spi.entitystore.helpers.JSONMapEntityStoreActivation;
+import org.apache.polygene.spi.entitystore.helpers.JSONMapEntityStoreMixin;
+import org.apache.polygene.spi.entitystore.helpers.StateStore;
+
+/**
+ * EntityStore service backed by BDB JE store.
+ * <p>Based on @{@link JSONMapEntityStoreMixin}.</p>
+ */
+@Concerns( { StateChangeNotificationConcern.class, ConcurrentModificationCheckConcern.class, ReadLockConcern.class, WriteLockConcern.class } )
+@Mixins( { JSONMapEntityStoreMixin.class, BdbJeEntityStoreMixin.class } )
+public interface BdbJeEntityStoreService
+    extends BdbJeEntityStoreActivation,
+            JSONMapEntityStoreActivation,
+            EntityStore,
+            EntityStateVersions,
+            StateStore,
+            LockingAbstractComposite,
+            Configuration<BdbJeEntityStoreConfiguration>
+{
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/assembly/BdbJeEntityStoreAssembler.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/assembly/BdbJeEntityStoreAssembler.java b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/assembly/BdbJeEntityStoreAssembler.java
new file mode 100644
index 0000000..db029a3
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/assembly/BdbJeEntityStoreAssembler.java
@@ -0,0 +1,45 @@
+/*
+ *  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.apache.polygene.entitystore.bdbje.assembly;
+
+import org.apache.polygene.bootstrap.Assemblers;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.bootstrap.ServiceDeclaration;
+import org.apache.polygene.entitystore.bdbje.BdbJeEntityStoreConfiguration;
+import org.apache.polygene.entitystore.bdbje.BdbJeEntityStoreService;
+
+public class BdbJeEntityStoreAssembler
+    extends Assemblers.VisibilityIdentityConfig<BdbJeEntityStoreAssembler>
+{
+    @Override
+    public void assemble( ModuleAssembly module )
+    {
+        super.assemble( module );
+        ServiceDeclaration service = module.services( BdbJeEntityStoreService.class ).visibleIn( visibility() );
+        if( hasIdentity() )
+        {
+            service.identifiedBy( identity() );
+        }
+        if( hasConfig() )
+        {
+            configModule().entities( BdbJeEntityStoreConfiguration.class ).visibleIn( configVisibility() );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/assembly/package.html
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/assembly/package.html b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/assembly/package.html
new file mode 100644
index 0000000..298493f
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/assembly/package.html
@@ -0,0 +1,24 @@
+<!--
+  ~  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.
+  ~
+  ~
+  -->
+<html>
+    <body>
+        <h2>Berkeley DB (Java Edition) EntityStore Assembly.</h2>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/package.html
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/package.html b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/package.html
new file mode 100644
index 0000000..17b4142
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/main/java/org/apache/polygene/entitystore/bdbje/package.html
@@ -0,0 +1,24 @@
+<!--
+  ~  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.
+  ~
+  ~
+  -->
+<html>
+    <body>
+        <h2>Berkley DB (Java Edition) EntityStore.</h2>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/test/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreTest.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/test/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreTest.java b/extensions/entitystore-bdbje/src/test/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreTest.java
new file mode 100644
index 0000000..c2a590f
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/test/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreTest.java
@@ -0,0 +1,60 @@
+/*
+ *  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.apache.polygene.entitystore.bdbje;
+
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.bootstrap.AssemblyException;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.entitystore.bdbje.assembly.BdbJeEntityStoreAssembler;
+import org.apache.polygene.library.fileconfig.FileConfigurationAssembler;
+import org.apache.polygene.library.fileconfig.FileConfigurationOverride;
+import org.apache.polygene.test.EntityTestAssembler;
+import org.apache.polygene.test.entity.AbstractEntityStoreTest;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+
+public class BdbJeEntityStoreTest
+    extends AbstractEntityStoreTest
+{
+    @Rule
+    public final TemporaryFolder tmpDir = new TemporaryFolder();
+
+    @Override
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        super.assemble( module );
+
+        ModuleAssembly config = module.layer().module( "config" );
+        new EntityTestAssembler().defaultServicesVisibleIn( Visibility.layer ).assemble( config );
+
+        new FileConfigurationAssembler()
+            .withOverride( new FileConfigurationOverride().withConventionalRoot( tmpDir.getRoot() ) )
+            .assemble( module );
+        new BdbJeEntityStoreAssembler().withConfig( config, Visibility.layer ).assemble( module );
+    }
+
+    @After
+    public void cleanup()
+    {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/extensions/entitystore-bdbje/src/test/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreTestSuite.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-bdbje/src/test/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreTestSuite.java b/extensions/entitystore-bdbje/src/test/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreTestSuite.java
new file mode 100644
index 0000000..6fb54bd
--- /dev/null
+++ b/extensions/entitystore-bdbje/src/test/java/org/apache/polygene/entitystore/bdbje/BdbJeEntityStoreTestSuite.java
@@ -0,0 +1,47 @@
+/*
+ *  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.apache.polygene.entitystore.bdbje;
+
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.bootstrap.ModuleAssembly;
+import org.apache.polygene.entitystore.bdbje.assembly.BdbJeEntityStoreAssembler;
+import org.apache.polygene.library.fileconfig.FileConfigurationAssembler;
+import org.apache.polygene.library.fileconfig.FileConfigurationOverride;
+import org.apache.polygene.test.entity.model.EntityStoreTestSuite;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+
+public class BdbJeEntityStoreTestSuite extends EntityStoreTestSuite
+{
+    @Rule
+    public final TemporaryFolder tmpDir = new TemporaryFolder();
+
+    @Override
+    protected void defineStorageModule( ModuleAssembly module )
+    {
+        module.defaultServices();
+        new FileConfigurationAssembler()
+            .withOverride( new FileConfigurationOverride().withConventionalRoot( tmpDir.getRoot() ) )
+            .assemble( module );
+        new BdbJeEntityStoreAssembler().visibleIn( Visibility.application )
+                                       .withConfig( configModule, Visibility.application )
+                                       .assemble( module );
+    }
+}

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/879580c3/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 3a4067c..3fa0179 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -55,6 +55,7 @@ include 'core:api',
         'libraries:uowfile',
         'extensions:cache-ehcache',
         'extensions:cache-memcache',
+        'extensions:entitystore-bdbje',
         'extensions:entitystore-cassandra',
         'extensions:entitystore-file',
         'extensions:entitystore-geode',