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 <nic...@hedhman.org> Authored: Sun Oct 29 17:34:44 2017 +0800 Committer: niclas <nic...@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',