diff --git a/couchbase-sdk-intro/.classpath b/couchbase-sdk-intro/.classpath
new file mode 100644
index 0000000000..698778fef3
--- /dev/null
+++ b/couchbase-sdk-intro/.classpath
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/couchbase-sdk-intro/.mvn/wrapper/maven-wrapper.jar b/couchbase-sdk-intro/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000000..5fd4d5023f
Binary files /dev/null and b/couchbase-sdk-intro/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/couchbase-sdk-intro/.mvn/wrapper/maven-wrapper.properties b/couchbase-sdk-intro/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000000..eb91947648
--- /dev/null
+++ b/couchbase-sdk-intro/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1 @@
+distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip
\ No newline at end of file
diff --git a/couchbase-sdk-intro/.project b/couchbase-sdk-intro/.project
new file mode 100644
index 0000000000..b5b2a86ff9
--- /dev/null
+++ b/couchbase-sdk-intro/.project
@@ -0,0 +1,23 @@
+
+
+ couchbase-intro
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/couchbase-sdk-intro/mvnw b/couchbase-sdk-intro/mvnw
new file mode 100755
index 0000000000..a1ba1bf554
--- /dev/null
+++ b/couchbase-sdk-intro/mvnw
@@ -0,0 +1,233 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ #
+ # Look for the Apple JDKs first to preserve the existing behaviour, and then look
+ # for the new JDKs provided by Oracle.
+ #
+ if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
+ #
+ # Oracle JDKs
+ #
+ export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=`/usr/libexec/java_home`
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Migwn, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+ # TODO classpath?
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ local basedir=$(pwd)
+ local wdir=$(pwd)
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ wdir=$(cd "$wdir/.."; pwd)
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} "$@"
diff --git a/couchbase-sdk-intro/mvnw.cmd b/couchbase-sdk-intro/mvnw.cmd
new file mode 100644
index 0000000000..2b934e89dd
--- /dev/null
+++ b/couchbase-sdk-intro/mvnw.cmd
@@ -0,0 +1,145 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+set MAVEN_CMD_LINE_ARGS=%*
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+
+set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
\ No newline at end of file
diff --git a/couchbase-sdk-intro/pom.xml b/couchbase-sdk-intro/pom.xml
new file mode 100644
index 0000000000..1c2ca5ee05
--- /dev/null
+++ b/couchbase-sdk-intro/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+ com.baeldung
+ couchbase-sdk-intro
+ 0.1-SNAPSHOT
+ jar
+ couchbase-sdk-intro
+ Intro to the Couchbase SDK
+
+
+
+
+ com.couchbase.client
+ java-client
+ ${couchbase.client.version}
+
+
+
+
+
+
+ maven-compiler-plugin
+ 2.3.2
+
+ 1.7
+ 1.7
+
+
+
+
+
+
+ 1.7
+ UTF-8
+ 2.2.6
+
+
+
diff --git a/couchbase-sdk-intro/src/main/java/com/baeldung/couchbase/examples/CodeSnippets.java b/couchbase-sdk-intro/src/main/java/com/baeldung/couchbase/examples/CodeSnippets.java
new file mode 100644
index 0000000000..088f7af7b1
--- /dev/null
+++ b/couchbase-sdk-intro/src/main/java/com/baeldung/couchbase/examples/CodeSnippets.java
@@ -0,0 +1,96 @@
+package com.baeldung.couchbase.examples;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.couchbase.client.core.CouchbaseException;
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.Cluster;
+import com.couchbase.client.java.CouchbaseCluster;
+import com.couchbase.client.java.ReplicaMode;
+import com.couchbase.client.java.document.JsonDocument;
+import com.couchbase.client.java.document.json.JsonObject;
+import com.couchbase.client.java.env.CouchbaseEnvironment;
+import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
+
+public class CodeSnippets {
+
+ static Cluster loadClusterWithDefaultEnvironment() {
+ return CouchbaseCluster.create("localhost");
+ }
+
+ static Cluster loadClusterWithCustomEnvironment() {
+ CouchbaseEnvironment env = DefaultCouchbaseEnvironment.builder()
+ .connectTimeout(10000)
+ .kvTimeout(3000)
+ .build();
+ return CouchbaseCluster.create(env, "localhost");
+ }
+
+ static Bucket loadDefaultBucketWithBlankPassword(Cluster cluster) {
+ return cluster.openBucket();
+ }
+
+ static Bucket loadBaeldungBucket(Cluster cluster) {
+ return cluster.openBucket("baeldung", "");
+ }
+
+ static JsonDocument insertExample(Bucket bucket) {
+ JsonObject content = JsonObject.empty()
+ .put("name", "John Doe")
+ .put("type", "Person")
+ .put("email", "john.doe@mydomain.com")
+ .put("homeTown", "Chicago")
+ ;
+ String id = UUID.randomUUID().toString();
+ JsonDocument document = JsonDocument.create(id, content);
+ JsonDocument inserted = bucket.insert(document);
+ return inserted;
+ }
+
+ static JsonDocument retrieveAndUpsertExample(Bucket bucket, String id) {
+ JsonDocument document = bucket.get(id);
+ JsonObject content = document.content();
+ content.put("homeTown", "Kansas City");
+ JsonDocument upserted = bucket.upsert(document);
+ return upserted;
+ }
+
+ static JsonDocument replaceExample(Bucket bucket, String id) {
+ JsonDocument document = bucket.get(id);
+ JsonObject content = document.content();
+ content.put("homeTown", "Milwaukee");
+ JsonDocument replaced = bucket.replace(document);
+ return replaced;
+ }
+
+ static JsonDocument removeExample(Bucket bucket, String id) {
+ JsonDocument removed = bucket.remove(id);
+ return removed;
+ }
+
+ static JsonDocument getFirstFromReplicaExample(Bucket bucket, String id) {
+ try{
+ return bucket.get(id);
+ }
+ catch(CouchbaseException e) {
+ List list = bucket.getFromReplica(id, ReplicaMode.FIRST);
+ if(!list.isEmpty()) {
+ return list.get(0);
+ }
+ }
+ return null;
+ }
+
+ static JsonDocument getLatestReplicaVersion(Bucket bucket, String id) {
+ long maxCasValue = -1;
+ JsonDocument latest = null;
+ for(JsonDocument replica : bucket.getFromReplica(id, ReplicaMode.ALL)) {
+ if(replica.cas() > maxCasValue) {
+ latest = replica;
+ maxCasValue = replica.cas();
+ }
+ }
+ return latest;
+ }
+}
diff --git a/couchbase-sdk-spring-service/.mvn/wrapper/maven-wrapper.jar b/couchbase-sdk-spring-service/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000000..5fd4d5023f
Binary files /dev/null and b/couchbase-sdk-spring-service/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/couchbase-sdk-spring-service/.mvn/wrapper/maven-wrapper.properties b/couchbase-sdk-spring-service/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000000..eb91947648
--- /dev/null
+++ b/couchbase-sdk-spring-service/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1 @@
+distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip
\ No newline at end of file
diff --git a/couchbase-sdk-spring-service/.springBeans b/couchbase-sdk-spring-service/.springBeans
new file mode 100644
index 0000000000..ff32b84d3b
--- /dev/null
+++ b/couchbase-sdk-spring-service/.springBeans
@@ -0,0 +1,15 @@
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/couchbase-sdk-spring-service/mvnw b/couchbase-sdk-spring-service/mvnw
new file mode 100755
index 0000000000..a1ba1bf554
--- /dev/null
+++ b/couchbase-sdk-spring-service/mvnw
@@ -0,0 +1,233 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ #
+ # Look for the Apple JDKs first to preserve the existing behaviour, and then look
+ # for the new JDKs provided by Oracle.
+ #
+ if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
+ #
+ # Oracle JDKs
+ #
+ export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
+ fi
+
+ if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
+ #
+ # Apple JDKs
+ #
+ export JAVA_HOME=`/usr/libexec/java_home`
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Migwn, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+ # TODO classpath?
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ local basedir=$(pwd)
+ local wdir=$(pwd)
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ wdir=$(cd "$wdir/.."; pwd)
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} "$@"
diff --git a/couchbase-sdk-spring-service/mvnw.cmd b/couchbase-sdk-spring-service/mvnw.cmd
new file mode 100644
index 0000000000..2b934e89dd
--- /dev/null
+++ b/couchbase-sdk-spring-service/mvnw.cmd
@@ -0,0 +1,145 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+set MAVEN_CMD_LINE_ARGS=%*
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+
+set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
\ No newline at end of file
diff --git a/couchbase-sdk-spring-service/pom.xml b/couchbase-sdk-spring-service/pom.xml
new file mode 100644
index 0000000000..d344f8c756
--- /dev/null
+++ b/couchbase-sdk-spring-service/pom.xml
@@ -0,0 +1,102 @@
+
+
+ 4.0.0
+ com.baeldung
+ couchbase-sdk-spring-service
+ 0.1-SNAPSHOT
+ jar
+ couchbase-sdk-spring-service
+ Intro to the Couchbase SDK
+
+
+
+
+ com.couchbase.client
+ java-client
+ ${couchbase.client.version}
+
+
+
+
+ org.springframework
+ spring-context
+ ${spring-framework.version}
+
+
+ org.springframework
+ spring-context-support
+ ${spring-framework.version}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${org.slf4j.version}
+ compile
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${org.slf4j.version}
+
+
+ org.slf4j
+ log4j-over-slf4j
+ ${org.slf4j.version}
+
+
+
+
+ org.springframework
+ spring-test
+ ${spring-framework.version}
+ test
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+ test
+
+
+
+
+
+
+ maven-compiler-plugin
+ 2.3.2
+
+ 1.7
+ 1.7
+
+
+
+
+
+
+ 1.7
+ UTF-8
+ 2.2.6
+ 4.2.4.RELEASE
+ 1.1.3
+ 1.7.12
+ 4.11
+ 3.4
+
+
+
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/FluentPersonDocumentConverter.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/FluentPersonDocumentConverter.java
new file mode 100644
index 0000000000..8210c10b3a
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/FluentPersonDocumentConverter.java
@@ -0,0 +1,31 @@
+package com.baeldung.couchbase.person;
+
+import org.springframework.stereotype.Service;
+
+import com.baeldung.couchbase.service.JsonDocumentConverter;
+import com.couchbase.client.java.document.JsonDocument;
+import com.couchbase.client.java.document.json.JsonObject;
+
+@Service
+public class FluentPersonDocumentConverter implements JsonDocumentConverter {
+
+ @Override
+ public JsonDocument toDocument(Person p) {
+ JsonObject content = JsonObject.empty()
+ .put("type", "Person")
+ .put("name", p.getName())
+ .put("homeTown", p.getHomeTown());
+ return JsonDocument.create(p.getId(), content);
+ }
+
+ @Override
+ public Person fromDocument(JsonDocument doc) {
+ JsonObject content = doc.content();
+ return Person.Builder.newInstance()
+ .id(doc.id())
+ .type("Person")
+ .name(content.getString("name"))
+ .homeTown(content.getString("homeTown"))
+ .build();
+ }
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/Person.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/Person.java
new file mode 100644
index 0000000000..48b7a38780
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/Person.java
@@ -0,0 +1,85 @@
+package com.baeldung.couchbase.person;
+
+public class Person {
+
+ private String id;
+ private String type;
+ private String name;
+ private String homeTown;
+
+ Person() {}
+
+ public Person(Builder b) {
+ this.id = b.id;
+ this.type = b.type;
+ this.name = b.name;
+ this.homeTown = b.homeTown;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getHomeTown() {
+ return homeTown;
+ }
+
+ public void setHomeTown(String homeTown) {
+ this.homeTown = homeTown;
+ }
+
+ public static class Builder {
+ private String id;
+ private String type;
+ private String name;
+ private String homeTown;
+
+ public static Builder newInstance() {
+ return new Builder();
+ }
+
+ public Person build() {
+ return new Person(this);
+ }
+
+ public Builder id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder type(String type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder homeTown(String homeTown) {
+ this.homeTown = homeTown;
+ return this;
+ }
+ }
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/PersonCrudService.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/PersonCrudService.java
new file mode 100644
index 0000000000..0203bf30bb
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/PersonCrudService.java
@@ -0,0 +1,68 @@
+package com.baeldung.couchbase.person;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.baeldung.couchbase.service.CrudService;
+import com.baeldung.couchbase.service.TutorialBucketService;import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.ReplicaMode;
+import com.couchbase.client.java.document.JsonDocument;
+
+@Service
+public class PersonCrudService implements CrudService {
+
+ @Autowired
+ private TutorialBucketService bucketService;
+
+ @Autowired
+ private PersonDocumentConverter converter;
+
+ private Bucket bucket;
+
+ @PostConstruct
+ private void init() {
+ bucket = bucketService.getBucket();
+ }
+
+ @Override
+ public void create(Person person) {
+ if(person.getId() == null) {
+ person.setId(UUID.randomUUID().toString());
+ }
+ JsonDocument document = converter.toDocument(person);
+ bucket.insert(document);
+ }
+
+ @Override
+ public Person read(String id) {
+ JsonDocument doc = bucket.get(id);
+ return (doc != null ? converter.fromDocument(doc) : null);
+ }
+
+ @Override
+ public Person readFromReplica(String id) {
+ List docs = bucket.getFromReplica(id, ReplicaMode.FIRST);
+ return (docs.isEmpty() ? null : converter.fromDocument(docs.get(0)));
+ }
+
+ @Override
+ public void update(Person person) {
+ JsonDocument document = converter.toDocument(person);
+ bucket.upsert(document);
+ }
+
+ @Override
+ public void delete(String id) {
+ bucket.remove(id);
+ }
+
+ @Override
+ public boolean exists(String id) {
+ return bucket.exists(id);
+ }
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/PersonDocumentConverter.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/PersonDocumentConverter.java
new file mode 100644
index 0000000000..cfb20a2bfb
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/PersonDocumentConverter.java
@@ -0,0 +1,31 @@
+package com.baeldung.couchbase.person;
+
+import org.springframework.stereotype.Service;
+
+import com.baeldung.couchbase.service.JsonDocumentConverter;
+import com.couchbase.client.java.document.JsonDocument;
+import com.couchbase.client.java.document.json.JsonObject;
+
+@Service
+public class PersonDocumentConverter implements JsonDocumentConverter {
+
+ @Override
+ public JsonDocument toDocument(Person p) {
+ JsonObject content = JsonObject.empty()
+ .put("type", "Person")
+ .put("name", p.getName())
+ .put("homeTown", p.getHomeTown());
+ return JsonDocument.create(p.getId(), content);
+ }
+
+ @Override
+ public Person fromDocument(JsonDocument doc) {
+ JsonObject content = doc.content();
+ Person p = new Person();
+ p.setId(doc.id());
+ p.setType("Person");
+ p.setName(content.getString("name"));
+ p.setHomeTown(content.getString("homeTown"));
+ return p;
+ }
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/RegistrationService.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/RegistrationService.java
new file mode 100644
index 0000000000..53af1c4041
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/person/RegistrationService.java
@@ -0,0 +1,29 @@
+package com.baeldung.couchbase.person;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.couchbase.client.core.CouchbaseException;
+
+@Service
+public class RegistrationService {
+
+ @Autowired
+ private PersonCrudService crud;
+
+ public void registerNewPerson(String name, String homeTown) {
+ Person person = new Person();
+ person.setName(name);
+ person.setHomeTown(homeTown);
+ crud.create(person);
+ }
+
+ public Person findRegistrant(String id) {
+ try{
+ return crud.read(id);
+ }
+ catch(CouchbaseException e) {
+ return crud.readFromReplica(id);
+ }
+ }
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/BucketService.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/BucketService.java
new file mode 100644
index 0000000000..c2562dd38e
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/BucketService.java
@@ -0,0 +1,9 @@
+package com.baeldung.couchbase.service;
+
+import com.couchbase.client.java.Bucket;
+
+public interface BucketService {
+
+ Bucket getBucket();
+
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/ClusterService.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/ClusterService.java
new file mode 100644
index 0000000000..4713893899
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/ClusterService.java
@@ -0,0 +1,17 @@
+package com.baeldung.couchbase.service;
+
+import java.util.List;
+
+import com.couchbase.client.java.AsyncBucket;
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.document.JsonDocument;
+
+public interface ClusterService {
+
+ Bucket openBucket(String name, String password);
+
+ List getDocuments(Bucket bucket, Iterable keys);
+
+ List getDocumentsAsync(AsyncBucket bucket, Iterable keys);
+
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/ClusterServiceImpl.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/ClusterServiceImpl.java
new file mode 100644
index 0000000000..3c355d2a27
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/ClusterServiceImpl.java
@@ -0,0 +1,84 @@
+package com.baeldung.couchbase.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.PostConstruct;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import com.couchbase.client.java.AsyncBucket;
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.Cluster;
+import com.couchbase.client.java.CouchbaseCluster;
+import com.couchbase.client.java.document.JsonDocument;
+import com.couchbase.client.java.env.CouchbaseEnvironment;
+import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
+
+import rx.Observable;
+import rx.functions.Action1;
+import rx.functions.Func1;
+
+@Service
+public class ClusterServiceImpl implements ClusterService {
+ private static final Logger logger = LoggerFactory.getLogger(ClusterServiceImpl.class);
+
+ private Cluster cluster;
+ private Map buckets = new ConcurrentHashMap<>();
+
+ @PostConstruct
+ private void init() {
+ CouchbaseEnvironment env = DefaultCouchbaseEnvironment.create();
+ cluster = CouchbaseCluster.create(env, "localhost");
+ }
+
+ @Override
+ synchronized public Bucket openBucket(String name, String password) {
+ if(!buckets.containsKey(name)) {
+ Bucket bucket = cluster.openBucket(name, password);
+ buckets.put(name, bucket);
+ }
+ return buckets.get(name);
+ }
+
+ @Override
+ public List getDocuments(Bucket bucket, Iterable keys) {
+ List docs = new ArrayList<>();
+ for(String key : keys) {
+ JsonDocument doc = bucket.get(key);
+ if(doc != null) {
+ docs.add(doc);
+ }
+ }
+ return docs;
+ }
+
+ @Override
+ public List getDocumentsAsync(final AsyncBucket asyncBucket, Iterable keys) {
+ Observable asyncBulkGet = Observable
+ .from(keys)
+ .flatMap(new Func1>() {
+ public Observable call(String key) {
+ return asyncBucket.get(key);
+ }
+ });
+
+ final List docs = new ArrayList<>();
+ try {
+ asyncBulkGet.toBlocking()
+ .forEach(new Action1() {
+ public void call(JsonDocument doc) {
+ docs.add(doc);
+ }
+ });
+ } catch (Exception e) {
+ logger.error("Error during bulk get", e);
+ }
+
+ return docs;
+ }
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/CrudService.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/CrudService.java
new file mode 100644
index 0000000000..20ee851b39
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/CrudService.java
@@ -0,0 +1,16 @@
+package com.baeldung.couchbase.service;
+
+public interface CrudService {
+
+ void create(T t);
+
+ T read(String id);
+
+ T readFromReplica(String id);
+
+ void update(T t);
+
+ void delete(String id);
+
+ boolean exists(String id);
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/JsonDocumentConverter.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/JsonDocumentConverter.java
new file mode 100644
index 0000000000..87331d2a17
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/JsonDocumentConverter.java
@@ -0,0 +1,10 @@
+package com.baeldung.couchbase.service;
+
+import com.couchbase.client.java.document.JsonDocument;
+
+public interface JsonDocumentConverter {
+
+ JsonDocument toDocument(T t);
+
+ T fromDocument(JsonDocument doc);
+}
diff --git a/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/TutorialBucketService.java b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/TutorialBucketService.java
new file mode 100644
index 0000000000..903a568399
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/java/com/baeldung/couchbase/service/TutorialBucketService.java
@@ -0,0 +1,29 @@
+package com.baeldung.couchbase.service;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import com.couchbase.client.java.Bucket;
+
+@Service
+@Qualifier("TutorialBucketService")
+public class TutorialBucketService implements BucketService {
+
+ @Autowired
+ private ClusterService couchbase;
+
+ private Bucket bucket;
+
+ @PostConstruct
+ private void init() {
+ bucket = couchbase.openBucket("baeldung-tutorial", "");
+ }
+
+ @Override
+ public Bucket getBucket() {
+ return bucket;
+ }
+}
diff --git a/couchbase-sdk-spring-service/src/main/resources/application.properties b/couchbase-sdk-spring-service/src/main/resources/application.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/couchbase-sdk-spring-service/src/main/resources/logback.xml b/couchbase-sdk-spring-service/src/main/resources/logback.xml
new file mode 100644
index 0000000000..efcc6fb4c7
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/main/resources/logback.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ web - %date [%thread] %-5level %logger{36} - %message%n
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/IntegrationTest.java b/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/IntegrationTest.java
new file mode 100644
index 0000000000..d1cc807f7a
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/IntegrationTest.java
@@ -0,0 +1,13 @@
+package com.baeldung.couchbase;
+
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { IntegrationTestConfig.class })
+@TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
+public abstract class IntegrationTest {
+}
diff --git a/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/IntegrationTestConfig.java b/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/IntegrationTestConfig.java
new file mode 100644
index 0000000000..d593aac52d
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/IntegrationTestConfig.java
@@ -0,0 +1,9 @@
+package com.baeldung.couchbase;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ComponentScan(basePackages={"com.baeldung.couchbase"})
+public class IntegrationTestConfig {
+}
diff --git a/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/person/PersonCrudServiceTest.java b/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/person/PersonCrudServiceTest.java
new file mode 100644
index 0000000000..e19e90769c
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/person/PersonCrudServiceTest.java
@@ -0,0 +1,82 @@
+package com.baeldung.couchbase.person;
+
+import static org.junit.Assert.*;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.baeldung.couchbase.IntegrationTest;
+
+public class PersonCrudServiceTest extends IntegrationTest {
+
+ private static final String CLARK_KENT = "Clark Kent";
+ private static final String SMALLVILLE = "Smallville";
+ private static final String CLARK_KENT_ID = "Person:ClarkKent";
+
+ private Person clarkKent;
+
+ @Autowired
+ private PersonCrudService personService;
+
+ @PostConstruct
+ private void init() {
+ clarkKent = personService.read(CLARK_KENT_ID);
+ if(clarkKent == null) {
+ clarkKent = buildClarkKent();
+ personService.create(clarkKent);
+ }
+ }
+
+ @Test
+ public final void givenRandomPerson_whenCreate_thenPersonPersisted() {
+ Person person = randomPerson();
+ personService.create(person);
+ String id = person.getId();
+ assertNotNull(personService.read(id));
+ }
+
+ @Test
+ public final void givenClarkKentId_whenRead_thenReturnsClarkKent() {
+ Person person = personService.read(CLARK_KENT_ID);
+ assertNotNull(person);
+ }
+
+ @Test
+ public final void givenNewHometown_whenUpdate_thenNewHometownPersisted() {
+ Person expected = randomPerson();
+ personService.create(expected);
+ String updatedHomeTown = RandomStringUtils.randomAlphabetic(12);
+ expected.setHomeTown(updatedHomeTown);
+ personService.update(expected);
+ Person actual = personService.read(expected.getId());
+ assertNotNull(actual);
+ assertEquals(expected.getHomeTown(), actual.getHomeTown());
+ }
+
+ @Test
+ public final void givenRandomPerson_whenDelete_thenPersonNotInBucket() {
+ Person person = randomPerson();
+ personService.create(person);
+ String id = person.getId();
+ personService.delete(id);
+ assertNull(personService.read(id));
+ }
+
+ private Person buildClarkKent() {
+ return Person.Builder.newInstance()
+ .id(CLARK_KENT_ID)
+ .name(CLARK_KENT)
+ .homeTown(SMALLVILLE)
+ .build();
+ }
+
+ private Person randomPerson() {
+ return Person.Builder.newInstance()
+ .name(RandomStringUtils.randomAlphabetic(10))
+ .homeTown(RandomStringUtils.randomAlphabetic(10))
+ .build();
+ }
+}
diff --git a/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/service/ClusterServiceTest.java b/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/service/ClusterServiceTest.java
new file mode 100644
index 0000000000..7795f41c93
--- /dev/null
+++ b/couchbase-sdk-spring-service/src/test/java/com/baeldung/couchbase/service/ClusterServiceTest.java
@@ -0,0 +1,34 @@
+package com.baeldung.couchbase.service;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+
+import com.baeldung.couchbase.IntegrationTest;
+import com.baeldung.couchbase.IntegrationTestConfig;
+import com.couchbase.client.java.Bucket;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { IntegrationTestConfig.class })
+@TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
+public class ClusterServiceTest extends IntegrationTest {
+
+ @Autowired
+ private ClusterService couchbaseService;
+
+ private Bucket defaultBucket;
+
+ @Test
+ public void whenOpenBucket_thenBucketIsNotNull() throws Exception {
+ defaultBucket = couchbaseService.openBucket("default", "");
+ assertNotNull(defaultBucket);
+ assertFalse(defaultBucket.isClosed());
+ defaultBucket.close();
+ }
+}