Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Roldan Betancort2013-08-09 08:55:41 -0400
committerVictor Roldan Betancort2013-08-09 08:55:41 -0400
commitceaa9cd5f320abae7c109852ac1d9a01f1e7cf37 (patch)
treec3b6b2f18228c6d58c4617f81f6c8949599b4519
parent02defe32410e41b300dac05f8835bb4307645c10 (diff)
downloadcdo-committers/vroldanbet/couchbase.tar.gz
cdo-committers/vroldanbet/couchbase.tar.xz
cdo-committers/vroldanbet/couchbase.zip
[414770] Implement Couchbase based IStore committers/vroldanbet/couchbase
https://bugs.eclipse.org/bugs/show_bug.cgi?id=414770
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/.classpath7
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/.project28
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/META-INF/MANIFEST.MF14
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/build.properties4
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/couchbase/ICouchbaseStore.java26
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/couchbase/package-info.java16
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStore.java165
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStoreAccessor.java353
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStoreFactory.java51
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/AbstractCommitable.java117
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/CommitInfoHandler.java143
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/CouchbaseHandler.java45
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/ICommitable.java12
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/JSONCommitInfo.java47
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/JSONHandler.java34
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/LobHandler.java148
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/LockingHandler.java167
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/PackageUnitHandler.java53
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/ResourceHandler.java154
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/RevisionHandler.java175
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/StoreHandler.java19
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/StoreMetaHandler.java151
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/bundle/OM.java45
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockArea.java127
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockAreaTypeAdapter.java66
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockEntry.java94
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONPackageUnit.java154
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONRevision.java499
-rw-r--r--plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONRevisionTypeAdapter.java259
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/.classpath7
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/.project28
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/CDO AllTests (Couchbase).launch16
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/CDO AllTests (Couchbase-memcached).launch16
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/META-INF/MANIFEST.MF13
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/build.properties4
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/hs_err_pid6840.log366
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsCouchbase.java69
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsMemcached.java72
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/CouchbaseConfig.java117
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/CouchbaseUtil.java176
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/bundle/OM.java44
43 files changed, 4115 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/.classpath b/plugins/org.eclipse.emf.cdo.server.couchbase/.classpath
new file mode 100644
index 0000000000..64c5e31b7a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/.project b/plugins/org.eclipse.emf.cdo.server.couchbase/.project
new file mode 100644
index 0000000000..b89e96a62a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.emf.cdo.server.couchbase</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.emf.cdo.server.couchbase/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..af0f20f97a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server.couchbase/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..fdece13338
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Couchbase CDO Server
+Bundle-SymbolicName: org.eclipse.emf.cdo.server.couchbase
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: eclipse.org
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Require-Bundle: com.google.gson;bundle-version="[2.2.0,3.0.0)",
+ org.eclipse.emf.cdo.server;bundle-version="[4.0.0,5.0.0)",
+ com.couchbase.client;bundle-version="[1.1.5,2.0.0)",
+ net.spy.memcached;bundle-version="[2.8.0,3.0.0)"
+Export-Package: org.eclipse.emf.cdo.server.couchbase;version="1.0.0",
+ org.eclipse.emf.cdo.server.internal;version="1.0.0";x-friends:="org.eclipse.emf.cdo.tests.couchbase",
+ org.eclipse.emf.cdo.server.internal.couchbase.bundle;version="1.0.0";x-internal:=true
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/build.properties b/plugins/org.eclipse.emf.cdo.server.couchbase/build.properties
new file mode 100644
index 0000000000..34d2e4d2da
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/couchbase/ICouchbaseStore.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/couchbase/ICouchbaseStore.java
new file mode 100644
index 0000000000..3e80bee6ed
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/couchbase/ICouchbaseStore.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2010-2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+
+package org.eclipse.emf.cdo.server.couchbase;
+
+import org.eclipse.emf.cdo.server.IStore;
+
+/**
+ * The main entry point to the API of CDO's integration with Couchbase database.
+ *
+ * @author Victor Roldan Betancort
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ICouchbaseStore extends IStore
+{
+ public static final String TYPE = "couchbase";
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/couchbase/package-info.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/couchbase/package-info.java
new file mode 100644
index 0000000000..8ab5557942
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/couchbase/package-info.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2011-2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+
+/**
+ * Server concepts for dealing with Couchbase stores and accessors.
+ */
+package org.eclipse.emf.cdo.server.couchbase;
+
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStore.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStore.java
new file mode 100644
index 0000000000..8dcf63869c
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStore.java
@@ -0,0 +1,165 @@
+package org.eclipse.emf.cdo.server.internal;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.emf.cdo.server.ISession;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.server.couchbase.ICouchbaseStore;
+import org.eclipse.emf.cdo.server.internal.commitables.StoreMetaHandler;
+import org.eclipse.emf.cdo.server.internal.couchbase.bundle.OM;
+import org.eclipse.emf.cdo.spi.server.LongIDStore;
+import org.eclipse.emf.cdo.spi.server.StoreAccessorBase;
+import org.eclipse.emf.cdo.spi.server.StoreAccessorPool;
+import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
+
+import com.couchbase.client.CouchbaseClient;
+import com.couchbase.client.CouchbaseConnectionFactory;
+import com.couchbase.client.CouchbaseConnectionFactoryBuilder;
+
+public class CouchbaseStore extends LongIDStore implements ICouchbaseStore {
+
+ private static final int COUCHBASE_OPERATION_TIMEOUT = 10000;
+
+ private List<URI> clusterList;
+
+ private String bucketName;
+
+ private CouchbaseClient client;
+
+ @ExcludeFromDump
+ private transient final StoreAccessorPool readerPool = new StoreAccessorPool(
+ this, null);
+
+ @ExcludeFromDump
+ private transient final StoreAccessorPool writerPool = new StoreAccessorPool(
+ this, null);
+
+ @ExcludeFromDump
+ private String password;
+
+ @ExcludeFromDump
+ private String user;
+
+ private StoreMetaHandler storeMetaHandler;
+
+ public CouchbaseStore(List<URI> clusterList, String bucketName, String user, String password) {
+ super(ICouchbaseStore.TYPE, set(ChangeFormat.REVISION), set(
+ RevisionTemporality.NONE, RevisionTemporality.AUDITING), set(
+ RevisionParallelism.NONE, RevisionParallelism.BRANCHING));
+
+ this.clusterList = clusterList;
+ this.bucketName = bucketName;
+ this.user = user;
+ this.password = password;
+ }
+
+ public StoreMetaHandler getStoreMetaHandler() {
+ if (storeMetaHandler == null) {
+ storeMetaHandler = new StoreMetaHandler(getClient());
+ }
+ return storeMetaHandler;
+ }
+
+ public CouchbaseClient openClient() {
+ try {
+ CouchbaseConnectionFactoryBuilder connectionFactoryBuilder = new CouchbaseConnectionFactoryBuilder();
+ // Reduces the rate of random "Cancelled" upon client.get() calls; still happens though
+ connectionFactoryBuilder.setOpTimeout(COUCHBASE_OPERATION_TIMEOUT);
+ CouchbaseConnectionFactory connectionFactory = connectionFactoryBuilder.buildCouchbaseConnection(clusterList, bucketName, user, password);
+ return new CouchbaseClient((CouchbaseConnectionFactory)connectionFactory);
+ } catch (IOException e) {
+ OM.LOG.error(e);
+ }
+ return null;
+ }
+
+ private CouchbaseClient getClient() {
+ if (client == null) {
+ client = openClient();
+ }
+ return client;
+ }
+
+ @Override
+ protected void doActivate() throws Exception {
+ super.doActivate();
+ Long lastCDOID = getStoreMetaHandler().getLastCDOID();
+ if (lastCDOID != null) {
+ setLastObjectID(lastCDOID);
+ }
+ setLastCommitTime(storeMetaHandler.getLastCommitTime());
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception {
+ super.doDeactivate();
+ storeMetaHandler.setIsFirstStart(false);
+ storeMetaHandler.setLastCommitTime(getLastCommitTime());
+ if (client != null) {
+ client.shutdown(10, TimeUnit.SECONDS); // Its important to gracefully shutdown, or we may lost data recently committed
+ client = null;
+ }
+ StoreAccessorBase readerAccessor;
+ while ((readerAccessor = readerPool.removeStoreAccessor(this)) != null) {
+ LifecycleUtil.deactivate(readerAccessor);
+ }
+ StoreAccessorBase writerAccessor;
+ while ((writerAccessor = writerPool.removeStoreAccessor(this)) != null) {
+ LifecycleUtil.deactivate(writerAccessor);
+ }
+
+ }
+
+ public void setCreationTime(long creationTime) {
+ storeMetaHandler.setCreationTime(creationTime);
+ }
+
+ public boolean isFirstStart() {
+ return storeMetaHandler.isFirstStart();
+ }
+
+ public long getCreationTime() {
+ return storeMetaHandler.getCreationTime();
+ }
+
+ public Map<String, String> getPersistentProperties(Set<String> names) {
+ return storeMetaHandler.getPersistentProperties(names);
+ }
+
+ public void setPersistentProperties(Map<String, String> properties) {
+ storeMetaHandler.setPersistentProperties(properties);
+ }
+
+ public void removePersistentProperties(Set<String> names) {
+ storeMetaHandler.removePersistentProperties(names);
+ }
+
+ @Override
+ protected StoreAccessorPool getReaderPool(ISession session, boolean forReleasing) {
+ return readerPool;
+ }
+
+ @Override
+ protected StoreAccessorPool getWriterPool(IView view, boolean forReleasing) {
+ return writerPool;
+ }
+
+ @Override
+ protected IStoreAccessor createReader(ISession session) {
+ return new CouchbaseStoreAccessor(this, session);
+ }
+
+ @Override
+ protected IStoreAccessor createWriter(ITransaction transaction) {
+ return new CouchbaseStoreAccessor(this, transaction);
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStoreAccessor.java
new file mode 100644
index 0000000000..f22df27ebe
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStoreAccessor.java
@@ -0,0 +1,353 @@
+package org.eclipse.emf.cdo.server.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchHandler;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lob.CDOLobHandler;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.revision.CDORevisionCacheAdder;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.util.CDOQueryInfo;
+import org.eclipse.emf.cdo.server.IQueryHandler;
+import org.eclipse.emf.cdo.server.ISession;
+import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking;
+import org.eclipse.emf.cdo.server.IStoreAccessor.Raw;
+import org.eclipse.emf.cdo.server.IStoreChunkReader;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.internal.commitables.CommitInfoHandler;
+import org.eclipse.emf.cdo.server.internal.commitables.ICommitable;
+import org.eclipse.emf.cdo.server.internal.commitables.LobHandler;
+import org.eclipse.emf.cdo.server.internal.commitables.LockingHandler;
+import org.eclipse.emf.cdo.server.internal.commitables.PackageUnitHandler;
+import org.eclipse.emf.cdo.server.internal.commitables.ResourceHandler;
+import org.eclipse.emf.cdo.server.internal.commitables.RevisionHandler;
+import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+import org.eclipse.emf.cdo.spi.server.LongIDStoreAccessor;
+import org.eclipse.emf.cdo.spi.server.Store;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class CouchbaseStoreAccessor extends LongIDStoreAccessor implements Raw,
+ DurableLocking {
+
+ private List<ICommitable> transaction = new ArrayList<ICommitable>();
+
+ private CouchbaseClient client;
+
+ private RevisionHandler revisionHandler;
+
+ private ResourceHandler resourceHandler;
+
+ private PackageUnitHandler packageUnitHandler;
+
+ private CommitInfoHandler commitInfoHandler;
+
+ private LobHandler lobHandler;
+
+ private LockingHandler lockingHandler;
+
+ protected CouchbaseStoreAccessor(Store store, ISession session) {
+ super(store, session);
+ }
+
+ public CouchbaseStoreAccessor(Store store, ITransaction transaction) {
+ super(store, transaction);
+ }
+
+ private void initHandlers() {
+ revisionHandler = new RevisionHandler(getClient(), getStore());
+ resourceHandler = new ResourceHandler(getClient(), getStore());
+ packageUnitHandler = new PackageUnitHandler(getClient(), getStore());
+ commitInfoHandler = new CommitInfoHandler(getClient(), getStore());
+ lobHandler = new LobHandler(getClient(), getStore());
+ lockingHandler = new LockingHandler(getClient(), getStore());
+ }
+
+ @Override
+ public CouchbaseStore getStore() {
+ return (CouchbaseStore) super.getStore();
+ }
+
+ @Override
+ protected void doActivate() throws Exception {
+ super.doActivate();
+ if (client == null) {
+ client = getStore().openClient();
+ }
+ initHandlers();
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception {
+ super.doDeactivate();
+ if (getClient() != null) {
+ getClient().shutdown(10, TimeUnit.SECONDS);
+ }
+ }
+
+ private CouchbaseClient getClient() {
+ return client;
+ }
+
+ public IStoreChunkReader createChunkReader(InternalCDORevision revision, EStructuralFeature feature) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public Collection<InternalCDOPackageUnit> readPackageUnits() {
+ return packageUnitHandler.readPackageUnits();
+ }
+
+ public EPackage[] loadPackageUnit(InternalCDOPackageUnit packageUnit) {
+ return packageUnitHandler.loadPackageUnit(packageUnit);
+ }
+
+ public InternalCDORevision readRevision(CDOID id, CDOBranchPoint branchPoint, int listChunk, CDORevisionCacheAdder cache) {
+ return revisionHandler.readRevision(id, branchPoint);
+ }
+
+ public InternalCDORevision readRevisionByVersion(CDOID id, CDOBranchVersion branchVersion, int listChunk, CDORevisionCacheAdder cache) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void handleRevisions(EClass eClass, CDOBranch branch, long timeStamp, boolean exactTime, CDORevisionHandler handler) {
+ revisionHandler.handleRevisions(eClass, branch, timeStamp, exactTime, handler);
+ }
+
+ public Set<CDOID> readChangeSet(OMMonitor monitor, CDOChangeSetSegment... segments) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void queryResources(QueryResourcesContext context) {
+ resourceHandler.queryResources(context);
+ }
+
+ public void queryXRefs(QueryXRefsContext context) {
+ revisionHandler.queryXRefs(context);
+ }
+
+ public void queryLobs(List<byte[]> ids) {
+ for (Iterator<byte[]> it = ids.iterator(); it.hasNext();)
+ {
+ if (lobHandler.readLob(it.next()) == null)
+ {
+ it.remove();
+ }
+ }
+ }
+
+ public void loadLob(byte[] id, OutputStream out) throws IOException {
+ lobHandler.loadLob(id, out);
+ }
+
+ public void handleLobs(long fromTime, long toTime, CDOLobHandler handler) throws IOException {
+ lobHandler.handleLobs(fromTime, toTime, handler);
+ }
+
+ public void writePackageUnits(InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) {
+ for (InternalCDOPackageUnit packageUnit : packageUnits) {
+ addToTransaction(packageUnitHandler.createPackageUnitCommitable(packageUnit));
+ }
+ }
+
+ public IQueryHandler getQueryHandler(CDOQueryInfo info) {
+ return null;
+ }
+
+ public Pair<Integer, Long> createBranch(int branchID, BranchInfo branchInfo) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public BranchInfo loadBranch(int branchID) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public SubBranchInfo[] loadSubBranches(int branchID) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public int loadBranches(int startID, int endID, CDOBranchHandler branchHandler) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void loadCommitInfos(CDOBranch branch, long startTime, long endTime, CDOCommitInfoHandler handler) {
+ commitInfoHandler.loadCommitInfos(branch, startTime, endTime, handler);
+ }
+
+ public LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly, Map<CDOID, LockGrade> locks) throws LockAreaAlreadyExistsException {
+ return lockingHandler.createLockArea(userID, branchPoint, readOnly, locks);
+ }
+
+ public LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException {
+ return lockingHandler.getLockArea(durableLockingID);
+ }
+
+ public void getLockAreas(String userIDPrefix, Handler handler) {
+ lockingHandler.getLockAreas(userIDPrefix, handler);
+ }
+
+ public void deleteLockArea(String durableLockingID) {
+ lockingHandler.deleteLockArea(durableLockingID);
+ }
+
+ public void lock(String durableLockingID, LockType type, Collection<? extends Object> objectsToLock) {
+ lockingHandler.lock(durableLockingID, type, objectsToLock);
+ }
+
+ public void unlock(String durableLockingID, LockType type, Collection<? extends Object> objectsToUnlock) {
+ lockingHandler.unlock(durableLockingID, type, objectsToUnlock);
+ }
+
+ public void unlock(String durableLockingID) {
+ lockingHandler.unlock(durableLockingID);
+ }
+
+ public void rawExport(CDODataOutput out, int fromBranchID, int toBranchID, long fromCommitTime, long toCommitTime) throws IOException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void rawImport(CDODataInput in, int fromBranchID, int toBranchID, long fromCommitTime, long toCommitTime, OMMonitor monitor) throws IOException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void rawStore(InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void rawStore(InternalCDORevision revision, OMMonitor monitor) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void rawStore(byte[] id, long size, InputStream inputStream) throws IOException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void rawStore(byte[] id, long size, Reader reader) throws IOException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void rawStore(CDOBranch branch, long timeStamp, long previousTimeStamp, String userID, String comment, OMMonitor monitor) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void rawDelete(CDOID id, int version, CDOBranch branch, EClass eClass, OMMonitor monitor) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void rawCommit(double commitWork, OMMonitor monitor) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ private void addToTransaction(ICommitable commitable) {
+ transaction.add(commitable);
+ }
+
+ @Override
+ protected void writeCommitInfo(CDOBranch branch, long timeStamp, long previousTimeStamp, String userID, String comment, OMMonitor monitor) {
+ addToTransaction(commitInfoHandler.createWriteCommitInfoCommitable(branch, timeStamp, previousTimeStamp, userID, comment));
+ }
+
+ @Override
+ protected void writeRevisions(InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor) {
+ monitor.begin(revisions.length);
+ try
+ {
+ for (InternalCDORevision revision : revisions)
+ {
+ writeRevision(revision, monitor.fork());
+ }
+ }
+ finally
+ {
+ monitor.done();
+ }
+ }
+
+ protected void writeRevision(InternalCDORevision revision, OMMonitor monitor) {
+ monitor.begin(10);
+ try
+ {
+ addToTransaction(revisionHandler.createRevisionWriteCommitable(revision));
+ } finally {
+ monitor.done();
+ }
+ }
+
+ @Override
+ protected void writeRevisionDeltas(InternalCDORevisionDelta[] revisionDeltas, CDOBranch branch, long created, OMMonitor monitor) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ protected void detachObjects(CDOID[] detachedObjects, CDOBranch branch, long timeStamp, OMMonitor monitor) {
+ monitor.begin(detachedObjects.length);
+
+ try
+ {
+ for (CDOID id : detachedObjects)
+ {
+ addToTransaction(revisionHandler.createRevisionDetachCommitable(id, branch));
+ monitor.worked();
+ }
+ }
+ finally
+ {
+ monitor.done();
+ }
+ }
+
+ @Override
+ protected void writeBlob(byte[] id, long size, InputStream inputStream) throws IOException {
+ addToTransaction(lobHandler.createWriteBlobCommitable(id, size, inputStream));
+ }
+
+ @Override
+ protected void writeClob(byte[] id, long size, Reader reader) throws IOException {
+ addToTransaction(lobHandler.createWriteClobCommitable(id, size, reader));
+ }
+
+ @Override
+ protected void doCommit(OMMonitor monitor) {
+ monitor.begin(transaction.size());
+ try {
+ for (ICommitable commitable : transaction) {
+ commitable.commit(monitor.fork());
+ }
+ transaction.clear();
+ }
+ finally
+ {
+ monitor.done();
+ }
+ }
+
+ @Override
+ protected void doRollback(CommitContext commitContext) {
+ transaction.clear();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStoreFactory.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStoreFactory.java
new file mode 100644
index 0000000000..dcea0cb1d1
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/CouchbaseStoreFactory.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010-2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.internal;
+
+import java.net.URI;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.IStoreFactory;
+import org.eclipse.emf.cdo.server.couchbase.ICouchbaseStore;
+import org.eclipse.emf.cdo.spi.server.RepositoryConfigurator;
+import org.w3c.dom.Element;
+
+public class CouchbaseStoreFactory implements IStoreFactory {
+
+ private static final String PROPERTY_URI = "uri";
+
+ private static final String PROPERTY_BUCKET = "bucket";
+
+ private static final String PROPERTY_PASSWORD = "password";
+
+ private static final Object PROPERTY_USER = "user";
+
+ public String getStoreType() {
+ return ICouchbaseStore.TYPE;
+ }
+
+ public IStore createStore(String repositoryName,
+ Map<String, String> repositoryProperties, Element storeConfig) {
+ Map<String, String> properties = RepositoryConfigurator.getProperties(
+ storeConfig, 1);
+ String uri = properties.get(PROPERTY_URI);
+ String bucket = properties.get(PROPERTY_BUCKET);
+ String user = properties.get(PROPERTY_USER);
+ String pass = properties.get(PROPERTY_PASSWORD);
+ List<URI> uris = new LinkedList<URI>();
+ uris.add(URI.create(uri));
+ return new CouchbaseStore(uris, bucket, user, pass);
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/AbstractCommitable.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/AbstractCommitable.java
new file mode 100644
index 0000000000..8849e3a084
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/AbstractCommitable.java
@@ -0,0 +1,117 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import net.spy.memcached.CASValue;
+import net.spy.memcached.internal.OperationFuture;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.server.internal.couchbase.bundle.OM;
+
+import com.couchbase.client.CouchbaseClient;
+
+public abstract class AbstractCommitable extends CouchbaseHandler implements ICommitable {
+
+ private StoreMetaHandler storeMetaHandler;
+
+ protected enum PersistMethod {
+ ADD, DELETE, SET, APPEND, APPEND_IF_NOT_CONTAINED, DELETE_APPENDED
+ }
+
+ private CDOID cdoid = CDOID.NULL;
+
+ public AbstractCommitable(CouchbaseClient client) {
+ super(client);
+ storeMetaHandler = new StoreMetaHandler(client);
+ }
+
+ public CDOID getCDOID() {
+ return cdoid;
+ }
+
+ protected void setCDOID(CDOID id) {
+ cdoid = id;
+ }
+
+ protected void doCommit(String key, Object value, CDOID id, PersistMethod persistMethod) {
+ Long storedLastCDOID = storeMetaHandler.getLastCDOID();
+ long lastCDOID = storedLastCDOID == null? -1 : storedLastCDOID;
+ boolean newLastCDOIDFound = false;
+ long commitableID = CDOIDUtil.getLong(id);
+ if (commitableID > lastCDOID) {
+ lastCDOID = commitableID;
+ newLastCDOIDFound = true;
+ }
+ // write actual data
+ switch (persistMethod) {
+ case DELETE:
+ getClient().delete(key);
+ break;
+ case ADD:
+ getClient().add(key, 0, value);
+ break;
+ case SET:
+ getClient().set(key, 0, value);
+ break;
+ case DELETE_APPENDED:
+ List<String> multivalue = getMultiValue(key);
+ Iterator<String> it = multivalue.iterator();
+ String valueString = value.toString();
+ while (it.hasNext()) {
+ String fetchedValue = it.next();
+ if (fetchedValue.equals(valueString)) {
+ it.remove();
+ }
+ }
+ StringBuilder builder = new StringBuilder();
+ for (String fetchedValue : multivalue) {
+ builder.append(getSeparator() + fetchedValue);
+ }
+ if (builder.length() > 0) {
+ builder.deleteCharAt(0);
+ }
+ doCommit(key, builder.toString(), id, PersistMethod.SET);
+ break;
+ case APPEND_IF_NOT_CONTAINED:
+ List<String> valueList = getMultiValue(key);
+ String valueString2 = value.toString();
+ for(String valueFromList : valueList) {
+ if (valueFromList.equals(valueString2)) {
+ return;
+ }
+ }
+ doCommit(key, value, id, PersistMethod.APPEND);
+ break;
+ case APPEND:
+ CASValue<Object> cas = getClient().gets(key);
+ if (cas == null || "".equals(cas.getValue())) { //FIXME why sometimes value is empty?
+ doCommit(key, value.toString(), id, PersistMethod.SET);
+ } else {
+ doAppend(key, value, cas);
+ }
+ break;
+ }
+ if (newLastCDOIDFound) {
+ storeMetaHandler.setLastCDOID(lastCDOID);
+ }
+ }
+
+ private void doAppend(String key, Object value, CASValue<Object> cas) {
+ for(;;) {
+ OperationFuture<Boolean> future = getClient().append(cas.getCas(), key, getSeparator() + value.toString());
+ try {
+ if (future.get()) {
+ break;
+ }
+ } catch (InterruptedException e) {
+ OM.LOG.error(e);
+ } catch (ExecutionException e) {
+ OM.LOG.error(e);
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/CommitInfoHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/CommitInfoHandler.java
new file mode 100644
index 0000000000..003b11256a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/CommitInfoHandler.java
@@ -0,0 +1,143 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager;
+import org.eclipse.emf.cdo.spi.common.commit.CDOCommitInfoUtil;
+import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class CommitInfoHandler extends JSONHandler {
+
+ public CommitInfoHandler(CouchbaseClient client, IStore store) {
+ super(client, store);
+ }
+
+ protected String getCommitInfoKey(CDOBranch branch, long timeStamp) {
+ return getCommitInfoKey(branch.getID(), timeStamp);
+ }
+
+ protected String getCommitInfoKey(int branch, long timeStamp) {
+ return "CDOCommitInfo::Branch-" + branch + "::TimeStamp-" + timeStamp;
+ }
+
+ protected String getCommitInfoListKey() {
+ return "CDOCommitInfo";
+ }
+
+ public ICommitable createWriteCommitInfoCommitable(final CDOBranch branch, final long timeStamp,
+ final long previousTimeStamp, final String userID, final String comment) {
+ return new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ JSONCommitInfo info = new JSONCommitInfo(branch.getID(), timeStamp, previousTimeStamp, userID, comment);
+ doCommit(getCommitInfoKey(branch, timeStamp), toJson(info), null, PersistMethod.ADD);
+ String keyListValue = branch.getID() + getCommitInfoSeparator() + timeStamp;
+ doCommit(getCommitInfoListKey(), keyListValue, null, PersistMethod.APPEND);
+ }
+ };
+ }
+
+ protected String getCommitInfoSeparator() {
+ return "#";
+ }
+
+ public void loadCommitInfos(CDOBranch branch, long startTime, long endTime, CDOCommitInfoHandler handler) {
+ List<Pair<Integer, Long>> keyPairs = getBranchAndTimestamp();
+ // look for branch matches
+ List<Pair<Integer, Long>> matchedBranch = new ArrayList<Pair<Integer, Long>>();
+ if (branch != null) {
+ for (Pair<Integer, Long> keyPair : keyPairs) {
+ if (branch.getID() == keyPair.getElement1()) {
+ matchedBranch.add(keyPair);
+ }
+ }
+ } else {
+ // branch is not defined, we consider all branch/timestamp combinations
+ matchedBranch = keyPairs;
+ }
+
+
+ // if not encoded in the endTime, infos should be returned
+ // ordered in a descending manner (from latter commits to earlier)
+
+ // if endTime < starTime, it means the info count is coded in that parameter
+ // it means that we must return "endTime" commit infos
+ // Depending on the sign of the number (positive or negative)
+ // we should order in a ascending or descending, correspondingly
+
+ long count = CDOCommitInfoUtil.decodeCount(endTime);
+ final boolean descendant;
+ if (count < CDOBranchPoint.UNSPECIFIED_DATE || endTime >= startTime) {
+ descendant = true;
+ } else {
+ descendant = false;
+ }
+ count = Math.abs(count);
+ List<Pair<Integer, Long>> matchedTimestamp = new ArrayList<Pair<Integer, Long>>();
+ Collections.sort(matchedBranch, new Comparator<Pair<Integer, Long>>() {
+ public int compare(Pair<Integer, Long> arg0, Pair<Integer, Long> arg1) {
+ if (descendant) {
+ return arg0.getElement2() > arg1.getElement2() ? -1 : 1;
+ } else {
+ return arg0.getElement2() > arg1.getElement2() ? 1 : -1;
+ }
+ }
+ });
+ int currentCount = 0;
+ for (Pair<Integer, Long> keyPair : matchedBranch) {
+ if (startTime != CDOBranchPoint.UNSPECIFIED_DATE && keyPair.getElement2() < startTime)
+ {
+ continue;
+ }
+ if (endTime != CDOBranchPoint.UNSPECIFIED_DATE && endTime > startTime && keyPair.getElement2() > endTime)
+ {
+ continue;
+ }
+ currentCount++;
+ if (currentCount > count) {
+ break;
+ }
+ matchedTimestamp.add(keyPair);
+ }
+ // Fetch for database actual CommitInfo instances
+ List<JSONCommitInfo> infos = new ArrayList<JSONCommitInfo>();
+ for (Pair<Integer, Long> match : matchedTimestamp) {
+ String key = getCommitInfoKey(match.getElement1(), match.getElement2());
+ Object obj = getValue(key);
+ JSONCommitInfo info = fromJson((String)obj, JSONCommitInfo.class);
+ infos.add(info);
+ }
+
+ InternalRepository repository = (InternalRepository)getStore().getRepository();
+ InternalCDOCommitInfoManager commitInfoManager = repository.getCommitInfoManager();
+ InternalCDOBranchManager branchManager = repository.getBranchManager();
+
+ for (JSONCommitInfo info : infos) {
+ info.handle(branchManager, commitInfoManager, handler);
+ }
+
+ }
+
+ private List<Pair<Integer, Long>> getBranchAndTimestamp() {
+ List<String> splittedKeys = getMultiValue(getCommitInfoListKey());
+ List<Pair<Integer, Long>> keyPairs = new ArrayList<Pair<Integer, Long>>();
+ // Parse branch and key
+ for (String key : splittedKeys) {
+ String[] branchAndTimestamp = key.split(getCommitInfoSeparator());
+ keyPairs.add(new Pair<Integer, Long>(Integer.valueOf(branchAndTimestamp[0]), Long.valueOf(branchAndTimestamp[1])));
+ }
+ return keyPairs;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/CouchbaseHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/CouchbaseHandler.java
new file mode 100644
index 0000000000..f2482fd700
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/CouchbaseHandler.java
@@ -0,0 +1,45 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class CouchbaseHandler {
+
+ private CouchbaseClient client;
+
+ public CouchbaseHandler(CouchbaseClient client) {
+ this.client = client;
+ }
+
+ protected CouchbaseClient getClient() {
+ return client;
+ }
+
+ protected Object getValue(String key) {
+ return getClient().get(key);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected List<String> getMultiValue(String key) {
+ String keys = (String)getValue(key);
+ // FIXME there should not be empty values committed, investigate this
+ if (keys == null || "".equals(keys)) {
+ return Collections.EMPTY_LIST;
+ }
+ String[] splittedValues = keys.split(getSeparator());
+ List<String> result = new ArrayList<String>();
+ for (String value : splittedValues) {
+ result.add(value);
+ }
+ return result;
+ }
+
+ protected String getSeparator() {
+ return ";";
+ }
+
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/ICommitable.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/ICommitable.java
new file mode 100644
index 0000000000..7ae00e11d7
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/ICommitable.java
@@ -0,0 +1,12 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+public interface ICommitable {
+
+ public CDOID getCDOID();
+
+ public void commit(OMMonitor monitor);
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/JSONCommitInfo.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/JSONCommitInfo.java
new file mode 100644
index 0000000000..dcb4af0d17
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/JSONCommitInfo.java
@@ -0,0 +1,47 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
+import org.eclipse.emf.cdo.common.commit.CDOCommitInfoHandler;
+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
+import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager;
+import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
+
+public class JSONCommitInfo
+{
+ private int branchID;
+
+ private long timeStamp;
+
+ private long previousTimeStamp;
+
+ private String userID;
+
+ private String comment;
+
+ public JSONCommitInfo(int branchID, long timeStamp, long previousTimeStamp, String userID, String comment)
+ {
+ this.branchID = branchID;
+ this.timeStamp = timeStamp;
+ this.previousTimeStamp = previousTimeStamp;
+ this.userID = userID;
+ this.comment = comment;
+ }
+
+ public int getBranchID()
+ {
+ return branchID;
+ }
+
+ public long getTimeStamp()
+ {
+ return timeStamp;
+ }
+
+ public void handle(InternalCDOBranchManager branchManager, InternalCDOCommitInfoManager manager,
+ CDOCommitInfoHandler handler)
+ {
+ InternalCDOBranch branch = branchManager.getBranch(branchID);
+ CDOCommitInfo commitInfo = manager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, null);
+ handler.handleCommitInfo(commitInfo);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/JSONHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/JSONHandler.java
new file mode 100644
index 0000000000..4b2c57bb7a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/JSONHandler.java
@@ -0,0 +1,34 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.internal.couchbase.marshall.JSONRevision;
+import org.eclipse.emf.cdo.server.internal.couchbase.marshall.JSONRevisionTypeAdapter;
+
+import com.couchbase.client.CouchbaseClient;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public abstract class JSONHandler extends StoreHandler {
+
+ private Gson gson;
+
+ private void initGson() {
+ GsonBuilder builder = new GsonBuilder();
+ builder.registerTypeAdapter(JSONRevision.class, new JSONRevisionTypeAdapter(getStore()));
+ gson = builder.serializeNulls().create();
+ }
+
+ public JSONHandler(CouchbaseClient client, IStore store) {
+ super(client, store);
+ initGson();
+ }
+
+ protected <TYPE> TYPE fromJson(String jsonString, Class<TYPE> clazz) {
+ return gson.fromJson(jsonString, clazz);
+ }
+
+ protected String toJson(Object elemenToJson) {
+ return gson.toJson(elemenToJson);
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/LobHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/LobHandler.java
new file mode 100644
index 0000000000..9cc0008499
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/LobHandler.java
@@ -0,0 +1,148 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayReader;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+
+import org.eclipse.emf.cdo.common.lob.CDOLobHandler;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.net4j.util.HexUtil;
+import org.eclipse.net4j.util.io.IOUtil;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class LobHandler extends StoreHandler {
+
+ public LobHandler(CouchbaseClient client, IStore store) {
+ super(client, store);
+ }
+
+ public Object readLob(byte[] id) {
+ Object result = getValue(getBlobKey(id));
+ if (result == null) {
+ return getValue(getClobKey(id));
+ }
+ return result;
+ }
+
+ public void loadLob(byte[] id, OutputStream out) {
+ Object rawObject = getValue(getBlobKey(id));
+ if (rawObject != null) {
+ byte[] byteArray = (byte[])rawObject;
+ ByteArrayInputStream in = new ByteArrayInputStream(byteArray);
+ try {
+ IOUtil.copyBinary(in, out, byteArray.length);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ rawObject = getValue(getClobKey(id));
+ char[] charArray = (char[])rawObject;
+ CharArrayReader in = new CharArrayReader(charArray);
+ try {
+ IOUtil.copyCharacter(in, new OutputStreamWriter(out), charArray.length);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
+
+ public ICommitable createWriteBlobCommitable(final byte[] id, final long size, final InputStream inputStream) {
+ return new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ IOUtil.copyBinary(inputStream, out, size);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ doCommit(getBlobKey(id), out.toByteArray(), null, PersistMethod.ADD);
+ doCommit("LOB", HexUtil.bytesToHex(id), null, PersistMethod.APPEND);
+ }
+ };
+ }
+
+ public ICommitable createWriteClobCommitable(final byte[] id, final long size, final Reader reader) {
+ return new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ CharArrayWriter out = new CharArrayWriter();
+ try {
+ IOUtil.copyCharacter(reader, out, size);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ doCommit(getClobKey(id), out.toCharArray(), null, PersistMethod.ADD);
+ doCommit(getAllLobKey(), HexUtil.bytesToHex(id), null, PersistMethod.APPEND);
+ }
+ };
+ }
+
+ public void handleLobs(long fromTime, long toTime, CDOLobHandler handler) throws IOException {
+ for (String id : getMultiValue(getAllLobKey())) {
+ Object rawBlob = getValue(getBlobKey(id));
+ if (rawBlob != null) {
+ byte[] byteArray = (byte[])rawBlob;
+ ByteArrayInputStream in = new ByteArrayInputStream(byteArray);
+ OutputStream out = handler.handleBlob(HexUtil.hexToBytes(id), byteArray.length);
+ if (out != null)
+ {
+ try
+ {
+ IOUtil.copyBinary(in, out, byteArray.length);
+ }
+ finally
+ {
+ IOUtil.close(out);
+ }
+ }
+ } else {
+ Object rawClob = getValue(getClobKey(id));
+ if (rawClob != null) {
+ char[] clob = (char[])rawClob;
+ CharArrayReader in = new CharArrayReader(clob);
+ Writer out = handler.handleClob(HexUtil.hexToBytes(id), clob.length);
+ if (out != null)
+ {
+ try
+ {
+ IOUtil.copyCharacter(in, out, clob.length);
+ }
+ finally
+ {
+ IOUtil.close(out);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected String getBlobKey(byte[] id) {
+ return getBlobKey(HexUtil.bytesToHex(id));
+ }
+
+ protected String getBlobKey(String id) {
+ return "BLOB::" + id;
+ }
+
+ protected String getClobKey(byte[] id) {
+ return getClobKey(HexUtil.bytesToHex(id));
+ }
+
+ protected String getClobKey(String id) {
+ return "CLOB::" + id;
+ }
+
+ protected String getAllLobKey() {
+ return "LOB";
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/LockingHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/LockingHandler.java
new file mode 100644
index 0000000000..592e45f1d1
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/LockingHandler.java
@@ -0,0 +1,167 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea.Handler;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockAreaNotFoundException;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.internal.couchbase.marshall.JSONLockArea;
+import org.eclipse.emf.cdo.spi.server.InternalLockManager;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class LockingHandler extends JSONHandler {
+
+ public LockingHandler(CouchbaseClient client, IStore store) {
+ super(client, store);
+ }
+
+ public LockArea getLockArea(String durableLockingID) throws LockAreaNotFoundException
+ {
+ JSONLockArea primitive = readJSONLockArea(durableLockingID);
+ if (primitive != null) {
+ return JSONLockArea.getLockArea(getStore(), primitive);
+ }
+ throw new LockAreaNotFoundException(durableLockingID);
+ }
+
+ public LockArea createLockArea(String userID, CDOBranchPoint branchPoint, boolean readOnly, Map<CDOID, LockGrade> locks)
+ {
+ String durableLockingID = getNextDurableLockingID();
+ LockArea lockArea = CDOLockUtil.createLockArea(durableLockingID, userID, branchPoint, readOnly, locks);
+ storeLockArea(lockArea);
+ return lockArea;
+ }
+
+ public void lock(String durableLockingID, LockType type, Collection<? extends Object> objectsToLock)
+ {
+ // TODO Refactor. Next chunk of code copied verbatim from MEMStore.lock
+ LockArea area = getLockArea(durableLockingID);
+ Map<CDOID, LockGrade> locks = area.getLocks();
+
+ InternalLockManager lockManager = (InternalLockManager)getStore().getRepository().getLockingManager();
+ for (Object objectToLock : objectsToLock)
+ {
+ CDOID id = lockManager.getLockKeyID(objectToLock);
+ LockGrade grade = locks.get(id);
+ if (grade != null)
+ {
+ grade = grade.getUpdated(type, true);
+ }
+ else
+ {
+ grade = LockGrade.get(type);
+ }
+
+ locks.put(id, grade);
+ }
+
+ storeLockArea(area);
+ }
+
+ public void unlock(String durableLockingID, LockType type, Collection<? extends Object> objectsToUnlock) {
+ // TODO (CD) Refactor? Next chunk of code copied verbatim from MEMStore.lock
+ LockArea area = getLockArea(durableLockingID);
+ Map<CDOID, LockGrade> locks = area.getLocks();
+ InternalLockManager lockManager = (InternalLockManager) getStore() .getRepository().getLockingManager();
+ for (Object objectToUnlock : objectsToUnlock) {
+ CDOID id = lockManager.getLockKeyID(objectToUnlock);
+ LockGrade grade = locks.get(id);
+ if (grade != null) {
+ grade = grade.getUpdated(type, false);
+ if (grade == LockGrade.NONE) {
+ locks.remove(id);
+ } else {
+ locks.put(id, grade);
+ }
+ }
+ }
+
+ storeLockArea(area);
+ }
+
+ public void unlock(String durableLockingID) {
+ LockArea area = getLockArea(durableLockingID);
+ Map<CDOID, LockGrade> locks = area.getLocks();
+ locks.clear();
+ storeLockArea(area);
+ }
+
+ // FIXME if user id is a prefix, and not the full userID, this method will fail
+ public void getLockAreas(String userIDPrefix, Handler handler) {
+ // the framework requests with userIDPrefix == "" to
+ // get all the persisted locks
+ List<String> lockIds = userIDPrefix.length() == 0 ? getMultiValue(getAllLocksKey()) : getMultiValue(getLockUserKey(userIDPrefix));
+ for (String lockId : lockIds) {
+ System.out.println();
+ LockArea lockArea = getLockArea(lockId);
+ handler.handleLockArea(lockArea);
+ }
+ }
+
+ public void deleteLockArea(final String durableLockingID) {
+ new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ LockArea lockArea = getLockArea(durableLockingID);
+ doCommit(durableLockingID, null, null, PersistMethod.DELETE);
+ doCommit(getLockUserKey(lockArea), durableLockingID, null, PersistMethod.DELETE_APPENDED);
+ doCommit(getAllLocksKey(), durableLockingID, null, PersistMethod.DELETE_APPENDED);
+ }
+ }.commit(null);
+ }
+
+ private void storeLockArea(final LockArea area)
+ {
+ new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ JSONLockArea jsonLockArea = JSONLockArea.getJSONLockArea(area);
+ doCommit(jsonLockArea.getId(), toJson(jsonLockArea), null, PersistMethod.SET);
+ doCommit(getLockUserKey(area), jsonLockArea.getId(), null, PersistMethod.APPEND_IF_NOT_CONTAINED);
+ doCommit(getAllLocksKey(), jsonLockArea.getId(), null, PersistMethod.APPEND_IF_NOT_CONTAINED);
+ }
+ }.commit(null);
+ }
+
+ private String getLockUserKey(final LockArea area) {
+ return getLockUserKey(area.getUserID());
+ }
+
+ private String getLockUserKey(final String userName) {
+ return "LockUser::" + userName;
+ }
+
+ private String getAllLocksKey() {
+ return "AllLocks";
+ }
+
+ private JSONLockArea readJSONLockArea(String durableLockingID) throws LockAreaNotFoundException
+ {
+ String jsonString = (String)getValue(durableLockingID);
+ if (jsonString != null) {
+ return fromJson(jsonString, JSONLockArea.class);
+ }
+ return null;
+ }
+
+ // TODO: Refactor -- this was copied verbatim from DurableLockingManager
+ private String getNextDurableLockingID() {
+ for (;;) {
+ String durableLockingID = CDOLockUtil.createDurableLockingID();
+ try {
+ getLockArea(durableLockingID); // Check uniqueness
+ // Not unique; try once more...
+ } catch (LockAreaNotFoundException ex) {
+ return durableLockingID;
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/PackageUnitHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/PackageUnitHandler.java
new file mode 100644
index 0000000000..f6bc45c241
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/PackageUnitHandler.java
@@ -0,0 +1,53 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.cdo.common.model.EMFUtil;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.internal.couchbase.marshall.JSONPackageUnit;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class PackageUnitHandler extends JSONHandler {
+
+ public PackageUnitHandler(CouchbaseClient client, IStore store) {
+ super(client, store);
+ }
+
+ protected String getPackageUnitsKey() {
+ return "CDOPackageUnits";
+ }
+
+ public Collection<InternalCDOPackageUnit> readPackageUnits() {
+ List<String> packageUnits = getMultiValue(getPackageUnitsKey());
+ List<InternalCDOPackageUnit> result = new ArrayList<InternalCDOPackageUnit>();
+ for(String packageID : packageUnits) {
+ result.add(readPackageUnit(packageID));
+ }
+ return result;
+ }
+
+ public InternalCDOPackageUnit readPackageUnit(String id) {
+ return JSONPackageUnit.getPackageUnit(fromJson((String)getValue(id), JSONPackageUnit.class));
+ }
+
+ public EPackage[] loadPackageUnit(InternalCDOPackageUnit packageUnit) {
+ JSONPackageUnit jsonPackageUnit = fromJson((String)getValue(packageUnit.getTopLevelPackageInfo().getPackageURI()), JSONPackageUnit.class);
+ return EMFUtil.getAllPackages(jsonPackageUnit.getEPackage());
+ }
+
+ public ICommitable createPackageUnitCommitable(final InternalCDOPackageUnit packageUnit) {
+ return new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ JSONPackageUnit jsonPackageUnit = JSONPackageUnit.getJsonPackageUnit(packageUnit, getStore());
+ doCommit(getPackageUnitsKey(), packageUnit.getID(), null, PersistMethod.APPEND);
+ doCommit(packageUnit.getID(), toJson(jsonPackageUnit), null, PersistMethod.SET);
+ }
+ };
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/ResourceHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/ResourceHandler.java
new file mode 100644
index 0000000000..148623246b
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/ResourceHandler.java
@@ -0,0 +1,154 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.util.List;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.eresource.EresourcePackage;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class ResourceHandler extends JSONHandler {
+
+ public ResourceHandler(CouchbaseClient client, IStore store) {
+ super(client, store);
+ }
+
+ /**
+ * We are persisting here:
+ * - Association folder + name = resourceID
+ * - Association resourceID = parentFolderID
+ * - Association resourceID = resourceName
+ * - List of all resources
+ */
+ public ICommitable createStoreResourceCommitable(final InternalCDORevision revision) {
+ return new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ if (EresourcePackage.eINSTANCE.getCDOResourceNode().isSuperTypeOf(revision.getEClass())) {
+ String currentName = (String)revision.get(EresourcePackage.eINSTANCE.getCDOResourceNode_Name(), 0);
+ Long resourceID = (Long)getValue(getResourceIDKey(revision));
+ if (resourceID == null || resourceID == CDOIDUtil.getLong(revision.getID())) {
+ Long formerFolder = (Long)getValue(getResourceFolderKey(revision));
+ Long currentFolder = CDOIDUtil.getLong((CDOID)revision.getContainerID());
+ formerFolder = formerFolder != null ? formerFolder : currentFolder;
+ String formerName = (String)getValue(getResourceNameKey(revision));
+ if (currentFolder != formerFolder || formerName != currentName) { // this updates data in case path changed
+ doCommit(getAllResourceKey(), getResourceIDKey(formerFolder, formerName), revision.getID(), PersistMethod.DELETE_APPENDED);
+ doCommit(getResourceIDKey(formerFolder, formerName), null, null, PersistMethod.DELETE);
+ }
+ doCommit(getResourceIDKey(revision), getResourceID(revision), revision.getID(), PersistMethod.SET);
+ doCommit(getResourceFolderKey(revision), CDOIDUtil.getLong((CDOID)revision.getContainerID()), revision.getID(), PersistMethod.SET);
+ doCommit(getResourceNameKey(revision), currentName == null? "" : currentName, revision.getID(), PersistMethod.SET);
+ // FIXME APPEND_IF_NOT_CONTAINED is highly inefficient
+ doCommit(getAllResourceKey(), getResourceIDKey(revision), revision.getID(), PersistMethod.APPEND_IF_NOT_CONTAINED);
+ } else {
+ throw new RuntimeException("Duplicate Resource " + currentName);
+ }
+ }
+ }
+ };
+ }
+
+ public ICommitable createDetachResourceCommitable(final InternalCDORevision revision) {
+ return new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ if (EresourcePackage.eINSTANCE.getCDOResourceNode().isSuperTypeOf(revision.getEClass())) {
+ doCommit(getResourceFolderKey(revision), null, null, PersistMethod.DELETE);
+ doCommit(getResourceNameKey(revision), null, null, PersistMethod.DELETE);
+ doCommit(getResourceIDKey(revision), getResourceID(revision), revision.getID(), PersistMethod.DELETE);
+ doCommit(getAllResourceKey(), getResourceIDKey(revision), revision.getID(), PersistMethod.DELETE_APPENDED);
+ }
+ }
+ };
+ }
+
+ protected String getResourceIDKey(InternalCDORevision revision) {
+ String name = (String)revision.get(EresourcePackage.eINSTANCE.getCDOResourceNode_Name(), 0);
+ return getResourceIDKey(CDOIDUtil.getLong((CDOID)revision.getContainerID()), name);
+ }
+
+ protected String getResourceIDKey(long containerID, String resourceName) {
+ return "CDOResources::" + containerID + "::" + resourceName;
+ }
+
+ protected String getAllResourceKey() {
+ return "AllCDOResources";
+ }
+
+ protected String getResourceFolderKey(InternalCDORevision revision) {
+ return getResourceFolderKey(CDOIDUtil.getLong(revision.getID()));
+ }
+
+ protected String getResourceNameKey(InternalCDORevision revision) {
+ return getResourceNameKey(CDOIDUtil.getLong(revision.getID()));
+ }
+
+ protected String getResourceFolderKey(long resourceID) {
+ return "CDOResourceFolder::" + resourceID;
+ }
+
+ protected String getResourceNameKey(long resourceID) {
+ return "CDOResourceName::" + resourceID;
+ }
+
+ protected Long getResourceID(InternalCDORevision revision) {
+ return CDOIDUtil.getLong(revision.getID());
+ }
+
+ protected String getResourceKey(IStoreAccessor.QueryResourcesContext context) {
+ final long folderID = CDOIDUtil.getLong(context.getFolderID());
+ final String name = context.getName();
+ return getResourceIDKey(folderID, name);
+ }
+
+ private String getNameFromID(String resourceID) {
+ String[] splitted = resourceID.split("::");
+ return splitted[2];
+ }
+
+ private Long getFolderFromID(String resourceID) {
+ String[] splitted = resourceID.split("::");
+ return Long.parseLong(splitted[1]);
+ }
+
+ private void addExistingResourceToContext(QueryResourcesContext context,
+ String resourceID) {
+ Long result = (Long)getValue(resourceID);
+ if (result != null) {
+ CDOID id = CDOIDUtil.createLong(result);
+ context.addResource(id);
+ }
+ }
+
+ public void queryResources(QueryResourcesContext context) {
+ final boolean exactMatch = context.exactMatch();
+ if (exactMatch) {
+ Long result = (Long)getValue(getResourceKey(context));
+ if (result != null) {
+ CDOID id = CDOIDUtil.createLong(result);
+ context.addResource(id);
+ }
+ } else {
+ // FIXME This is not efficient, maybe implement with Couchbase queries?
+ List<String> resourceIDs = getMultiValue(getAllResourceKey());
+ CDOID folderID = context.getFolderID();
+ for (String resourceID : resourceIDs) {
+ if (getNameFromID(resourceID).startsWith(context.getName())) {
+ if (folderID != null && folderID != CDOID.NULL) {
+ if (CDOIDUtil.getLong(folderID) == getFolderFromID(resourceID)) {
+ addExistingResourceToContext(context, resourceID);
+ }
+ } else {
+ // if no folder restriction is not defined in the context, we check all resources
+ addExistingResourceToContext(context, resourceID);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/RevisionHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/RevisionHandler.java
new file mode 100644
index 0000000000..00aa1b05c7
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/RevisionHandler.java
@@ -0,0 +1,175 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
+import org.eclipse.emf.cdo.server.internal.couchbase.marshall.JSONRevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.net4j.util.ObjectUtil;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class RevisionHandler extends JSONHandler {
+
+ private ResourceHandler resourceHandler;
+
+ public RevisionHandler(CouchbaseClient client, IStore store) {
+ super(client, store);
+ resourceHandler = new ResourceHandler(getClient(), getStore());
+ }
+
+ public ICommitable createRevisionWriteCommitable(final InternalCDORevision revision) {
+ return new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ resourceHandler.createStoreResourceCommitable(revision).commit(monitor);
+ JSONRevision rev = JSONRevision.getJSONRevision(revision);
+ doCommit(getRevisionByIdAndBranchKey(revision), toJson(rev), revision.getID(), PersistMethod.SET);
+ //FIXME modeling this information as lists wont scale well, and introduces overhead on writting, and this info is not requested usually
+ // Investigate Couchbase queries
+ doCommit(getRevisionByEClassKey(revision), CDOIDUtil.getLong(revision.getID()), revision.getID(), PersistMethod.APPEND_IF_NOT_CONTAINED);
+ doCommit(getRevisionByEClassAndBranchKey(revision), CDOIDUtil.getLong(revision.getID()), revision.getID(), PersistMethod.APPEND_IF_NOT_CONTAINED);
+ doCommit(getAllRevisionInBranchKey(revision.getBranch()), CDOIDUtil.getLong(revision.getID()), revision.getID(), PersistMethod.APPEND_IF_NOT_CONTAINED);
+ }
+ };
+ }
+
+ public ICommitable createRevisionDetachCommitable(final CDOID id, final CDOBranch branch) {
+ return new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ InternalCDORevision revision = readRevision(id, branch);
+ resourceHandler.createDetachResourceCommitable(revision).commit(monitor);
+ doCommit(getRevisionByIdAndBranchKey(revision), null, id, PersistMethod.DELETE);
+ doCommit(getRevisionByEClassKey(revision), CDOIDUtil.getLong(id), id, PersistMethod.DELETE_APPENDED);
+ doCommit(getRevisionByEClassAndBranchKey(revision), CDOIDUtil.getLong(id), id, PersistMethod.DELETE_APPENDED);
+ doCommit(getAllRevisionInBranchKey(revision.getBranch()), CDOIDUtil.getLong(revision.getID()), revision.getID(), PersistMethod.DELETE_APPENDED);
+ }
+ };
+ }
+
+ public InternalCDORevision readRevision(CDOID id, CDOBranchPoint branchPoint) {
+ return readRevision(id, branchPoint.getBranch());
+ }
+
+ public InternalCDORevision readRevision(CDOID id, CDOBranch branch) {
+ String key = getRevisionByIdAndBranchKey(id, branch);
+ String jsonString = (String)getValue(key);
+ if (jsonString == null) {
+ return null;
+ }
+ JSONRevision revision = fromJson(jsonString, JSONRevision.class);
+ return JSONRevision.getCDORevision(getStore(), revision);
+ }
+
+ public List<CDOID> readAllRevisionsInBranch(CDOBranch branch) {
+ return getCDOIDList(getMultiValue(getAllRevisionInBranchKey(branch)));
+ }
+
+ public List<CDOID> readAllRevisionsOfEClassInBranch(EClass eClass, CDOBranch branch) {
+ return getCDOIDList(getMultiValue(getRevisionByEClassAndBranchKey(eClass, branch)));
+ }
+
+ public void handleRevisions(EClass eClass, CDOBranch branch, long timeStamp, boolean exactTime, CDORevisionHandler handler) {
+ for (CDOID id : eClass != null ? readAllRevisionsOfEClassInBranch(eClass, branch) : readAllRevisionsInBranch(branch)) {
+ InternalCDORevision revision = readRevision(id, branch);
+ if (timeStamp != CDOBranchPoint.INVALID_DATE)
+ {
+ if (exactTime)
+ {
+ if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE && revision.getTimeStamp() != timeStamp)
+ {
+ continue;
+ }
+ }
+ else
+ {
+ if (!revision.isValid(timeStamp))
+ {
+ continue;
+ }
+ }
+ }
+ handler.handleRevision(revision);
+ }
+ }
+
+ private List<CDOID> getCDOIDList(List<String> cdoids) {
+ List<CDOID> ids = new ArrayList<CDOID>();
+ for (String id : cdoids) {
+ CDOID cdoid = CDOIDUtil.createLong(Long.parseLong(id));
+ ids.add(cdoid);
+ }
+ return ids;
+ }
+
+ protected String getRevisionByIdAndBranchKey(InternalCDORevision revision) {
+ return getRevisionByIdAndBranchKey(revision.getID(), revision.getBranch());
+ }
+
+ protected String getRevisionByIdAndBranchKey(CDOID id, CDOBranch branch) {
+ return "CDORevision::" + branch.getName() + "::" + CDOIDUtil.getLong(id);
+ }
+
+ protected String getRevisionByEClassKey(InternalCDORevision revision) {
+ return getRevisionByEClassKey(revision.getEClass());
+ }
+
+ protected String getRevisionByEClassKey(EClass eClass) {
+ return "RevisionByEClass::" + eClass.getEPackage().getNsURI() + "::" + eClass.getName();
+ }
+
+ protected String getRevisionByEClassAndBranchKey(InternalCDORevision revision) {
+ return getRevisionByEClassAndBranchKey(revision.getEClass(), revision.getBranch());
+ }
+
+ protected String getRevisionByEClassAndBranchKey(EClass eClass, CDOBranch branch) {
+ return "RevisionByEClassAndBranch::" + eClass.getEPackage().getNsURI()
+ + "::" + eClass.getName() + branch.getName();
+ }
+
+ protected String getAllRevisionInBranchKey(CDOBranch branch) {
+ return "AllCDORevision::" + branch.getName();
+ }
+
+ public void queryXRefs(QueryXRefsContext context) {
+ final CDOBranch branch = context.getBranch();
+ for (final CDOID target : context.getTargetObjects().keySet())
+ {
+ for (final EClass eClass : context.getSourceCandidates().keySet())
+ {
+ final List<EReference> eReferences = context.getSourceCandidates().get(eClass);
+ for (EReference eReference : eReferences) {
+ List<String> byEClassIds = getMultiValue(getRevisionByEClassKey(eClass));
+ for (String id : byEClassIds) {
+ CDOID source = CDOIDUtil.createLong(Long.parseLong(id));
+ InternalCDORevision revision = readRevision(source, branch);
+ Object obj = revision.getValue(eReference);
+ if (obj instanceof CDOID) {
+ if (ObjectUtil.equals(obj, target)) {
+ context.addXRef(target, source, eReference, 0);
+ }
+ } else if (obj instanceof List<?>) {
+ int index = 0;
+ for (Object objFromList :(List<?>)obj) {
+ if (ObjectUtil.equals(objFromList, target)) {
+ context.addXRef(target, source, eReference, index);
+ }
+ ++index;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/StoreHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/StoreHandler.java
new file mode 100644
index 0000000000..60dde58809
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/StoreHandler.java
@@ -0,0 +1,19 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import org.eclipse.emf.cdo.server.IStore;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class StoreHandler extends CouchbaseHandler {
+
+ private IStore store;
+
+ public StoreHandler(CouchbaseClient client, IStore store) {
+ super(client);
+ this.store = store;
+ }
+
+ protected IStore getStore() {
+ return store;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/StoreMetaHandler.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/StoreMetaHandler.java
new file mode 100644
index 0000000000..22c1a62a7d
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/commitables/StoreMetaHandler.java
@@ -0,0 +1,151 @@
+package org.eclipse.emf.cdo.server.internal.commitables;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import com.couchbase.client.CouchbaseClient;
+
+public class StoreMetaHandler extends CouchbaseHandler {
+
+ public StoreMetaHandler(CouchbaseClient client) {
+ super(client);
+ }
+
+ public Long getLastCDOID() {
+ return (Long)getValue(getLastCDOIDKey());
+ }
+
+ public Boolean isFirstStart() {
+ Boolean result = (Boolean)getValue(getIsFirstStartKey());
+ if (result != null) {
+ return result;
+ }
+ return true;
+ }
+
+ public void setLastCDOID(final Long lastCDOID) {
+ new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ doCommit(getLastCDOIDKey(), lastCDOID, null, PersistMethod.SET);
+ }
+ }.commit(null);
+ }
+
+ public void setIsFirstStart(final Boolean firstStart) {
+ new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ doCommit(getIsFirstStartKey(), firstStart, null, PersistMethod.SET);
+ }
+ }.commit(null);
+ }
+
+ public Long getCreationTime() {
+ Long value = (Long)getValue(getCreationTimeKey());
+ if (value != null) {
+ return value;
+ }
+ value = System.currentTimeMillis();
+ setCreationTime(value);
+ return value;
+ }
+
+ public void setCreationTime(final long creationTime) {
+ new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ doCommit(getCreationTimeKey(), creationTime, null, PersistMethod.SET);
+ }
+ }.commit(null);
+ }
+
+ public Long getLastCommitTime() {
+ Long value = (Long)getValue(getLastCommitTimeKey());
+ if (value != null) {
+ return value;
+ }
+ return 0l;
+ }
+
+ public void setLastCommitTime(final long commitTime) {
+ new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ doCommit(getLastCommitTimeKey(), commitTime, null, PersistMethod.SET);
+ }
+ }.commit(null);
+ }
+
+ public Map<String, String> getPersistentProperties(Set<String> names) {
+
+ if (names == null || names.isEmpty())
+ {
+ List<String> propertyKeys = getMultiValue(getAllPropertyKey());
+ Map<String, String> result = new HashMap<String, String>();
+ for (String propertyKey : propertyKeys) {
+ result.put(propertyKey, (String)getValue(getPropertyKey(propertyKey)));
+ }
+ return result;
+ }
+
+ Map<String, String> result = new HashMap<String, String>();
+ for (String key : names)
+ {
+ String value = (String)getValue(getPropertyKey(key));
+ if (value != null)
+ {
+ result.put(key, value);
+ }
+ }
+
+ return result;
+ }
+
+ public void setPersistentProperties(final Map<String, String> properties) {
+ new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ for (String key : properties.keySet()) {
+ doCommit(getPropertyKey(key), properties.get(key), null, PersistMethod.SET);
+ doCommit(getAllPropertyKey(), key, null, PersistMethod.APPEND_IF_NOT_CONTAINED);
+ }
+ }
+ }.commit(null);
+
+ }
+
+ public void removePersistentProperties(final Set<String> names) {
+ new AbstractCommitable(getClient()) {
+ public void commit(OMMonitor monitor) {
+ for (String key : names) {
+ doCommit(getPropertyKey(key), null, null, PersistMethod.DELETE);
+ doCommit(getAllPropertyKey(), key, null, PersistMethod.DELETE_APPENDED);
+ }
+ }
+ }.commit(null);
+ }
+
+ private String getLastCDOIDKey() {
+ return "lastCDOID";
+ }
+
+ private String getIsFirstStartKey() {
+ return "isFirstStart";
+ }
+
+ private String getCreationTimeKey() {
+ return "creationTime";
+ }
+
+ private String getLastCommitTimeKey() {
+ return "lastCommitTime";
+ }
+
+ private String getAllPropertyKey() {
+ return "AllStoreProperties";
+ }
+
+ private String getPropertyKey(String key) {
+ return "StoreProperty::" + key;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/bundle/OM.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/bundle/OM.java
new file mode 100644
index 0000000000..20138f420a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/bundle/OM.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010-2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+
+package org.eclipse.emf.cdo.server.internal.couchbase.bundle;
+
+import org.eclipse.net4j.util.om.OMBundle;
+import org.eclipse.net4j.util.om.OMPlatform;
+import org.eclipse.net4j.util.om.OSGiActivator;
+import org.eclipse.net4j.util.om.log.OMLogger;
+import org.eclipse.net4j.util.om.trace.OMTracer;
+
+/**
+ * The <em>Operations & Maintenance</em> class of this bundle.
+ *
+ * @author Victor Roldan Betancort
+ */
+public abstract class OM
+{
+ public static final String BUNDLE_ID = "org.eclipse.emf.cdo.server.couchbase"; //$NON-NLS-1$
+
+ public static final OMBundle BUNDLE = OMPlatform.INSTANCE.bundle(BUNDLE_ID, OM.class);
+
+ public static final OMTracer DEBUG = BUNDLE.tracer("debug"); //$NON-NLS-1$
+
+ public static final OMLogger LOG = BUNDLE.logger();
+
+ /**
+ * @author Victor Roldan Betancort
+ */
+ public static final class Activator extends OSGiActivator
+ {
+ public Activator()
+ {
+ super(BUNDLE);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockArea.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockArea.java
new file mode 100644
index 0000000000..56ecea43c4
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockArea.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2011-2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Caspar De Groot - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.internal.couchbase.marshall;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchManager;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade;
+import org.eclipse.emf.cdo.server.IStore;
+
+/**
+ * @author Victor Roldan Betancort TODO Verbatim copy of DB4OLockArea. Refactor
+ */
+public class JSONLockArea {
+
+ private String id;
+
+ private String userID;
+
+ private long timestamp;
+
+ private int branchID;
+
+ private boolean readOnly;
+
+ private List<JSONLockEntry> lockEntries = new LinkedList<JSONLockEntry>();
+
+ public static JSONLockArea getJSONLockArea(LockArea lockArea) {
+ JSONLockArea jsonLockArea = new JSONLockArea();
+
+ jsonLockArea.setId(lockArea.getDurableLockingID());
+ jsonLockArea.setUserID(lockArea.getUserID());
+ jsonLockArea.setTimestamp(lockArea.getTimeStamp());
+ jsonLockArea.setBranchID(lockArea.getBranch().getID());
+ jsonLockArea.setReadOnly(lockArea.isReadOnly());
+
+ List<JSONLockEntry> newList = JSONLockEntry.getPrimitiveLockEntries(jsonLockArea, lockArea.getLocks());
+ jsonLockArea.setLockEntries(newList);
+
+ return jsonLockArea;
+ }
+
+ public static LockArea getLockArea(IStore store, JSONLockArea jsonLockArea) {
+ // Reconstruct the branchpoint
+ //
+ CDOBranchManager branchManager = store.getRepository().getBranchManager();
+ CDOBranch branch = branchManager.getBranch(jsonLockArea.getBranchID());
+ CDOBranchPoint branchpoint = branch.getPoint(jsonLockArea.getTimestamp());
+
+ // Reconstruct the lockMap
+ //
+ Map<CDOID, LockGrade> lockMap = CDOIDUtil.createMap();
+ for (JSONLockEntry entry : jsonLockArea.getLockEntries()) {
+ CDOID cdoid = CDOIDUtil.createLong(entry.getCdoID());
+ LockGrade lockGrade = LockGrade.get(entry.getLockGrade());
+ lockMap.put(cdoid, lockGrade);
+ }
+
+ return CDOLockUtil.createLockArea(jsonLockArea.getId(),
+ jsonLockArea.getUserID(), branchpoint,
+ jsonLockArea.isReadOnly(), lockMap);
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getUserID() {
+ return userID;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public int getBranchID() {
+ return branchID;
+ }
+
+ public List<JSONLockEntry> getLockEntries() {
+ return lockEntries;
+ }
+
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ public void setReadOnly(boolean readOnly) {
+ this.readOnly = readOnly;
+ }
+
+ public void setUserID(String userID) {
+ this.userID = userID;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public void setBranchID(int branchID) {
+ this.branchID = branchID;
+ }
+
+ private void setLockEntries(List<JSONLockEntry> lockEntries) {
+ this.lockEntries = lockEntries;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockAreaTypeAdapter.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockAreaTypeAdapter.java
new file mode 100644
index 0000000000..ffb88fdfd9
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockAreaTypeAdapter.java
@@ -0,0 +1,66 @@
+package org.eclipse.emf.cdo.server.internal.couchbase.marshall;
+
+import java.lang.reflect.Type;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+public class JSONLockAreaTypeAdapter implements JsonDeserializer<JSONLockArea>,
+ JsonSerializer<JSONLockArea> {
+
+ private static final String ID = "id";
+ private static final String USER_ID = "user_id";
+ private static final String BRANCH_ID = "branch_id";
+ private static final String TIMESTAMP = "timestamp";
+ private static final String READONLY = "readonly";
+ private static final String ENTRY_CDOID = "entry_cdoid_";
+ private static final String ENTRY_GRADE = "entry_grade_";
+
+ public JsonElement serialize(JSONLockArea arg0, Type arg1, JsonSerializationContext arg2) {
+ JsonObject obj = new JsonObject();
+ obj.addProperty(ID, arg0.getId());
+ obj.addProperty(USER_ID, arg0.getUserID());
+ obj.addProperty(BRANCH_ID, arg0.getBranchID());
+ obj.addProperty(TIMESTAMP, arg0.getTimestamp());
+ obj.addProperty(READONLY, arg0.isReadOnly());
+ int count = 0;
+ for (JSONLockEntry entry : arg0.getLockEntries()) {
+ obj.addProperty(getEntryCDOIDKey(count), entry.getCdoID());
+ obj.addProperty(getEntryGradeKey(count), entry.getLockGrade());
+ count++;
+ }
+ return obj;
+ }
+
+ public JSONLockArea deserialize(JsonElement arg0, Type arg1, JsonDeserializationContext arg2) throws JsonParseException {
+ JSONLockArea jsonLockArea = new JSONLockArea();
+ JsonObject json = (JsonObject) arg0;
+ jsonLockArea.setId(json.get(ID).getAsString());
+ jsonLockArea.setUserID(json.get(USER_ID).getAsString());
+ jsonLockArea.setBranchID(json.get(BRANCH_ID).getAsInt());
+ jsonLockArea.setTimestamp(json.get(TIMESTAMP).getAsLong());
+ jsonLockArea.setReadOnly(json.get(READONLY).getAsBoolean());
+ for (int i = 0; true; i++) {
+ if (json.get(getEntryCDOIDKey(i)) != null) {
+ jsonLockArea.getLockEntries().add(new JSONLockEntry(json.get(getEntryCDOIDKey(i))
+ .getAsLong(), json.get(getEntryGradeKey(i)).getAsInt()));
+ } else {
+ break;
+ }
+ }
+ return jsonLockArea;
+ }
+
+ private String getEntryCDOIDKey(int count) {
+ return ENTRY_CDOID + count;
+ }
+
+ private String getEntryGradeKey(int count) {
+ return ENTRY_GRADE + count;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockEntry.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockEntry.java
new file mode 100644
index 0000000000..71c8d6144b
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONLockEntry.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2011, 2012 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Caspar De Groot - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.internal.couchbase.marshall;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * @author Victor Roldan Betancort
+ * TODO Verbatim copy of DB4OLockArea. Refactor
+ */
+public class JSONLockEntry
+{
+ private long cdoID;
+
+ private int lockGrade;
+
+ public JSONLockEntry(long longCdoID, int intLockGrade)
+ {
+ cdoID = longCdoID;
+ lockGrade = intLockGrade;
+ }
+
+ public static List<JSONLockEntry> getPrimitiveLockEntries(JSONLockArea jsonLockArea, Map<CDOID, LockGrade> locks)
+ {
+ List<JSONLockEntry> newList = new LinkedList<JSONLockEntry>();
+
+ for (Entry<CDOID, LockGrade> entry : locks.entrySet())
+ {
+ CDOID cdoid = entry.getKey();
+ long longCdoID = CDOIDUtil.getLong(cdoid);
+
+ LockGrade lockGrade = entry.getValue();
+ int intLockGrade = lockGrade.getValue();
+
+ JSONLockEntry lockEntry = getEntry(jsonLockArea.getLockEntries(), longCdoID);
+ if (lockEntry == null)
+ {
+ lockEntry = new JSONLockEntry(longCdoID, intLockGrade);
+ }
+ else
+ {
+ lockEntry.setLockGrade(intLockGrade);
+ }
+
+ newList.add(lockEntry);
+ }
+
+ return newList;
+ }
+
+ private void setLockGrade(int lockGrade)
+ {
+ this.lockGrade = lockGrade;
+ }
+
+ // TODO (CD) Avoid linear search
+ private static JSONLockEntry getEntry(List<JSONLockEntry> entries, long targetID)
+ {
+ for (JSONLockEntry entry : entries)
+ {
+ if (entry.cdoID == targetID)
+ {
+ return entry;
+ }
+ }
+
+ return null;
+ }
+
+ public long getCdoID()
+ {
+ return cdoID;
+ }
+
+ public int getLockGrade()
+ {
+ return lockGrade;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONPackageUnit.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONPackageUnit.java
new file mode 100644
index 0000000000..8ae8cea174
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONPackageUnit.java
@@ -0,0 +1,154 @@
+package org.eclipse.emf.cdo.server.internal.couchbase.marshall;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.cdo.common.model.CDOModelUtil;
+import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
+import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
+import org.eclipse.emf.cdo.common.model.EMFUtil;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
+import org.eclipse.net4j.util.collection.Pair;
+
+public class JSONPackageUnit {
+
+ private String id;
+
+ private Integer originalType;
+
+ private Long timeStamp;
+
+ private List<Byte> ePackageBytes;
+
+ private List<Pair<String, String>> packageInfos;
+
+ public JSONPackageUnit(String id, Integer originalType, Long timeStamp,
+ List<Byte> ePackageBytes, List<Pair<String, String>> packageIntos) {
+ this.setId(id);
+ this.setOriginalType(originalType);
+ this.setTimeStamp(timeStamp);
+ this.setEPackageBytes(ePackageBytes);
+ this.setPackageInfos(packageIntos);
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Integer getOriginalType() {
+ return originalType;
+ }
+
+ public Long getTimeStamp() {
+ return timeStamp;
+ }
+
+ public List<Byte> getEPackageBytes() {
+ return ePackageBytes;
+ }
+
+ public List<Pair<String, String>> getPackageInfos() {
+ return packageInfos;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setOriginalType(Integer originalType) {
+ this.originalType = originalType;
+ }
+
+ public void setTimeStamp(Long timeStamp) {
+ this.timeStamp = timeStamp;
+ }
+
+ public void setEPackageBytes(List<Byte> ePackageBytes) {
+ this.ePackageBytes = ePackageBytes;
+ }
+
+ public void setPackageInfos(List<Pair<String, String>> packageInfos) {
+ this.packageInfos = packageInfos;
+ }
+
+ public EPackage getEPackage() {
+ return getEPackageFromBytes(getEPackageBytes());
+ }
+
+ public static InternalCDOPackageUnit getPackageUnit(JSONPackageUnit jsonPackageUnit) {
+ InternalCDOPackageUnit cdoPackageUnit = (InternalCDOPackageUnit) CDOModelUtil.createPackageUnit();
+ cdoPackageUnit.setOriginalType(CDOPackageUnit.Type.values()[jsonPackageUnit.getOriginalType()]);
+ cdoPackageUnit.setTimeStamp(jsonPackageUnit.getTimeStamp());
+ cdoPackageUnit.setPackageInfos(getPackageInfos(jsonPackageUnit.getPackageInfos()));
+ return cdoPackageUnit;
+ }
+
+ public static JSONPackageUnit getJsonPackageUnit(InternalCDOPackageUnit packageUnit, IStore store) {
+ String id = new String(packageUnit.getID());
+ Integer originalType = new Integer(packageUnit.getOriginalType().ordinal());
+ Long timeStamp = new Long(packageUnit.getTimeStamp());
+ List<Byte> ePackageBytes = getEPackageBytes(store, packageUnit);
+ List<Pair<String, String>> packageInfos = getPackageInfosAsPair(packageUnit.getPackageInfos());
+ return new JSONPackageUnit(id, originalType, timeStamp, ePackageBytes, packageInfos);
+
+ }
+
+ private static EPackage getEPackageFromBytes(List<Byte> ePackageBytesList) {
+ ResourceSet rSet = new ResourceSetImpl();
+ Resource.Factory resourceFactory = new EcoreResourceFactoryImpl();
+ rSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", resourceFactory); //$NON-NLS-1$
+ byte[] packageBytes = new byte[ePackageBytesList.size()];
+ for (int i = 0; i < packageBytes.length; i++) {
+ packageBytes[i] = ePackageBytesList.get(i);
+ }
+ EPackage ePackage = EMFUtil.createEPackage("", packageBytes, true, rSet, false);
+ return ePackage;
+ }
+
+ private static List<Byte> getEPackageBytes(IStore store,
+ InternalCDOPackageUnit packageUnit) {
+ EPackage ePackage = packageUnit.getTopLevelPackageInfo().getEPackage();
+ CDOPackageRegistry packageRegistry = store.getRepository()
+ .getPackageRegistry();
+ byte[] bytes = EMFUtil
+ .getEPackageBytes(ePackage, true, packageRegistry);
+ List<Byte> bytesObject = new ArrayList<Byte>();
+ for (byte bt : bytes) {
+ bytesObject.add(new Byte(bt));
+ }
+
+ return bytesObject;
+ }
+
+ private static List<Pair<String, String>> getPackageInfosAsPair(
+ InternalCDOPackageInfo[] packageInfos) {
+ List<Pair<String, String>> infos = new ArrayList<Pair<String, String>>();
+ for (InternalCDOPackageInfo info : packageInfos) {
+ Pair<String, String> pair = Pair.create(info.getParentURI(),
+ info.getPackageURI());
+ infos.add(pair);
+ }
+
+ return infos;
+ }
+
+ private static InternalCDOPackageInfo[] getPackageInfos(
+ List<Pair<String, String>> packagePairs) {
+ List<InternalCDOPackageInfo> list = new ArrayList<InternalCDOPackageInfo>();
+ for (Pair<String, String> infoPair : packagePairs) {
+ InternalCDOPackageInfo packageInfo = (InternalCDOPackageInfo) CDOModelUtil
+ .createPackageInfo();
+ packageInfo.setParentURI(infoPair.getElement1());
+ packageInfo.setPackageURI(infoPair.getElement2());
+ list.add(packageInfo);
+ }
+ return list.toArray(new InternalCDOPackageInfo[list.size()]);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONRevision.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONRevision.java
new file mode 100644
index 0000000000..4a684b3057
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONRevision.java
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2010-2012 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+
+package org.eclipse.emf.cdo.server.internal.couchbase.marshall;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDExternal;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.model.CDOClassInfo;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDOListFactory;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionData;
+import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
+import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
+import org.eclipse.emf.cdo.server.IRepository;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.spi.common.revision.CDOFeatureMapEntry;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.FeatureMap;
+
+import com.google.gson.JsonNull;
+
+/**
+ * @author Victor Roldan Betancort
+ */
+public class JSONRevision
+{
+ public final static String ATTRIBUTE_CLASS_NAME = "className";
+
+ public final static String ATTRIBUTE_PACKAGE_NS_URI = "packageNsURI";
+
+ private String packageNsURI;
+
+ private String className;
+
+ private long id;
+
+ private int version;
+
+ private long timeStamp;
+
+ private long resourceID;
+
+ /**
+ * Can be an external ID!
+ */
+ private Object containerID;
+
+ private int containingFeatureID;
+
+ private List<Object> values;
+
+ // TODO enum RevisionType { NORMAL, ROOT_RESOURCE, RESOURCE, RESOURCE_FOLDER }??
+ private boolean isResource;
+
+ private boolean isResourceFolder;
+
+ public JSONRevision() {
+
+ }
+
+ public JSONRevision(String packageURI, String className, long id, int version, long resourceID, Object containerID,
+ int containingFeatureID, List<Object> values, long timestamp, boolean isResource, boolean isResourceFolder)
+ {
+ setPackageURI(packageURI);
+ setClassName(className);
+ setID(id);
+ setVersion(version);
+ setResourceID(resourceID);
+ setContainerID(containerID);
+ setContainingFeatureID(containingFeatureID);
+ setValues(values);
+ setTimeStamp(timestamp);
+ setResource(isResource);
+ setResourceFolder(isResourceFolder);
+ }
+
+ public void setPackageURI(String packageURI)
+ {
+ packageNsURI = packageURI;
+ }
+
+ public String getPackageURI()
+ {
+ return packageNsURI;
+ }
+
+ public void setClassName(String className)
+ {
+ this.className = className;
+ }
+
+ public String getClassName()
+ {
+ return className;
+ }
+
+ public void setID(long id)
+ {
+ this.id = id;
+ }
+
+ public long getID()
+ {
+ return id;
+ }
+
+ public void setVersion(int version)
+ {
+ this.version = version;
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public long getRevised()
+ {
+ return CDORevision.UNSPECIFIED_DATE;
+ }
+
+ public void setResourceID(long resourceID)
+ {
+ this.resourceID = resourceID;
+ }
+
+ public long getResourceID()
+ {
+ return resourceID;
+ }
+
+ public void setContainerID(Object containerID)
+ {
+ this.containerID = containerID;
+ }
+
+ public Object getContainerID()
+ {
+ return containerID;
+ }
+
+ public void setContainingFeatureID(int containingFeatureID)
+ {
+ this.containingFeatureID = containingFeatureID;
+ }
+
+ public int getContainingFeatureID()
+ {
+ return containingFeatureID;
+ }
+
+ public void setValues(List<Object> values)
+ {
+ this.values = values;
+ }
+
+ public List<Object> getValues()
+ {
+ return values;
+ }
+
+ public void setTimeStamp(long timeStamp)
+ {
+ this.timeStamp = timeStamp;
+ }
+
+ public long getTimeStamp()
+ {
+ return timeStamp;
+ }
+
+ public void setResource(boolean isResource)
+ {
+ this.isResource = isResource;
+ }
+
+ public boolean isResource()
+ {
+ return isResource;
+ }
+
+ public void setResourceFolder(boolean isResourceFolder)
+ {
+ this.isResourceFolder = isResourceFolder;
+ }
+
+ public boolean isResourceFolder()
+ {
+ return isResourceFolder;
+ }
+
+ public boolean isResourceNode()
+ {
+ return isResource || isResourceFolder;
+ }
+
+ public static JSONRevision getJSONRevision(InternalCDORevision revision)
+ {
+ CDOClassInfo classInfo = revision.getClassInfo();
+ EClass eClass = classInfo.getEClass();
+ String packageURI = eClass.getEPackage().getNsURI();
+ String className = eClass.getName();
+
+ CDOID revisionID = revision.getID();
+ if (revisionID.isTemporary())
+ {
+ throw new IllegalArgumentException("TEMPORARY CDOID: " + revisionID);
+ }
+
+ boolean isResource = revision.isResource();
+ boolean isResourceFolder = revision.isResourceFolder();
+
+ long id = CDOIDUtil.getLong(revisionID);
+ int version = revision.getVersion();
+ long timeStamp = revision.getTimeStamp();
+ long resourceID = CDOIDUtil.getLong(revision.getResourceID());
+ Object containerID = getJSONID((CDOID)revision.getContainerID());
+ int containingFeatureID = revision.getContainingFeatureID();
+
+ EStructuralFeature[] features = classInfo.getAllPersistentFeatures();
+ List<Object> values = new ArrayList<Object>(features.length);
+ if (features.length > 0)
+ {
+ for (int i = 0; i < features.length; i++)
+ {
+ EStructuralFeature feature = features[i];
+ Object obj = revision.getValue(feature);
+
+ // We will process CDOList for EReferences to get rid of CDOIDs (we want to get only primitive types,
+ // otherwise the JSON Converter will mess up certain classes
+
+ // Multi-valued EAttributes (also kept in CDOList) will be saved as is
+ if (feature instanceof EReference)
+ {
+ if (feature.isMany()) {
+ InternalCDOList cdoList = (InternalCDOList)obj;
+ List<Object> list = new ArrayList<Object>();
+ // if the multivalued reference is empty, it would be null
+ if (obj != null) {
+ for (Object listElement : cdoList)
+ {
+ if (!(listElement instanceof CDOID))
+ {
+ throw new IllegalStateException("CDOList should contain only CDOID instances but received "
+ + listElement.getClass().getName() + " instead");
+ }
+
+ list.add(getJSONID((CDOID)listElement));
+ }
+ }
+ values.add(i, list);
+ } else {
+ if (obj != null) {
+ values.add(i, getJSONID((CDOID)obj));
+ } else {
+ values.add(i, null);
+ }
+ }
+ }
+ else if (listContainsInstancesOfClass(obj, CDOFeatureMapEntry.class)) // FeatureMap
+ {
+ values.add(i, JSONFeatureMapEntry.getPrimitiveFeatureMapEntryList(obj));
+ }
+ else // Process EAttribute
+ {
+ // Prevent the explicit null-ref "NIL" from being serialized!
+ if (obj == CDORevisionData.NIL)
+ {
+ obj = new ExplicitNull();
+ }
+ if (obj instanceof CDOID) {
+ System.out.println("This should not happen");
+ } else {
+ values.add(i, obj);
+ }
+ }
+ }
+ }
+
+ return new JSONRevision(packageURI, className, id, version, resourceID, containerID, containingFeatureID, values,
+ timeStamp, isResource, isResourceFolder);
+ }
+
+ public static InternalCDORevision getCDORevision(IStore store, JSONRevision primitiveRevision)
+ {
+ IRepository repository = store.getRepository();
+ CDORevisionFactory factory = ((InternalCDORevisionManager)repository.getRevisionManager()).getFactory();
+ CDOBranch branch = repository.getBranchManager().getMainBranch();
+
+ String nsURI = primitiveRevision.getPackageURI();
+ String className = primitiveRevision.getClassName();
+ EPackage ePackage = repository.getPackageRegistry().getEPackage(nsURI);
+ EClass eClass = (EClass)ePackage.getEClassifier(className);
+ InternalCDORevision revision = (InternalCDORevision)factory.createRevision(eClass);
+
+ revision.setID(getCDOID(primitiveRevision.getID()));
+ revision.setVersion(primitiveRevision.getVersion());
+ revision.setBranchPoint(branch.getPoint(primitiveRevision.getTimeStamp()));
+ revision.setRevised(primitiveRevision.getRevised());
+ revision.setResourceID(getCDOID(primitiveRevision.getResourceID()));
+ revision.setContainerID(getCDOID(primitiveRevision.getContainerID()));
+ revision.setContainingFeatureID(primitiveRevision.getContainingFeatureID());
+ EStructuralFeature[] features = revision.getClassInfo().getAllPersistentFeatures();
+
+ int i = 0;
+ for (Object value : primitiveRevision.getValues())
+ {
+ EStructuralFeature feature = features[i++];
+ if (feature instanceof EReference)
+ {
+ if (feature.isMany()) {
+ value = getCDOList(value, true);
+ } else {
+ value = getCDOID(value);
+ }
+ }
+ else if (feature instanceof EAttribute && feature.isMany())
+ {
+ value = getCDOList(value, false);
+ }
+ else if (listContainsInstancesOfClass(value, JSONFeatureMapEntry.class))
+ {
+ value = JSONFeatureMapEntry.getCDOFeatureMapEntryList(eClass, value);
+ }
+
+ // Convert 'null' into the explicit null-ref "NIL" if appropriate
+ if (value instanceof ExplicitNull)
+ {
+ value = CDORevisionData.NIL;
+ }
+
+ revision.setValue(feature, value);
+ }
+
+ return revision;
+ }
+
+private static CDOList getCDOList(Object value, boolean isReference) {
+ List<?> sourceList = (List<?>)value;
+ CDOList list = CDOListFactory.DEFAULT.createList(sourceList.size(), sourceList.size(), CDORevision.UNCHUNKED);
+ for (int j = 0; j < sourceList.size(); j++)
+ {
+ list.set(j, isReference ? getCDOID(sourceList.get(j)) : sourceList.get(j));
+ }
+ return list;
+}
+
+ public static Object getJSONID(CDOID id)
+ {
+ if (id.isExternal())
+ {
+ return new String(((CDOIDExternal)id).getURI());
+ }
+
+ return CDOIDUtil.getLong(id);
+ }
+
+ public static CDOID getCDOID(Object id)
+ {
+ if (id == null || id instanceof JsonNull)
+ {
+ return CDOID.NULL;
+ }
+
+ if (id instanceof String)
+ {
+ String value = (String)id;
+ value = value.replace("\"", "");
+ try {
+ return CDOIDUtil.createLong(Long.valueOf(value));
+ } catch (NumberFormatException e) {
+ return CDOIDUtil.createExternal(value);
+ }
+ }
+
+ if (id instanceof CDOID)
+ {
+ return (CDOID)id;
+ }
+
+ return CDOIDUtil.createLong((Long)id);
+ }
+
+ public static boolean isNull(Object obj) {
+ return obj instanceof ExplicitNull;
+ }
+
+
+ public static boolean listContainsInstancesOfClass(Object obj, Class<?> clazz)
+ {
+ if (obj instanceof List)
+ {
+ List<?> list = (List<?>)obj;
+ for (Object potentialFeatureMap : list)
+ {
+ if (!clazz.isAssignableFrom(potentialFeatureMap.getClass()))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private static final class JSONFeatureMapEntry
+ {
+
+ private int featureID;
+
+ private Object valueID;
+
+ public JSONFeatureMapEntry(int featureID, Object valueID)
+ {
+ setFeatureID(featureID);
+ setValueID(valueID);
+ }
+
+ private void setFeatureID(int featureID)
+ {
+ this.featureID = featureID;
+ }
+
+ public int getFeatureID()
+ {
+ return featureID;
+ }
+
+ private void setValueID(Object valueID)
+ {
+ this.valueID = valueID;
+ }
+
+ public Object getValueID()
+ {
+ return valueID;
+ }
+
+ public static List<JSONFeatureMapEntry> getPrimitiveFeatureMapEntryList(Object obj)
+ {
+ InternalCDOList cdoList = (InternalCDOList)obj;
+ List<JSONFeatureMapEntry> list = new ArrayList<JSONFeatureMapEntry>();
+ for (Object listElement : cdoList)
+ {
+ if (listElement instanceof FeatureMap.Entry)
+ {
+ FeatureMap.Entry entry = (FeatureMap.Entry)listElement;
+ EStructuralFeature entryFeature = entry.getEStructuralFeature();
+ CDOID entryValue = (CDOID)entry.getValue();
+ JSONFeatureMapEntry jsonEntry = new JSONFeatureMapEntry(entryFeature.getFeatureID(), getJSONID(entryValue));
+ list.add(jsonEntry);
+ }
+ }
+ return list;
+ }
+
+ public static CDOList getCDOFeatureMapEntryList(EClass eClass, Object value)
+ {
+ List<?> sourceList = (List<?>)value;
+ CDOList list = CDOListFactory.DEFAULT.createList(sourceList.size(), sourceList.size(), CDORevision.UNCHUNKED);
+ for (int j = 0; j < sourceList.size(); j++)
+ {
+ JSONFeatureMapEntry mapEntry = (JSONFeatureMapEntry)sourceList.get(j);
+ EStructuralFeature entryFeature = eClass.getEStructuralFeature(mapEntry.getFeatureID());
+ CDOID valueID = getCDOID(mapEntry.getValueID());
+ list.set(j, CDORevisionUtil.createFeatureMapEntry(entryFeature, valueID));
+ }
+ return list;
+ }
+ }
+
+ /**
+ * @author Caspar De Groot
+ */
+ private static final class ExplicitNull
+ {
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONRevisionTypeAdapter.java b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONRevisionTypeAdapter.java
new file mode 100644
index 0000000000..78dda40f39
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.couchbase/src/org/eclipse/emf/cdo/server/internal/couchbase/marshall/JSONRevisionTypeAdapter.java
@@ -0,0 +1,259 @@
+package org.eclipse.emf.cdo.server.internal.couchbase.marshall;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.eclipse.emf.cdo.common.model.CDOModelUtil;
+import org.eclipse.emf.cdo.server.IRepository;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcorePackage;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * Gson is not able to properly serialize JSONRevision, so an adapter
+ * to manually serialize it is needed.
+ *
+ * @author vroldan
+ *
+ */
+public class JSONRevisionTypeAdapter implements JsonDeserializer<JSONRevision>,
+ JsonSerializer<JSONRevision> {
+
+ private static final String FEATURE = "feature_";
+
+ private static final String CONTAINER_ID = "containerId";
+
+ private static final String VERSION = "version";
+
+ private static final String TIMESTAMP = "timestamp";
+
+ private static final String REVISED = "revised";
+
+ private static final String RESOURCE_ID = "resourceId";
+
+ private static final String ID = "id";
+
+ private static final String CONTAINING_FEATURE_ID = "containingFeatureID";
+
+ private static final String PACKAGE_URI = "packageURI";
+
+ private static final String CLASS_NAME = "className";
+
+ private IStore store;
+
+ private static final String EMPTY_LIST = new String("$_empty_list");
+
+ public JSONRevisionTypeAdapter(IStore store) {
+ this.store = store;
+ }
+
+ public JsonElement serialize(JSONRevision arg0, Type arg1, JsonSerializationContext arg2) {
+ JsonObject obj = new JsonObject();
+ obj.addProperty(CLASS_NAME, arg0.getClassName());
+ obj.addProperty(PACKAGE_URI, arg0.getPackageURI());
+ obj.addProperty(CONTAINING_FEATURE_ID, arg0.getContainingFeatureID());
+ obj.addProperty(ID, arg0.getID());
+ obj.addProperty(RESOURCE_ID, arg0.getResourceID());
+ obj.addProperty(REVISED, arg0.getRevised());
+ obj.addProperty(TIMESTAMP, arg0.getTimeStamp());
+ obj.addProperty(VERSION, arg0.getVersion());
+ obj.addProperty(CONTAINER_ID, arg0.getContainerID().toString());
+ int count = 0;
+ for (Object value : arg0.getValues()) {
+ if (value == null) {
+ obj.addProperty(getFeatureValueID(count), (String)null);
+ } else if (value instanceof List<?>) {
+ int nestedCount = 0;
+ for (Object nestedValue : (List<?>)value) {
+ obj.addProperty(getNestedFeatureValueID(count, nestedCount), getSerializableValue(nestedValue));
+ nestedCount++;
+ }
+ if (nestedCount == 0) {
+ obj.addProperty(getFeatureValueID(count), EMPTY_LIST);
+ }
+ } else {
+ if (value.getClass().isArray()) {
+ int length = Array.getLength(value);
+ for (int i = 0; i < length; i ++) {
+ Object arrayElement = Array.get(value, i);
+ obj.addProperty(getNestedFeatureValueID(count, i), getSerializableValue(arrayElement));
+ }
+ } else {
+ obj.addProperty(getFeatureValueID(count), getSerializableValue(value));
+ }
+ }
+ count++;
+ }
+
+ return obj;
+ }
+
+ private String getSerializableValue(Object value) {
+ if (value == null || JSONRevision.isNull(value)) {
+ return (String)null;
+ } else if (value instanceof Date) {
+ return String.valueOf(((Date)value).getTime());
+ }
+ return value.toString();
+ }
+
+ public JSONRevision deserialize(JsonElement arg0, Type arg1, JsonDeserializationContext arg2) throws JsonParseException {
+ JSONRevision rev = new JSONRevision();
+ JsonObject json = (JsonObject)arg0;
+ rev.setClassName(json.get(CLASS_NAME).getAsString());
+ rev.setPackageURI(json.get(PACKAGE_URI).getAsString());
+ rev.setContainingFeatureID(json.get(CONTAINING_FEATURE_ID).getAsInt());
+ rev.setID(json.get(ID).getAsLong());
+ rev.setResourceID(json.get(RESOURCE_ID).getAsLong());
+ rev.setTimeStamp(json.get(TIMESTAMP).getAsLong());
+ rev.setVersion(json.get(VERSION).getAsInt());
+ rev.setContainerID(json.get(CONTAINER_ID).getAsString());
+
+ IRepository repository = store.getRepository();
+ String nsURI = rev.getPackageURI();
+ String className = rev.getClassName();
+ EPackage ePackage = repository.getPackageRegistry().getEPackage(nsURI);
+ EClass eClass = (EClass)ePackage.getEClassifier(className);
+
+ int count = 0;
+ EStructuralFeature[] features = CDOModelUtil.getClassInfo(eClass).getAllPersistentFeatures();
+ List<Object> values = new ArrayList<Object>(features.length);
+ for (EStructuralFeature feature : features) {
+ if (!feature.isDerived()) {
+ if (feature.isMany()) {
+ int nestedCount = 0;
+ List<Object> nestedList = new ArrayList<Object>();
+ JsonElement nestedValue = null;
+ while (json.has(getNestedFeatureValueID(count, nestedCount))) {
+ nestedValue = json.get(getNestedFeatureValueID(count, nestedCount));
+ nestedList.add(getTypedElement(feature.getEType(), nestedValue, count));
+ nestedCount++;
+ };
+ values.add(nestedList);
+ } else {
+ if (isByteArray(feature.getEType())) {
+ values.add(getByteArray(json, count));
+ }
+ else {
+ values.add(getTypedElement(feature.getEType(), json.get(getFeatureValueID(count)), count));
+ }
+ }
+ count++;
+ }
+ }
+ rev.setValues(values);
+ return rev;
+ }
+
+ private String getFeatureValueID(int count) {
+ return FEATURE + count;
+ }
+
+ private String getNestedFeatureValueID(int count, int nestedCount) {
+ return FEATURE + count + nestedCount;
+ }
+
+ private boolean isByteArray(EClassifier eType) {
+ return eType == EcorePackage.eINSTANCE.getEByteArray();
+ }
+
+ private Object getByteArray(JsonObject json, int count) {
+ List<String> arrayList = getArrayValues(json, count);
+ byte[] byteArray = new byte[arrayList.size()];
+ for (int i = 0; i < arrayList.size(); i++) {
+ byteArray[i] = Byte.valueOf(arrayList.get(i));
+ }
+ return byteArray;
+ }
+
+ private List<String> getArrayValues(JsonObject json, int count) {
+ int nestedCount = 0;
+ List<String> result = new ArrayList<String>();
+ while (json.has(getNestedFeatureValueID(count, nestedCount))) {
+ String nestedValue = json.get(getNestedFeatureValueID(count, nestedCount)).getAsString();
+ result.add(nestedValue);
+ nestedCount++;
+ };
+ return result;
+ }
+
+ private Object getTypedElement(EClassifier eType, JsonElement jsonElement, int currentCount) {
+ if (eType instanceof EClass) {
+ if (jsonElement == null || jsonElement instanceof JsonNull) {
+ return JSONRevision.getCDOID(jsonElement);
+ } else {
+ return JSONRevision.getCDOID(jsonElement.toString());
+ }
+ } else if (eType instanceof EEnum) {
+ if (jsonElement == null || jsonElement instanceof JsonNull) {
+ return null;
+ }
+ return jsonElement.getAsInt();
+ } else if (eType instanceof EDataType) {
+ if (jsonElement == null || jsonElement instanceof JsonNull) {
+ return null;
+ }
+ EDataType eDataType = (EDataType)eType;
+ if (eDataType == EcorePackage.eINSTANCE.getEString()) {
+ return jsonElement.getAsString();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEBigDecimal()) {
+ return jsonElement.getAsBigDecimal();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEBigInteger()) {
+ return jsonElement.getAsBigInteger();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEBoolean()) {
+ return jsonElement.getAsBoolean();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEByte()) {
+ return jsonElement.getAsByte();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEChar()) {
+ return jsonElement.getAsCharacter();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEDate()) {
+ return new Date(jsonElement.getAsLong());
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEDouble()) {
+ return jsonElement.getAsDouble();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEFloat()) {
+ return jsonElement.getAsFloat();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getELong()) {
+ return jsonElement.getAsLong();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEInt()) {
+ return jsonElement.getAsInt();
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEIntegerObject()) {
+ return new Integer(jsonElement.getAsInt());
+ }
+ else if (eDataType == EcorePackage.eINSTANCE.getEShort()) {
+ return jsonElement.getAsShort();
+ }
+ return jsonElement.getAsString(); // for custom types
+ }
+
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/.classpath b/plugins/org.eclipse.emf.cdo.tests.couchbase/.classpath
new file mode 100644
index 0000000000..64c5e31b7a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/.project b/plugins/org.eclipse.emf.cdo.tests.couchbase/.project
new file mode 100644
index 0000000000..8b3af59638
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.emf.cdo.tests.couchbase</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.emf.cdo.tests.couchbase/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..af0f20f97a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/CDO AllTests (Couchbase).launch b/plugins/org.eclipse.emf.cdo.tests.couchbase/CDO AllTests (Couchbase).launch
new file mode 100644
index 0000000000..07a1d7caac
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/CDO AllTests (Couchbase).launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsCouchbase.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.cdo.tests.couchbase.AllTestsCouchbase"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.emf.cdo.tests.couchbase"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:MaxPermSize=128m&#13;&#10;-Xmx1024m"/>
+</launchConfiguration>
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/CDO AllTests (Couchbase-memcached).launch b/plugins/org.eclipse.emf.cdo.tests.couchbase/CDO AllTests (Couchbase-memcached).launch
new file mode 100644
index 0000000000..bfaccd5bd7
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/CDO AllTests (Couchbase-memcached).launch
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsMemcached.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.cdo.tests.couchbase.AllTestsMemcached"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.emf.cdo.tests.couchbase"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:MaxPermSize=128m&#13;&#10;-Xmx1024m"/>
+</launchConfiguration>
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.tests.couchbase/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..f8370f3285
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Couchbase Tests for CDO
+Bundle-SymbolicName: org.eclipse.emf.cdo.tests.couchbase
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: eclipse.org
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Require-Bundle: org.eclipse.emf.cdo.tests;bundle-version="[4.0.0,5.0.0)",
+ org.eclipse.emf.cdo.server.couchbase;bundle-version="[1.0.0,2.0.0)",
+ com.couchbase.client;bundle-version="[1.1.5,2.0.0)",
+ org.apache.commons.codec;bundle-version="[1.5.0,2.0.0)",
+ net.spy.memcached;bundle-version="[2.8.0,3.0.0)",
+ com.google.gson;bundle-version="[2.2.0,3.0.0)"
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/build.properties b/plugins/org.eclipse.emf.cdo.tests.couchbase/build.properties
new file mode 100644
index 0000000000..34d2e4d2da
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/hs_err_pid6840.log b/plugins/org.eclipse.emf.cdo.tests.couchbase/hs_err_pid6840.log
new file mode 100644
index 0000000000..d82c8e029f
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/hs_err_pid6840.log
@@ -0,0 +1,366 @@
+#
+# A fatal error has been detected by the Java Runtime Environment:
+#
+# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006340df5b, pid=6840, tid=1880
+#
+# JRE version: 7.0_21-b11
+# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.21-b01 mixed mode windows-amd64 compressed oops)
+# Problematic frame:
+# V [jvm.dll+0x11df5b]
+#
+# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
+#
+# If you would like to submit a bug report, please visit:
+# http://bugreport.sun.com/bugreport/crash.jsp
+#
+
+--------------- T H R E A D ---------------
+
+Current thread (0x000000000b489000): JavaThread "JDWP Transport Listener: dt_socket" daemon [_thread_in_vm, id=1880, stack(0x000000000b1c0000,0x000000000b2c0000)]
+
+siginfo: ExceptionCode=0xc0000005, reading address 0x00003b6c616e7265
+
+Registers:
+RAX=0x000000000b2bf201, RBX=0x000000000b489000, RCX=0x00003b6c616e7265, RDX=0x000000000b489000
+RSP=0x000000000b2bf230, RBP=0x00003b6c616e7265, RSI=0x000000000b2bf348, RDI=0x0000000001deb1c0
+R8 =0x000000000b2bf348, R9 =0x0000ac470bae0121, R10=0x656a624f2f676e61, R11=0x000000000cee1999
+R12=0x0000000000000000, R13=0x0000000000000000, R14=0x0000000000000000, R15=0x0000000000000000
+RIP=0x000000006340df5b, EFLAGS=0x0000000000010206
+
+Top of Stack: (sp=0x000000000b2bf230)
+0x000000000b2bf230: 000000000b489000 0000000001f86840
+0x000000000b2bf240: 000000000b2bf2f8 0000000063595699
+0x000000000b2bf250: 000000000b489000 00000000635b1062
+0x000000000b2bf260: 0000000000000029 000000000b489000
+0x000000000b2bf270: 000000000cefcc70 00000000648d264e
+0x000000000b2bf280: 000000000b489000 0000000000000000
+0x000000000b2bf290: 0000000000000000 0000000000000000
+0x000000000b2bf2a0: 00003b6c616e7265 00000000648d1745
+0x000000000b2bf2b0: 000000000b2bf348 000000000b2bf320
+0x000000000b2bf2c0: 0000000000000001 000000000cefcc70
+0x000000000b2bf2d0: 00003b6c616e7265 00000000648b53b3
+0x000000000b2bf2e0: 000000000b2bf410 0000000000000001
+0x000000000b2bf2f0: 0000000000000001 000000000cefcc70
+0x000000000b2bf300: 0000000000000009 0000000000000000
+0x000000000b2bf310: 0000000000000000 0000000000000000
+0x000000000b2bf320: 0000000000000001 00000000648b5571
+
+Instructions: (pc=0x000000006340df5b)
+0x000000006340df3b: 48 8b 5c 24 30 48 89 47 18 48 83 c4 20 5f c3 cc
+0x000000006340df4b: cc cc cc cc cc 40 53 48 83 ec 20 48 85 c9 74 54
+0x000000006340df5b: 48 8b 19 48 85 db 74 4c 48 b8 fe fe fe fe fe fe
+0x000000006340df6b: fe fe 48 3b d8 74 3d 80 3d ff fd 58 00 00 74 15
+
+
+Register to memory mapping:
+
+RAX=0x000000000b2bf201 is pointing into the stack for thread: 0x000000000b489000
+RBX=0x000000000b489000 is a thread
+RCX=0x00003b6c616e7265 is an unknown value
+RDX=0x000000000b489000 is a thread
+RSP=0x000000000b2bf230 is pointing into the stack for thread: 0x000000000b489000
+RBP=0x00003b6c616e7265 is an unknown value
+RSI=0x000000000b2bf348 is pointing into the stack for thread: 0x000000000b489000
+RDI=0x0000000001deb1c0 is an unknown value
+R8 =0x000000000b2bf348 is pointing into the stack for thread: 0x000000000b489000
+R9 =0x0000ac470bae0121 is an unknown value
+R10=0x656a624f2f676e61 is an unknown value
+R11=0x000000000cee1999 is an unknown value
+R12=0x0000000000000000 is an unknown value
+R13=0x0000000000000000 is an unknown value
+R14=0x0000000000000000 is an unknown value
+R15=0x0000000000000000 is an unknown value
+
+
+Stack: [0x000000000b1c0000,0x000000000b2c0000], sp=0x000000000b2bf230, free space=1020k
+Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
+V [jvm.dll+0x11df5b]
+
+
+--------------- P R O C E S S ---------------
+
+Java Threads: ( => current thread )
+ 0x000000000de7b000 JavaThread "pool-13-thread-2" [_thread_blocked, id=7132, stack(0x00000000104f0000,0x00000000105f0000)]
+ 0x000000000de7a800 JavaThread "CDORevisionCacheCleaner-SignalProtocol[2, CLIENT, cdo]" daemon [_thread_blocked, id=3816, stack(0x00000000111e0000,0x00000000112e0000)]
+ 0x000000000de79800 JavaThread "net4j-Thread-3" daemon [_thread_blocked, id=2172, stack(0x0000000011070000,0x0000000011170000)]
+ 0x000000000de79000 JavaThread "Net4jReceiveSerializer-Channel[2, SERVER, cdo]" daemon [_thread_blocked, id=4952, stack(0x0000000010c00000,0x0000000010d00000)]
+ 0x000000000de77800 JavaThread "Net4jReceiveSerializer-Channel[2, CLIENT, cdo]" daemon [_thread_blocked, id=3792, stack(0x000000000e790000,0x000000000e890000)]
+ 0x000000000de78000 JavaThread "pool-13-thread-1" [_thread_blocked, id=6624, stack(0x000000000e520000,0x000000000e620000)]
+ 0x000000000de76800 JavaThread "monitor-timer" daemon [_thread_blocked, id=4452, stack(0x0000000010ed0000,0x0000000010fd0000)]
+ 0x000000000d0ba800 JavaThread "I/O dispatcher 8" [_thread_in_native, id=6524, stack(0x0000000010a50000,0x0000000010b50000)]
+ 0x000000000d0ba000 JavaThread "I/O dispatcher 7" [_thread_in_native, id=3596, stack(0x0000000010800000,0x0000000010900000)]
+ 0x000000000d0b9000 JavaThread "New I/O worker #49" [_thread_in_native, id=4532, stack(0x000000000f5d0000,0x000000000f6d0000)]
+ 0x000000000d0b7000 JavaThread "Couchbase View Thread for node 127.0.0.1/127.0.0.1:8092" [_thread_in_native, id=4212, stack(0x000000000fcc0000,0x000000000fdc0000)]
+ 0x000000000cf1a000 JavaThread "Memcached IO over {MemcachedConnection to 127.0.0.1/127.0.0.1:11210}" [_thread_in_native, id=516, stack(0x000000000fba0000,0x000000000fca0000)]
+ 0x000000000d0b6000 JavaThread "New I/O worker #33" [_thread_in_native, id=3544, stack(0x0000000010320000,0x0000000010420000)]
+ 0x000000000d0b5800 JavaThread "I/O dispatcher 6" [_thread_in_native, id=6692, stack(0x0000000010220000,0x0000000010320000)]
+ 0x000000000d0b4800 JavaThread "I/O dispatcher 5" [_thread_in_native, id=2952, stack(0x0000000010000000,0x0000000010100000)]
+ 0x000000000cf19800 JavaThread "Couchbase View Thread for node 127.0.0.1/127.0.0.1:8092" [_thread_in_native, id=6628, stack(0x000000000f820000,0x000000000f920000)]
+ 0x000000000cf15800 JavaThread "Memcached IO over {MemcachedConnection to 127.0.0.1/127.0.0.1:11210}" [_thread_in_native, id=4644, stack(0x000000000f4d0000,0x000000000f5d0000)]
+ 0x000000000cf18800 JavaThread "I/O dispatcher 4" [_thread_in_native, id=6640, stack(0x000000000fa50000,0x000000000fb50000)]
+ 0x000000000cf18000 JavaThread "I/O dispatcher 3" [_thread_in_native, id=6788, stack(0x000000000eca0000,0x000000000eda0000)]
+ 0x000000000cf17000 JavaThread "New I/O worker #17" [_thread_in_native, id=4396, stack(0x000000000f940000,0x000000000fa40000)]
+ 0x000000000cf15000 JavaThread "Couchbase View Thread for node 127.0.0.1/127.0.0.1:8092" [_thread_in_native, id=6564, stack(0x000000000f390000,0x000000000f490000)]
+ 0x000000000cf14000 JavaThread "Memcached IO over {MemcachedConnection to 127.0.0.1/127.0.0.1:11210}" [_thread_in_native, id=2860, stack(0x000000000f210000,0x000000000f310000)]
+ 0x000000000b6ff800 JavaThread "CDORevisionCacheCleaner-Repository[repo1]" daemon [_thread_blocked, id=2104, stack(0x000000000f110000,0x000000000f210000)]
+ 0x000000000d10f800 JavaThread "New I/O worker #1" [_thread_in_native, id=2872, stack(0x000000000c690000,0x000000000c790000)]
+ 0x000000000d700000 JavaThread "I/O dispatcher 2" [_thread_in_native, id=1668, stack(0x000000000efd0000,0x000000000f0d0000)]
+ 0x000000000d6ff800 JavaThread "I/O dispatcher 1" [_thread_in_native, id=6220, stack(0x000000000ede0000,0x000000000eee0000)]
+ 0x000000000d703800 JavaThread "Couchbase View Thread for node 127.0.0.1/127.0.0.1:8092" [_thread_in_native, id=6908, stack(0x000000000eba0000,0x000000000eca0000)]
+ 0x000000000de30800 JavaThread "Memcached IO over {MemcachedConnection to 127.0.0.1/127.0.0.1:11210}" [_thread_in_native, id=6724, stack(0x000000000e8b0000,0x000000000e9b0000)]
+ 0x000000000cf02800 JavaThread "Net4jBufferPoolMonitor" daemon [_thread_blocked, id=6884, stack(0x000000000e400000,0x000000000e500000)]
+ 0x000000000cea5800 JavaThread "EMF Reference Cleaner" daemon [_thread_blocked, id=3148, stack(0x000000000d200000,0x000000000d300000)]
+ 0x000000000b82f800 JavaThread "ReaderThread" [_thread_in_native, id=6436, stack(0x000000000d330000,0x000000000d430000)]
+ 0x000000000b4c1000 JavaThread "Service Thread" daemon [_thread_blocked, id=6240, stack(0x000000000c0c0000,0x000000000c1c0000)]
+ 0x000000000b4be000 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=6888, stack(0x000000000c7b0000,0x000000000c8b0000)]
+ 0x000000000b4bc800 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=5844, stack(0x000000000c570000,0x000000000c670000)]
+ 0x000000000b496800 JavaThread "JDWP Command Reader" daemon [_thread_in_native, id=4036, stack(0x000000000c450000,0x000000000c550000)]
+ 0x000000000b495800 JavaThread "JDWP Event Helper Thread" daemon [_thread_blocked, id=5676, stack(0x000000000bec0000,0x000000000bfc0000)]
+=>0x000000000b489000 JavaThread "JDWP Transport Listener: dt_socket" daemon [_thread_in_vm, id=1880, stack(0x000000000b1c0000,0x000000000b2c0000)]
+ 0x000000000b481800 JavaThread "Attach Listener" daemon [_thread_blocked, id=4540, stack(0x000000000bab0000,0x000000000bbb0000)]
+ 0x000000000b481000 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=6488, stack(0x000000000b960000,0x000000000ba60000)]
+ 0x000000000924f000 JavaThread "Finalizer" daemon [_thread_blocked, id=3872, stack(0x000000000b330000,0x000000000b430000)]
+ 0x0000000009247000 JavaThread "Reference Handler" daemon [_thread_blocked, id=6568, stack(0x000000000b0c0000,0x000000000b1c0000)]
+ 0x0000000001f68000 JavaThread "main" [_thread_blocked, id=3784, stack(0x00000000020e0000,0x00000000021e0000)]
+
+Other Threads:
+ 0x000000000923b800 VMThread [stack: 0x000000000af10000,0x000000000b010000] [id=2552]
+ 0x000000000b510000 WatcherThread [stack: 0x000000000c8f0000,0x000000000c9f0000] [id=6092]
+
+VM state:not at safepoint (normal execution)
+
+VM Mutex/Monitor currently owned by a thread: None
+
+Heap
+ PSYoungGen total 57344K, used 38561K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 63% used [0x00000000eaab0000,0x00000000ec964c58,0x00000000edac0000)
+ from space 8128K, 87% used [0x00000000ee2b0000,0x00000000ee9a37c0,0x00000000eeaa0000)
+ to space 8128K, 0% used [0x00000000edac0000,0x00000000edac0000,0x00000000ee2b0000)
+ ParOldGen total 131008K, used 88K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0016010,0x00000000c7ff0000)
+ PSPermGen total 21824K, used 21684K [0x00000000b8000000, 0x00000000b9550000, 0x00000000c0000000)
+ object space 21824K, 99% used [0x00000000b8000000,0x00000000b952d188,0x00000000b9550000)
+
+Card table byte_map: [0x00000000051e0000,0x0000000005430000] byte_map_base: 0x0000000004c20000
+
+Polling page: 0x0000000000200000
+
+Code Cache [0x00000000021e0000, 0x0000000002450000, 0x00000000051e0000)
+ total_blobs=716 nmethods=340 adapters=334 free_code_cache=47818Kb largest_free_block=48928064
+
+Compilation events (10 events):
+Event: 145.535 Thread 0x000000000b4be000 363 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject::awaitNanos (158 bytes)
+Event: 145.555 Thread 0x000000000b4be000 nmethod 363 0x0000000002334e90 code [0x00000000023350e0, 0x0000000002335d38]
+Event: 173.350 Thread 0x000000000b4bc800 364 java.util.concurrent.locks.ReentrantLock$Sync::tryRelease (45 bytes)
+Event: 173.351 Thread 0x000000000b4bc800 nmethod 364 0x00000000022f56d0 code [0x00000000022f5800, 0x00000000022f5898]
+Event: 185.491 Thread 0x000000000b4be000 365 java.util.concurrent.locks.ReentrantLock$NonfairSync::tryAcquire (6 bytes)
+Event: 185.493 Thread 0x000000000b4be000 nmethod 365 0x00000000022f7790 code [0x00000000022f78c0, 0x00000000022f7998]
+Event: 192.785 Thread 0x000000000b4bc800 366 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject::unlinkCancelledWaiters (67 bytes)
+Event: 192.787 Thread 0x000000000b4bc800 nmethod 366 0x00000000022f5150 code [0x00000000022f5280, 0x00000000022f5358]
+Event: 195.415 Thread 0x000000000b4be000 367 ! java.util.concurrent.LinkedBlockingQueue::poll (134 bytes)
+Event: 195.427 Thread 0x000000000b4be000 nmethod 367 0x000000000232e010 code [0x000000000232e1e0, 0x000000000232e980]
+
+GC Heap History (8 events):
+Event: 1.188 GC heap before
+{Heap before GC invocations=1 (full 0):
+ PSYoungGen total 57344K, used 49216K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 100% used [0x00000000eaab0000,0x00000000edac0000,0x00000000edac0000)
+ from space 8128K, 0% used [0x00000000ee2b0000,0x00000000ee2b0000,0x00000000eeaa0000)
+ to space 8128K, 0% used [0x00000000edac0000,0x00000000edac0000,0x00000000ee2b0000)
+ ParOldGen total 131008K, used 0K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0000000,0x00000000c7ff0000)
+ PSPermGen total 21248K, used 9993K [0x00000000b8000000, 0x00000000b94c0000, 0x00000000c0000000)
+ object space 21248K, 47% used [0x00000000b8000000,0x00000000b89c2738,0x00000000b94c0000)
+Event: 1.194 GC heap after
+Heap after GC invocations=1 (full 0):
+ PSYoungGen total 57344K, used 6129K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 0% used [0x00000000eaab0000,0x00000000eaab0000,0x00000000edac0000)
+ from space 8128K, 75% used [0x00000000edac0000,0x00000000ee0bc408,0x00000000ee2b0000)
+ to space 8128K, 0% used [0x00000000ee2b0000,0x00000000ee2b0000,0x00000000eeaa0000)
+ ParOldGen total 131008K, used 8K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0002000,0x00000000c7ff0000)
+ PSPermGen total 21248K, used 9993K [0x00000000b8000000, 0x00000000b94c0000, 0x00000000c0000000)
+ object space 21248K, 47% used [0x00000000b8000000,0x00000000b89c2738,0x00000000b94c0000)
+}
+Event: 1.913 GC heap before
+{Heap before GC invocations=2 (full 0):
+ PSYoungGen total 57344K, used 55345K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 100% used [0x00000000eaab0000,0x00000000edac0000,0x00000000edac0000)
+ from space 8128K, 75% used [0x00000000edac0000,0x00000000ee0bc408,0x00000000ee2b0000)
+ to space 8128K, 0% used [0x00000000ee2b0000,0x00000000ee2b0000,0x00000000eeaa0000)
+ ParOldGen total 131008K, used 8K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0002000,0x00000000c7ff0000)
+ PSPermGen total 21248K, used 13153K [0x00000000b8000000, 0x00000000b94c0000, 0x00000000c0000000)
+ object space 21248K, 61% used [0x00000000b8000000,0x00000000b8cd8540,0x00000000b94c0000)
+Event: 1.917 GC heap after
+Heap after GC invocations=2 (full 0):
+ PSYoungGen total 57344K, used 4402K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 0% used [0x00000000eaab0000,0x00000000eaab0000,0x00000000edac0000)
+ from space 8128K, 54% used [0x00000000ee2b0000,0x00000000ee6fc810,0x00000000eeaa0000)
+ to space 8128K, 0% used [0x00000000edac0000,0x00000000edac0000,0x00000000ee2b0000)
+ ParOldGen total 131008K, used 16K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0004000,0x00000000c7ff0000)
+ PSPermGen total 21248K, used 13153K [0x00000000b8000000, 0x00000000b94c0000, 0x00000000c0000000)
+ object space 21248K, 61% used [0x00000000b8000000,0x00000000b8cd8540,0x00000000b94c0000)
+}
+Event: 5.878 GC heap before
+{Heap before GC invocations=3 (full 0):
+ PSYoungGen total 57344K, used 53618K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 100% used [0x00000000eaab0000,0x00000000edac0000,0x00000000edac0000)
+ from space 8128K, 54% used [0x00000000ee2b0000,0x00000000ee6fc810,0x00000000eeaa0000)
+ to space 8128K, 0% used [0x00000000edac0000,0x00000000edac0000,0x00000000ee2b0000)
+ ParOldGen total 131008K, used 16K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0004000,0x00000000c7ff0000)
+ PSPermGen total 21248K, used 16101K [0x00000000b8000000, 0x00000000b94c0000, 0x00000000c0000000)
+ object space 21248K, 75% used [0x00000000b8000000,0x00000000b8fb9698,0x00000000b94c0000)
+Event: 5.891 GC heap after
+Heap after GC invocations=3 (full 0):
+ PSYoungGen total 57344K, used 6079K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 0% used [0x00000000eaab0000,0x00000000eaab0000,0x00000000edac0000)
+ from space 8128K, 74% used [0x00000000edac0000,0x00000000ee0afe00,0x00000000ee2b0000)
+ to space 8128K, 0% used [0x00000000ee2b0000,0x00000000ee2b0000,0x00000000eeaa0000)
+ ParOldGen total 131008K, used 16K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0004000,0x00000000c7ff0000)
+ PSPermGen total 21248K, used 16101K [0x00000000b8000000, 0x00000000b94c0000, 0x00000000c0000000)
+ object space 21248K, 75% used [0x00000000b8000000,0x00000000b8fb9698,0x00000000b94c0000)
+}
+Event: 6.779 GC heap before
+{Heap before GC invocations=4 (full 0):
+ PSYoungGen total 57344K, used 55295K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 100% used [0x00000000eaab0000,0x00000000edac0000,0x00000000edac0000)
+ from space 8128K, 74% used [0x00000000edac0000,0x00000000ee0afe00,0x00000000ee2b0000)
+ to space 8128K, 0% used [0x00000000ee2b0000,0x00000000ee2b0000,0x00000000eeaa0000)
+ ParOldGen total 131008K, used 16K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0004000,0x00000000c7ff0000)
+ PSPermGen total 21248K, used 19681K [0x00000000b8000000, 0x00000000b94c0000, 0x00000000c0000000)
+ object space 21248K, 92% used [0x00000000b8000000,0x00000000b9338578,0x00000000b94c0000)
+Event: 6.786 GC heap after
+Heap after GC invocations=4 (full 0):
+ PSYoungGen total 57344K, used 7117K [0x00000000eaab0000, 0x00000000eeaa0000, 0x0000000100000000)
+ eden space 49216K, 0% used [0x00000000eaab0000,0x00000000eaab0000,0x00000000edac0000)
+ from space 8128K, 87% used [0x00000000ee2b0000,0x00000000ee9a37c0,0x00000000eeaa0000)
+ to space 8128K, 0% used [0x00000000edac0000,0x00000000edac0000,0x00000000ee2b0000)
+ ParOldGen total 131008K, used 88K [0x00000000c0000000, 0x00000000c7ff0000, 0x00000000eaab0000)
+ object space 131008K, 0% used [0x00000000c0000000,0x00000000c0016010,0x00000000c7ff0000)
+ PSPermGen total 21248K, used 19681K [0x00000000b8000000, 0x00000000b94c0000, 0x00000000c0000000)
+ object space 21248K, 92% used [0x00000000b8000000,0x00000000b9338578,0x00000000b94c0000)
+}
+
+Deoptimization events (10 events):
+Event: 18.987 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd214
+Event: 18.987 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd478
+Event: 18.988 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd214
+Event: 18.992 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd214
+Event: 18.993 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd214
+Event: 18.993 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd214
+Event: 18.994 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd214
+Event: 18.995 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd214
+Event: 18.995 Thread 0x000000000de76000 Uncommon trap -89 fr.pc 0x00000000022cd214
+Event: 22.234 Thread 0x000000000de79800 Uncommon trap -83 fr.pc 0x0000000002247288
+
+Internal exceptions (10 events):
+Event: 19.054 Thread 0x000000000de79800 Threw 0x00000000ebed1c10 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 19.055 Thread 0x000000000de79800 Threw 0x00000000ebeec580 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 19.056 Thread 0x000000000de79800 Threw 0x00000000ebf05e38 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 19.058 Thread 0x000000000de79800 Threw 0x00000000ebf1e948 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 19.114 Thread 0x000000000de79800 Threw 0x00000000ebf42148 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 19.129 Thread 0x0000000001f68000 Threw 0x00000000ebf878e8 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 19.130 Thread 0x0000000001f68000 Threw 0x00000000ebf950a8 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 19.131 Thread 0x0000000001f68000 Threw 0x00000000ebfa5f60 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 19.152 Thread 0x0000000001f68000 Threw 0x00000000ebfd0778 at C:\jdk7u2_64p\jdk7u21\hotspot\src\share\vm\prims\jvm.cpp:1166
+Event: 22.234 Thread 0x000000000de79800 Implicit null exception at 0x0000000002246e49 to 0x0000000002247271
+
+Events (10 events):
+Event: 226.998 Executing VM operation: GetCurrentLocation
+Event: 226.998 Executing VM operation: GetCurrentLocation done
+Event: 226.998 Executing VM operation: EnterInterpOnlyMode
+Event: 226.998 Executing VM operation: EnterInterpOnlyMode done
+Event: 226.998 Executing VM operation: ChangeSingleStep
+Event: 226.998 Executing VM operation: ChangeSingleStep done
+Event: 226.998 Executing VM operation: ChangeSingleStep
+Event: 226.998 Executing VM operation: ChangeSingleStep done
+Event: 227.006 Executing VM operation: RedefineClasses
+Event: 227.009 Executing VM operation: RedefineClasses done
+
+
+Dynamic libraries:
+0x000000013ff00000 - 0x000000013ff33000 C:\Program Files\Java\jre7\bin\javaw.exe
+0x00000000772d0000 - 0x0000000077479000 C:\Windows\SYSTEM32\ntdll.dll
+0x00000000771b0000 - 0x00000000772cf000 C:\Windows\system32\kernel32.dll
+0x000007fefd470000 - 0x000007fefd4db000 C:\Windows\system32\KERNELBASE.dll
+0x000007feff250000 - 0x000007feff32b000 C:\Windows\system32\ADVAPI32.dll
+0x000007fefddd0000 - 0x000007fefde6f000 C:\Windows\system32\msvcrt.dll
+0x000007fefdb80000 - 0x000007fefdb9f000 C:\Windows\SYSTEM32\sechost.dll
+0x000007fefde70000 - 0x000007fefdf9d000 C:\Windows\system32\RPCRT4.dll
+0x00000000770b0000 - 0x00000000771aa000 C:\Windows\system32\USER32.dll
+0x000007fefe450000 - 0x000007fefe4b7000 C:\Windows\system32\GDI32.dll
+0x000007feff5d0000 - 0x000007feff5de000 C:\Windows\system32\LPK.dll
+0x000007fefd8a0000 - 0x000007fefd969000 C:\Windows\system32\USP10.dll
+0x000007fefbb60000 - 0x000007fefbd54000 C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_fa396087175ac9ac\COMCTL32.dll
+0x000007fefd4e0000 - 0x000007fefd551000 C:\Windows\system32\SHLWAPI.dll
+0x000007fefe420000 - 0x000007fefe44e000 C:\Windows\system32\IMM32.DLL
+0x000007fefe1b0000 - 0x000007fefe2b9000 C:\Windows\system32\MSCTF.dll
+0x0000000063a20000 - 0x0000000063af1000 C:\Program Files\Java\jre7\bin\msvcr100.dll
+0x00000000632f0000 - 0x0000000063a11000 C:\Program Files\Java\jre7\bin\server\jvm.dll
+0x000007fef8780000 - 0x000007fef8789000 C:\Windows\system32\WSOCK32.dll
+0x000007fefe100000 - 0x000007fefe14d000 C:\Windows\system32\WS2_32.dll
+0x000007feff5c0000 - 0x000007feff5c8000 C:\Windows\system32\NSI.dll
+0x000007fefac40000 - 0x000007fefac7b000 C:\Windows\system32\WINMM.dll
+0x0000000077490000 - 0x0000000077497000 C:\Windows\system32\PSAPI.DLL
+0x0000000074d50000 - 0x0000000074d5f000 C:\Program Files\Java\jre7\bin\verify.dll
+0x00000000632c0000 - 0x00000000632e8000 C:\Program Files\Java\jre7\bin\java.dll
+0x00000000648b0000 - 0x00000000648e5000 C:\Program Files\Java\jre7\bin\jdwp.dll
+0x00000000648a0000 - 0x00000000648a8000 C:\Program Files\Java\jre7\bin\npt.dll
+0x00000000632a0000 - 0x00000000632b5000 C:\Program Files\Java\jre7\bin\zip.dll
+0x0000000064890000 - 0x0000000064899000 C:\Program Files\Java\jre7\bin\dt_socket.dll
+0x000007fefa900000 - 0x000007fefa915000 C:\Windows\system32\NLAapi.dll
+0x000007fef80a0000 - 0x000007fef80b5000 C:\Windows\system32\napinsp.dll
+0x000007fef8080000 - 0x000007fef8099000 C:\Windows\system32\pnrpnsp.dll
+0x000007fefc900000 - 0x000007fefc955000 C:\Windows\System32\mswsock.dll
+0x000007fefc790000 - 0x000007fefc7eb000 C:\Windows\system32\DNSAPI.dll
+0x000007fef8070000 - 0x000007fef807b000 C:\Windows\System32\winrnr.dll
+0x000007fefa760000 - 0x000007fefa787000 C:\Windows\system32\IPHLPAPI.DLL
+0x000007fefa750000 - 0x000007fefa75b000 C:\Windows\system32\WINNSI.DLL
+0x000007fefa4e0000 - 0x000007fefa533000 C:\Windows\System32\fwpuclnt.dll
+0x000007fef8060000 - 0x000007fef8068000 C:\Windows\system32\rasadhlp.dll
+0x000007fefc2c0000 - 0x000007fefc2c7000 C:\Windows\System32\wshtcpip.dll
+0x0000000068780000 - 0x0000000068799000 C:\Program Files\Java\jre7\bin\net.dll
+0x000007fefcb80000 - 0x000007fefcb87000 C:\Windows\System32\wship6.dll
+0x0000000063280000 - 0x0000000063291000 C:\Program Files\Java\jre7\bin\nio.dll
+0x000007fefc960000 - 0x000007fefc977000 C:\Windows\system32\CRYPTSP.dll
+0x000007fefc670000 - 0x000007fefc6b7000 C:\Windows\system32\rsaenh.dll
+0x000007fefc3f0000 - 0x000007fefc40e000 C:\Windows\system32\USERENV.dll
+0x000007fefd0b0000 - 0x000007fefd0bf000 C:\Windows\system32\profapi.dll
+0x000007fefcfe0000 - 0x000007fefcfef000 C:\Windows\system32\CRYPTBASE.dll
+0x0000000064860000 - 0x0000000064884000 C:\Program Files\Java\jre7\bin\sunec.dll
+0x0000000064850000 - 0x000000006485b000 C:\Program Files\Java\jre7\bin\sunmscapi.dll
+0x000007fefd1c0000 - 0x000007fefd32a000 C:\Windows\system32\CRYPT32.dll
+0x000007fefd150000 - 0x000007fefd15f000 C:\Windows\system32\MSASN1.dll
+0x000007fef8bc0000 - 0x000007fef8ce5000 C:\Windows\system32\dbghelp.dll
+
+VM Arguments:
+jvm_args: -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:3250 -XX:MaxPermSize=128m -Xmx1024m -Dfile.encoding=UTF-8
+java_command: org.eclipse.jdt.internal.junit.runner.RemoteTestRunner -version 3 -port 3249 -testLoaderClass org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader -loaderpluginname org.eclipse.jdt.junit.runtime -test org.eclipse.emf.cdo.tests.ChunkingTest:testPartiallyLoadedAddAtIndex
+Launcher Type: SUN_STANDARD
+
+Environment Variables:
+PATH=C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\YourKit Java Profiler 12.0.2\bin\win64;C:\Program Files (x86)\Git\cmd;C:\Program Files (x86)\CVSNT\
+USERNAME=vroldan
+OS=Windows_NT
+PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 26 Stepping 5, GenuineIntel
+
+
+
+--------------- S Y S T E M ---------------
+
+OS: Windows 7 , 64 bit Build 7601 Service Pack 1
+
+CPU:total 8 (4 cores per cpu, 2 threads per core) family 6 model 26 stepping 5, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt, ht, tsc, tscinvbit, tscinv
+
+Memory: 4k page, physical 12573816k(7127872k free), swap 25145772k(16751756k free)
+
+vm_info: Java HotSpot(TM) 64-Bit Server VM (23.21-b01) for windows-amd64 JRE (1.7.0_21-b11), built on Apr 4 2013 08:11:28 by "java_re" with unknown MS VC++:1600
+
+time: Mon Aug 05 11:42:14 2013
+elapsed time: 227 seconds
+
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsCouchbase.java b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsCouchbase.java
new file mode 100644
index 0000000000..cf20994191
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsCouchbase.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2011-2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.couchbase;
+
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.emf.cdo.tests.AllConfigs;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_261218_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_303466_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_324585_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_411927_Test;
+import org.eclipse.emf.cdo.tests.config.IScenario;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest;
+
+import com.couchbase.client.clustermanager.BucketType;
+
+/**
+ * Some comments on setting up the tests:
+ * <p>
+ * check the server does have memory free for new bucket creation.
+ * If no memory is available, bucket creation fails silently
+ * <p>
+ * increase bucket number limit
+ * http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-admin-restapi-max-buckets.html
+ * curl -X POST -u admin:password -d maxBucketCount=20 http://ip_address:8091/internalSettings
+ *
+ * @author Victor Roldan Betancort
+ */
+public class AllTestsCouchbase extends AllConfigs
+{
+ public static Test suite()
+ {
+ return new AllTestsCouchbase().getTestSuite();
+ }
+
+ @Override
+ protected void initConfigSuites(TestSuite parent)
+ {
+ addScenario(parent, COMBINED, new CouchbaseConfig(BucketType.COUCHBASE), JVM, NATIVE);
+ }
+
+ @Override
+ protected void initTestClasses(List<Class<? extends ConfigTest>> testClasses, IScenario scenario)
+ {
+ super.initTestClasses(testClasses, scenario);
+
+ // Added here testcases to skip
+ // takes too much
+ testClasses.remove(Bugzilla_261218_Test.class);
+ testClasses.remove(Bugzilla_324585_Test.class);
+ testClasses.remove(Bugzilla_411927_Test.class);
+
+ // this test-case uses files that cannot be found because
+ // are no longer where is expected (due to git)
+ // (if manually added the file, it passes)
+ testClasses.remove(Bugzilla_303466_Test.class);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsMemcached.java b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsMemcached.java
new file mode 100644
index 0000000000..9b44d8b69d
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/AllTestsMemcached.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011-2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.couchbase;
+
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.emf.cdo.tests.AllConfigs;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_303466_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_324585_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_377212_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_390185_Test;
+import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_411927_Test;
+import org.eclipse.emf.cdo.tests.config.IScenario;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest;
+
+import com.couchbase.client.clustermanager.BucketType;
+
+/**
+ * Some comments on setting up the tests:
+ * <p>
+ * check the server does have memory free for new bucket creation.
+ * If no memory is available, bucket creation fails silently
+ * <p>
+ * increase bucket number limit
+ * http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-admin-restapi-max-buckets.html
+ * curl -X POST -u admin:password -d maxBucketCount=20 http://ip_address:8091/internalSettings
+ *
+ * @author Victor Roldan Betancort
+ */
+public class AllTestsMemcached extends AllConfigs
+{
+ public static Test suite()
+ {
+ return new AllTestsMemcached().getTestSuite();
+ }
+
+ @Override
+ protected void initConfigSuites(TestSuite parent)
+ {
+ addScenario(parent, COMBINED, new CouchbaseConfig(BucketType.MEMCACHED), JVM, NATIVE);
+ }
+
+ @Override
+ protected void initTestClasses(List<Class<? extends ConfigTest>> testClasses, IScenario scenario)
+ {
+ super.initTestClasses(testClasses, scenario);
+
+ // Added here test-cases to skip
+ // takes too much
+ testClasses.remove(Bugzilla_324585_Test.class); // 33s
+ testClasses.remove(Bugzilla_377212_Test.class); // 36s
+ testClasses.remove(Bugzilla_390185_Test.class); // 30s
+ testClasses.remove(Bugzilla_411927_Test.class); // does not end
+
+ // this test-case uses files that cannot be found because
+ // are no longer where is expected (due to git)
+ // (if manually added the file, it passes)
+ testClasses.remove(Bugzilla_303466_Test.class);
+
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/CouchbaseConfig.java b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/CouchbaseConfig.java
new file mode 100644
index 0000000000..c790750e6c
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/CouchbaseConfig.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2011, 2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.couchbase;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation;
+import org.eclipse.emf.cdo.server.IStore;
+import org.eclipse.emf.cdo.server.couchbase.ICouchbaseStore;
+import org.eclipse.emf.cdo.server.internal.CouchbaseStore;
+import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig;
+
+import com.couchbase.client.clustermanager.BucketType;
+
+/**
+ * @author Victor Roldan Betancort
+ */
+public class CouchbaseConfig extends RepositoryConfig {
+ private static final long serialVersionUID = 1L;
+
+ private static final String HOST = "localhost";
+
+ private static final String PORT = "8091";
+
+ private static final String USER = "Administrator";
+
+ private static final String PASS = "scaverok";
+
+ private static final URI COUCHBASE_URI = URI.create("http://" + HOST + ":" + PORT + "/pools");
+
+ private static Map<String, Boolean> bucketCleaned = new HashMap<String, Boolean>();
+
+ private static boolean firstRun = true;
+
+ private transient CouchbaseUtil couchbaseUtil;
+
+ private BucketType bucketType;
+
+ public CouchbaseConfig(BucketType bucketType) {
+ super(ICouchbaseStore.TYPE, false, false, IDGenerationLocation.STORE);
+ this.bucketType = bucketType;
+ }
+
+ @Override
+ public void initCapabilities(Set<String> capabilities) {
+ super.initCapabilities(capabilities);
+ }
+
+ @Override
+ protected String getStoreName() {
+ return "Couchbase";
+ }
+
+ public IStore createStore(String repoName) {
+ initBucket(repoName);
+ List<URI> uris = new LinkedList<URI>();
+ uris.add(COUCHBASE_URI);
+ return new CouchbaseStore(uris, repoName, USER, PASS);
+ }
+
+ // buckets get cleaned only once for the whole test-suite
+ // (cleaning takes too much)
+ private void initBucket(String repoName) {
+ if (firstRun) {
+ try {
+ getCouchbaseUtil().deleteAllBuckets();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ firstRun = false;
+ }
+ Boolean bucketIsClean = bucketCleaned.get(repoName);
+ if (bucketIsClean == null) {
+ bucketIsClean = false;
+ }
+ if (!bucketIsClean || needsCleanRepos()) {
+ try {
+ getCouchbaseUtil().cleanBucket(repoName);
+ bucketCleaned.put(repoName, true);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private CouchbaseUtil getCouchbaseUtil() {
+ if (couchbaseUtil == null) {
+ couchbaseUtil = new CouchbaseUtil(bucketType, HOST, PORT, USER, PASS);
+ }
+ return couchbaseUtil;
+ }
+
+
+ @Override
+ protected void deactivateRepositories() {
+ super.deactivateRepositories();
+ if (couchbaseUtil != null) {
+ couchbaseUtil.clear();
+ }
+ couchbaseUtil = null;
+ }
+
+
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/CouchbaseUtil.java b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/CouchbaseUtil.java
new file mode 100644
index 0000000000..0fc5263200
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/CouchbaseUtil.java
@@ -0,0 +1,176 @@
+package org.eclipse.emf.cdo.tests.couchbase;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
+
+import net.spy.memcached.MemcachedClient;
+
+import com.couchbase.client.ClusterManager;
+import com.couchbase.client.CouchbaseClient;
+import com.couchbase.client.CouchbaseConnectionFactory;
+import com.couchbase.client.CouchbaseConnectionFactoryBuilder;
+import com.couchbase.client.clustermanager.BucketType;
+
+public class CouchbaseUtil {
+
+ private static final int BUCKET_MEMORY = 100;
+
+ private ClusterManager manager;
+
+ private MemcachedClient client;
+
+ private BucketType bucketType;
+
+ private String host;
+
+ private String port;
+
+ private String user;
+
+ private String pass;
+
+ public CouchbaseUtil(BucketType bucketType, String host, String port, String user, String pass) {
+ this.bucketType = bucketType;
+ this.host = host;
+ this.port = port;
+ this.user = user;
+ this.pass = pass;
+ }
+
+ public boolean isBucketEmpty(String bucketName) {
+ Map<SocketAddress, Map<String, String>> stats = getClient(bucketName)
+ .getStats();
+ for (Entry<SocketAddress, Map<String, String>> server : stats
+ .entrySet()) {
+ Map<String, String> serverStats = server.getValue();
+ if (bucketName.equals(serverStats.get("ep_couch_bucket"))) {
+ String value = serverStats.get("curr_items");
+ if (value != null) {
+ if (Integer.parseInt(value) == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Makes sure the argument bucket is created and empty
+ */
+ public void cleanBucket(String bucketName) throws Exception {
+ if (!existBucket(bucketName)) {
+ try {
+ createBucket(bucketName);
+ // it is necessary to wait a bit after creation or client connection will fail
+ // see http://www.couchbase.com/forums/thread/number-buckets-must-be-power-two-0-and-0
+ if (bucketType == BucketType.COUCHBASE) {
+ Thread.sleep(1000);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ if (!isBucketEmpty(bucketName)) {
+ flushBucket(bucketName);
+ }
+
+ }
+ waitForWarmup(bucketName);
+ }
+
+ public void createBucket(String bucketName) throws Exception {
+ ClusterManager manager = getClusterManager();
+ manager.createNamedBucket(bucketType, bucketName, BUCKET_MEMORY, 0, pass, true);
+ }
+
+ public void flushBucket(String bucketName) {
+ ClusterManager manager = getClusterManager();
+ manager.flushBucket(bucketName);
+ }
+
+ public void deleteBucket(String bucketName) throws Exception {
+ ClusterManager manager = getClusterManager();
+ manager.deleteBucket(bucketName);
+ }
+
+ public void deleteAllBuckets() throws Exception {
+ ClusterManager manager = getClusterManager();
+ for (String bucketName : manager.listBuckets()) {
+ manager.deleteBucket(bucketName);
+ }
+ }
+
+ public boolean existBucket(String bucketName) throws Exception {
+ ClusterManager manager = getClusterManager();
+ return manager.listBuckets().contains(bucketName);
+ }
+
+ public ClusterManager getClusterManager() {
+ if (manager == null) {
+ List<URI> uris = new LinkedList<URI>();
+ uris.add(URI.create("http://" + host + ":" + port + "/pools"));
+ manager = new ClusterManager(uris, user, pass);
+ }
+ return manager;
+ }
+
+ public MemcachedClient getClient(String bucketName) {
+ if (client == null) {
+ List<URI> uris = new LinkedList<URI>();
+ uris.add(URI.create("http://" + host + ":" + port + "/pools"));
+ try {
+ CouchbaseConnectionFactoryBuilder connectionFactoryBuilder = new CouchbaseConnectionFactoryBuilder();
+ connectionFactoryBuilder.setOpTimeout(10000); // To avoid random "Cancelled" upon client.get() calls
+ CouchbaseConnectionFactory connectionFactory = connectionFactoryBuilder.buildCouchbaseConnection(uris, bucketName, user, pass);
+ client = new CouchbaseClient((CouchbaseConnectionFactory)connectionFactory);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return client;
+ }
+
+ public void waitForWarmup(String bucketName) throws Exception {
+ // Couchbase-type bucket needs warmup time after flush, memcached does not
+ boolean warmup = bucketType == BucketType.COUCHBASE? true : false;
+ while (warmup) {
+ warmup = false;
+ Map<SocketAddress, Map<String, String>> stats = getClient(
+ bucketName).getStats();
+ for (Entry<SocketAddress, Map<String, String>> server : stats
+ .entrySet()) {
+ Map<String, String> serverStats = server.getValue();
+ if (!serverStats.containsKey("ep_degraded_mode")) {
+ warmup = true;
+ Thread.sleep(1000);
+ break;
+ }
+ if (!serverStats.get("ep_degraded_mode").equals("0")) {
+ warmup = true;
+ Thread.sleep(1000);
+ break;
+ }
+ }
+ }
+ }
+
+ public void clear() {
+ if (client != null) {
+ client.shutdown(10, TimeUnit.SECONDS);
+ client = null;
+ }
+ if (manager != null) {
+ manager.shutdown();
+ manager = null;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/bundle/OM.java b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/bundle/OM.java
new file mode 100644
index 0000000000..09cdf4c322
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests.couchbase/src/org/eclipse/emf/cdo/tests/couchbase/bundle/OM.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009, 2011, 2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Victor Roldan Betancort - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.couchbase.bundle;
+
+import org.eclipse.net4j.util.om.OMBundle;
+import org.eclipse.net4j.util.om.OMPlatform;
+import org.eclipse.net4j.util.om.OSGiActivator;
+import org.eclipse.net4j.util.om.log.OMLogger;
+import org.eclipse.net4j.util.om.trace.OMTracer;
+
+/**
+ * The <em>Operations & Maintenance</em> class of this bundle.
+ *
+ * @author Victor Roldan Betancort
+ */
+public abstract class OM
+{
+ public static final String BUNDLE_ID = "org.eclipse.emf.cdo.tests.couchbase"; //$NON-NLS-1$
+
+ public static final OMBundle BUNDLE = OMPlatform.INSTANCE.bundle(BUNDLE_ID, OM.class);
+
+ public static final OMTracer DEBUG = BUNDLE.tracer("debug"); //$NON-NLS-1$
+
+ public static final OMLogger LOG = BUNDLE.logger();
+
+ /**
+ * @author Victor Roldan Betancort
+ */
+ public static final class Activator extends OSGiActivator
+ {
+ public Activator()
+ {
+ super(BUNDLE);
+ }
+ }
+}

Back to the top