diff --git a/couchbase/.gitignore b/couchbase/.gitignore
new file mode 100644
index 0000000000..f6867e01bd
--- /dev/null
+++ b/couchbase/.gitignore
@@ -0,0 +1,6 @@
+# Created by .ignore support plugin (hsz.mobi)
+
+# IntelliJ project files
+.idea
+*.iml
+/target/
diff --git a/couchbase/README.md b/couchbase/README.md
new file mode 100644
index 0000000000..f124a0192c
--- /dev/null
+++ b/couchbase/README.md
@@ -0,0 +1,51 @@
+## Couchbase SDK Tutorial Project
+
+### Relevant Articles:
+- [Introduction to Couchbase SDK for Java](http://www.baeldung.com/java-couchbase-sdk)
+- [Using Couchbase in a Spring Application](http://www.baeldung.com/couchbase-sdk-spring)
+- [Asynchronous Batch Opereations in Couchbase](http://www.baeldung.com/async-batch-operations-in-couchbase)
+- [Querying Couchbase with MapReduce Views](http://www.baeldung.com/couchbase-query-mapreduce-view)
+
+### Overview
+This Maven project contains the Java code for the Couchbase entities and Spring services
+as described in the tutorials, as well as a unit/integration test
+for each service implementation.
+
+### Working with the Code
+The project was developed and tested using Java 7 and 8 in the Eclipse-based
+Spring Source Toolkit (STS) and therefore should run fine in any
+recent version of Eclipse or another IDE of your choice
+that supports Java 7 or later.
+
+### Building the Project
+You can also build the project using Maven outside of any IDE:
+```
+mvn clean install
+```
+
+### Package Organization
+Java classes for the intro tutorial are in the
+org.baeldung.couchbase.intro package.
+
+Java classes for the Spring service tutorial are in the
+org.baeldung.couchbase.spring package hierarchy.
+
+Java classes for the Asynchronous Couchbase tutorial are in the
+org.baeldung.couchbase.async package hierarchy.
+
+
+### Running the tests
+The test classes for the Spring service tutorial are:
+- org.baeldung.couchbase.spring.service.ClusterServiceTest
+- org.baeldung.couchbase.spring.person.PersonCrudServiceTest
+
+The test classes for the Asynchronous Couchbase tutorial are in the
+org.baeldung.couchbase.async package hierarchy:
+- org.baeldung.couchbase.async.service.ClusterServiceTest
+- org.baeldung.couchbase.async.person.PersonCrudServiceTest
+
+The test classes may be run as JUnit tests from your IDE
+or using the Maven command line:
+```
+mvn test
+```
diff --git a/couchbase/mvnw b/couchbase/mvnw
new file mode 100644
index 0000000000..a1ba1bf554
--- /dev/null
+++ b/couchbase/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/mvnw.cmd b/couchbase/mvnw.cmd
new file mode 100644
index 0000000000..2b934e89dd
--- /dev/null
+++ b/couchbase/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/pom.xml b/couchbase/pom.xml
new file mode 100644
index 0000000000..819c53b038
--- /dev/null
+++ b/couchbase/pom.xml
@@ -0,0 +1,82 @@
+
+
+ 4.0.0
+ com.baeldung
+ couchbase-sdk
+ 0.1-SNAPSHOT
+ jar
+ couchbase-sdk
+ Couchbase SDK Tutorials
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+
+ com.couchbase.client
+ java-client
+ ${couchbase.client.version}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson-version}
+
+
+
+
+ org.springframework
+ spring-context
+ ${spring-framework.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ org.springframework
+ spring-context-support
+ ${spring-framework.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+
+
+ org.springframework
+ spring-test
+ ${spring-framework.version}
+ test
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+ test
+
+
+
+
+ 1.8
+ UTF-8
+ 2.5.0
+ 4.3.5.RELEASE
+ 3.5
+ 2.9.1
+
+
+
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/CouchbaseEntity.java b/couchbase/src/main/java/com/baeldung/couchbase/async/CouchbaseEntity.java
new file mode 100644
index 0000000000..8f459e364f
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/CouchbaseEntity.java
@@ -0,0 +1,9 @@
+package com.baeldung.couchbase.async;
+
+public interface CouchbaseEntity {
+
+ String getId();
+
+ void setId(String id);
+
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/person/Person.java b/couchbase/src/main/java/com/baeldung/couchbase/async/person/Person.java
new file mode 100644
index 0000000000..f1135a32a2
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/person/Person.java
@@ -0,0 +1,90 @@
+package com.baeldung.couchbase.async.person;
+
+import com.baeldung.couchbase.async.CouchbaseEntity;
+
+public class Person implements CouchbaseEntity {
+
+ 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;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ 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/src/main/java/com/baeldung/couchbase/async/person/PersonCrudService.java b/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonCrudService.java
new file mode 100644
index 0000000000..407bc7ee1c
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonCrudService.java
@@ -0,0 +1,24 @@
+package com.baeldung.couchbase.async.person;
+
+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.baeldung.couchbase.async.service.AbstractCrudService;
+import com.baeldung.couchbase.async.service.BucketService;
+
+@Service
+public class PersonCrudService extends AbstractCrudService {
+
+ @Autowired
+ public PersonCrudService(@Qualifier("TutorialBucketService") BucketService bucketService, PersonDocumentConverter converter) {
+ super(bucketService, converter);
+ }
+
+ @PostConstruct
+ private void init() {
+ loadBucket();
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonDocumentConverter.java b/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonDocumentConverter.java
new file mode 100644
index 0000000000..0f08679ace
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/person/PersonDocumentConverter.java
@@ -0,0 +1,28 @@
+package com.baeldung.couchbase.async.person;
+
+import org.springframework.stereotype.Service;
+
+import com.baeldung.couchbase.async.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/src/main/java/com/baeldung/couchbase/async/person/RegistrationService.java b/couchbase/src/main/java/com/baeldung/couchbase/async/person/RegistrationService.java
new file mode 100644
index 0000000000..7cbc3625db
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/person/RegistrationService.java
@@ -0,0 +1,28 @@
+package com.baeldung.couchbase.async.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/src/main/java/com/baeldung/couchbase/async/service/AbstractBucketService.java b/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractBucketService.java
new file mode 100644
index 0000000000..1180ea00a6
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractBucketService.java
@@ -0,0 +1,27 @@
+package com.baeldung.couchbase.async.service;
+
+import com.couchbase.client.java.Bucket;
+
+public abstract class AbstractBucketService implements BucketService {
+
+ private ClusterService clusterService;
+
+ private Bucket bucket;
+
+ protected void openBucket() {
+ bucket = clusterService.openBucket(getBucketName(), getBucketPassword());
+ }
+
+ protected abstract String getBucketName();
+
+ protected abstract String getBucketPassword();
+
+ public AbstractBucketService(ClusterService clusterService) {
+ this.clusterService = clusterService;
+ }
+
+ @Override
+ public Bucket getBucket() {
+ return bucket;
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractCrudService.java b/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractCrudService.java
new file mode 100644
index 0000000000..089cc55d5d
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/service/AbstractCrudService.java
@@ -0,0 +1,142 @@
+package com.baeldung.couchbase.async.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.baeldung.couchbase.async.CouchbaseEntity;
+import com.couchbase.client.core.BackpressureException;
+import com.couchbase.client.core.time.Delay;
+import com.couchbase.client.java.AsyncBucket;
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.ReplicaMode;
+import com.couchbase.client.java.document.JsonDocument;
+import com.couchbase.client.java.util.retry.RetryBuilder;
+
+import rx.Observable;
+import rx.functions.Action1;
+import rx.functions.Func1;
+
+public abstract class AbstractCrudService implements CrudService {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractCrudService.class);
+
+ private BucketService bucketService;
+ private Bucket bucket;
+ private JsonDocumentConverter converter;
+
+ public AbstractCrudService(BucketService bucketService, JsonDocumentConverter converter) {
+ this.bucketService = bucketService;
+ this.converter = converter;
+ }
+
+ protected void loadBucket() {
+ bucket = bucketService.getBucket();
+ }
+
+ @Override
+ public void create(T t) {
+ if (t.getId() == null) {
+ t.setId(UUID.randomUUID().toString());
+ }
+ JsonDocument doc = converter.toDocument(t);
+ bucket.insert(doc);
+ }
+
+ @Override
+ public T read(String id) {
+ JsonDocument doc = bucket.get(id);
+ return (doc == null ? null : converter.fromDocument(doc));
+ }
+
+ @Override
+ public T readFromReplica(String id) {
+ List docs = bucket.getFromReplica(id, ReplicaMode.FIRST);
+ return (docs.isEmpty() ? null : converter.fromDocument(docs.get(0)));
+ }
+
+ @Override
+ public void update(T t) {
+ JsonDocument doc = converter.toDocument(t);
+ bucket.upsert(doc);
+ }
+
+ @Override
+ public void delete(String id) {
+ bucket.remove(id);
+ }
+
+ @Override
+ public List readBulk(Iterable ids) {
+ final AsyncBucket asyncBucket = bucket.async();
+ Observable asyncOperation = Observable.from(ids).flatMap(new Func1>() {
+ public Observable call(String key) {
+ return asyncBucket.get(key);
+ }
+ });
+
+ final List items = new ArrayList();
+ try {
+ asyncOperation.toBlocking().forEach(new Action1() {
+ public void call(JsonDocument doc) {
+ T item = converter.fromDocument(doc);
+ items.add(item);
+ }
+ });
+ } catch (Exception e) {
+ logger.error("Error during bulk get", e);
+ }
+
+ return items;
+ }
+
+ @Override
+ public void createBulk(Iterable items) {
+ final AsyncBucket asyncBucket = bucket.async();
+ Observable.from(items).flatMap(new Func1>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public Observable call(final T t) {
+ if (t.getId() == null) {
+ t.setId(UUID.randomUUID().toString());
+ }
+ JsonDocument doc = converter.toDocument(t);
+ return asyncBucket.insert(doc).retryWhen(RetryBuilder.anyOf(BackpressureException.class).delay(Delay.exponential(TimeUnit.MILLISECONDS, 100)).max(10).build());
+ }
+ }).last().toBlocking().single();
+ }
+
+ @Override
+ public void updateBulk(Iterable items) {
+ final AsyncBucket asyncBucket = bucket.async();
+ Observable.from(items).flatMap(new Func1>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public Observable call(final T t) {
+ JsonDocument doc = converter.toDocument(t);
+ return asyncBucket.upsert(doc).retryWhen(RetryBuilder.anyOf(BackpressureException.class).delay(Delay.exponential(TimeUnit.MILLISECONDS, 100)).max(10).build());
+ }
+ }).last().toBlocking().single();
+ }
+
+ @Override
+ public void deleteBulk(Iterable ids) {
+ final AsyncBucket asyncBucket = bucket.async();
+ Observable.from(ids).flatMap(new Func1>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public Observable call(String key) {
+ return asyncBucket.remove(key).retryWhen(RetryBuilder.anyOf(BackpressureException.class).delay(Delay.exponential(TimeUnit.MILLISECONDS, 100)).max(10).build());
+ }
+ }).last().toBlocking().single();
+ }
+
+ @Override
+ public boolean exists(String id) {
+ return bucket.exists(id);
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/BucketService.java b/couchbase/src/main/java/com/baeldung/couchbase/async/service/BucketService.java
new file mode 100644
index 0000000000..28470be99f
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/service/BucketService.java
@@ -0,0 +1,8 @@
+package com.baeldung.couchbase.async.service;
+
+import com.couchbase.client.java.Bucket;
+
+public interface BucketService {
+
+ Bucket getBucket();
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterService.java b/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterService.java
new file mode 100644
index 0000000000..7bf891244f
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterService.java
@@ -0,0 +1,8 @@
+package com.baeldung.couchbase.async.service;
+
+import com.couchbase.client.java.Bucket;
+
+public interface ClusterService {
+
+ Bucket openBucket(String name, String password);
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterServiceImpl.java b/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterServiceImpl.java
new file mode 100644
index 0000000000..e708922988
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/service/ClusterServiceImpl.java
@@ -0,0 +1,36 @@
+package com.baeldung.couchbase.async.service;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.stereotype.Service;
+
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.Cluster;
+import com.couchbase.client.java.CouchbaseCluster;
+import com.couchbase.client.java.env.CouchbaseEnvironment;
+import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
+
+@Service
+public class ClusterServiceImpl implements ClusterService {
+
+ 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);
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/CrudService.java b/couchbase/src/main/java/com/baeldung/couchbase/async/service/CrudService.java
new file mode 100644
index 0000000000..5bd0e52214
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/service/CrudService.java
@@ -0,0 +1,26 @@
+package com.baeldung.couchbase.async.service;
+
+import java.util.List;
+
+public interface CrudService {
+
+ void create(T t);
+
+ T read(String id);
+
+ T readFromReplica(String id);
+
+ void update(T t);
+
+ void delete(String id);
+
+ List readBulk(Iterable ids);
+
+ void createBulk(Iterable items);
+
+ void updateBulk(Iterable items);
+
+ void deleteBulk(Iterable ids);
+
+ boolean exists(String id);
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/JsonDocumentConverter.java b/couchbase/src/main/java/com/baeldung/couchbase/async/service/JsonDocumentConverter.java
new file mode 100644
index 0000000000..193e91016a
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/service/JsonDocumentConverter.java
@@ -0,0 +1,10 @@
+package com.baeldung.couchbase.async.service;
+
+import com.couchbase.client.java.document.JsonDocument;
+
+public interface JsonDocumentConverter {
+
+ JsonDocument toDocument(T t);
+
+ T fromDocument(JsonDocument doc);
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/async/service/TutorialBucketService.java b/couchbase/src/main/java/com/baeldung/couchbase/async/service/TutorialBucketService.java
new file mode 100644
index 0000000000..459585d995
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/async/service/TutorialBucketService.java
@@ -0,0 +1,32 @@
+package com.baeldung.couchbase.async.service;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+@Service
+@Qualifier("TutorialBucketService")
+public class TutorialBucketService extends AbstractBucketService {
+
+ @PostConstruct
+ void init() {
+ openBucket();
+ }
+
+ @Autowired
+ public TutorialBucketService(ClusterService clusterService) {
+ super(clusterService);
+ }
+
+ @Override
+ protected String getBucketName() {
+ return "baeldung-tutorial";
+ }
+
+ @Override
+ protected String getBucketPassword() {
+ return "";
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/intro/CodeSnippets.java b/couchbase/src/main/java/com/baeldung/couchbase/intro/CodeSnippets.java
new file mode 100644
index 0000000000..e7bddc6442
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/intro/CodeSnippets.java
@@ -0,0 +1,87 @@
+package com.baeldung.couchbase.intro;
+
+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/src/main/java/com/baeldung/couchbase/mapreduce/CouchbaseKeyGenerator.java b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/CouchbaseKeyGenerator.java
new file mode 100644
index 0000000000..9ac1bbb3f7
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/CouchbaseKeyGenerator.java
@@ -0,0 +1,6 @@
+package com.baeldung.couchbase.mapreduce;
+
+public interface CouchbaseKeyGenerator {
+
+ String generateKey(T t);
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/DuplicateKeyException.java b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/DuplicateKeyException.java
new file mode 100644
index 0000000000..78baaa155c
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/DuplicateKeyException.java
@@ -0,0 +1,10 @@
+package com.baeldung.couchbase.mapreduce;
+
+@SuppressWarnings("serial")
+public class DuplicateKeyException extends Exception {
+
+ public DuplicateKeyException(String s) {
+ super(s);
+ }
+
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/RandomUUIDGenerator.java b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/RandomUUIDGenerator.java
new file mode 100644
index 0000000000..9baf4a4f43
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/RandomUUIDGenerator.java
@@ -0,0 +1,11 @@
+package com.baeldung.couchbase.mapreduce;
+
+import java.util.UUID;
+
+public class RandomUUIDGenerator implements CouchbaseKeyGenerator {
+
+ @Override
+ public String generateKey(T t) {
+ return UUID.randomUUID().toString();
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGrade.java b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGrade.java
new file mode 100644
index 0000000000..846aba716a
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGrade.java
@@ -0,0 +1,50 @@
+package com.baeldung.couchbase.mapreduce;
+
+public class StudentGrade {
+
+ private String name;
+ private String course;
+ private Integer grade;
+ private Integer hours;
+
+ public StudentGrade() { }
+
+ public StudentGrade(String name, String course, Integer grade, Integer hours) {
+ this.name = name;
+ this.course = course;
+ this.grade = grade;
+ this.hours = hours;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getCourse() {
+ return course;
+ }
+
+ public void setCourse(String course) {
+ this.course = course;
+ }
+
+ public Integer getGrade() {
+ return grade;
+ }
+
+ public void setGrade(Integer grade) {
+ this.grade = grade;
+ }
+
+ public Integer getHours() {
+ return hours;
+ }
+
+ public void setHours(Integer hours) {
+ this.hours = hours;
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeKeyGenerator.java b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeKeyGenerator.java
new file mode 100644
index 0000000000..680e37ba57
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeKeyGenerator.java
@@ -0,0 +1,9 @@
+package com.baeldung.couchbase.mapreduce;
+
+public class StudentGradeKeyGenerator implements CouchbaseKeyGenerator {
+
+ @Override
+ public String generateKey(StudentGrade g) {
+ return g.getName() + ":" + g.getCourse();
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeQueryBuilder.java b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeQueryBuilder.java
new file mode 100644
index 0000000000..37bb03645a
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeQueryBuilder.java
@@ -0,0 +1,70 @@
+package com.baeldung.couchbase.mapreduce;
+
+import com.couchbase.client.deps.com.fasterxml.jackson.databind.ObjectMapper;
+import com.couchbase.client.java.document.json.JsonArray;
+import com.couchbase.client.java.view.ViewQuery;
+
+public class StudentGradeQueryBuilder {
+
+ final ObjectMapper om = new ObjectMapper();
+
+ public ViewQuery findAll() {
+ return ViewQuery.from("studentGrades", "findByCourse");
+ }
+
+ public ViewQuery findByCourse(String course) {
+ return ViewQuery.from("studentGrades", "findByCourse")
+ .key(course);
+ }
+
+ public ViewQuery findByCourses(String... courses) {
+ return ViewQuery.from("studentGrades", "findByCourse")
+ .keys(JsonArray.from(courses));
+ }
+
+ public ViewQuery findByGradeInRange(int lower, int upper, boolean inclusiveEnd) {
+ return ViewQuery.from("studentGrades", "findByGrade")
+ .startKey(lower)
+ .endKey(upper)
+ .inclusiveEnd(inclusiveEnd);
+ }
+
+ public ViewQuery findByGradeLessThan(int upper) {
+ return ViewQuery.from("studentGrades", "findByGrade")
+ .endKey(upper)
+ .inclusiveEnd(false);
+ }
+
+ public ViewQuery findByGradeGreaterThan(int lower) {
+ return ViewQuery.from("studentGrades", "findByGrade")
+ .startKey(lower);
+ }
+
+ public ViewQuery findByCourseAndGradeInRange(String course, int minGrade, int maxGrade, boolean inclusiveEnd) {
+ return ViewQuery.from("studentGrades", "findByCourseAndGrade")
+ .startKey(JsonArray.from(course, minGrade))
+ .endKey(JsonArray.from(course, maxGrade))
+ .inclusiveEnd(inclusiveEnd);
+ }
+
+ public ViewQuery findTopGradesByCourse(String course, int limit) {
+ return ViewQuery.from("studentGrades", "findByCourseAndGrade")
+ .startKey(JsonArray.from(course, 100))
+ .endKey(JsonArray.from(course, 0))
+ .inclusiveEnd(true)
+ .descending()
+ .limit(limit);
+ }
+
+ public ViewQuery countStudentsByCourse() {
+ return ViewQuery.from("studentGrades", "countStudentsByCourse")
+ .reduce()
+ .groupLevel(1);
+ }
+
+ public ViewQuery sumCreditsByStudent() {
+ return ViewQuery.from("studentGrades", "sumCreditsByStudent")
+ .reduce()
+ .groupLevel(1);
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeService.java b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeService.java
new file mode 100644
index 0000000000..2d2c63f699
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/mapreduce/StudentGradeService.java
@@ -0,0 +1,169 @@
+package com.baeldung.couchbase.mapreduce;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.couchbase.client.deps.com.fasterxml.jackson.databind.ObjectMapper;
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.CouchbaseCluster;
+import com.couchbase.client.java.document.JsonDocument;
+import com.couchbase.client.java.document.json.JsonArray;
+import com.couchbase.client.java.document.json.JsonObject;
+import com.couchbase.client.java.view.ViewQuery;
+import com.couchbase.client.java.view.ViewResult;
+import com.couchbase.client.java.view.ViewRow;
+
+public class StudentGradeService {
+
+ final CouchbaseKeyGenerator keyGenerator;
+ final CouchbaseCluster cluster;
+ final Bucket bucket;
+ final ObjectMapper om = new ObjectMapper();
+ final StudentGradeQueryBuilder queryBuilder;
+
+ public StudentGradeService(CouchbaseKeyGenerator keyGenerator) {
+ this.keyGenerator = keyGenerator;
+ this.queryBuilder = new StudentGradeQueryBuilder();
+ cluster = CouchbaseCluster.create("127.0.0.1");
+ bucket = cluster.openBucket("baeldung-tutorial");
+ }
+
+ public String insert(StudentGrade studentGrade) throws DuplicateKeyException {
+ String id = keyGenerator.generateKey(studentGrade);
+ if(bucket.exists(id)) {
+ throw new DuplicateKeyException("document already exists with key " + id);
+ }
+ JsonObject content = JsonObject.empty()
+ .put("type", "StudentGrade")
+ .put("name", studentGrade.getName())
+ .put("course", studentGrade.getCourse())
+ .put("grade", studentGrade.getGrade())
+ .put("hours", studentGrade.getHours());
+ JsonDocument doc = JsonDocument.create(id, content);
+ bucket.insert(doc);
+ return id;
+ }
+
+ public List findAll() {
+ ViewQuery query = queryBuilder.findAll();
+ ViewResult result = bucket.query(query);
+ return extractDocuments(result);
+ }
+
+ private List extractDocuments(ViewResult result) {
+ List docs = new ArrayList<>();
+ for(ViewRow row : result.allRows()) {
+ JsonDocument doc = row.document();
+ docs.add(doc);
+ }
+ return docs;
+ }
+
+ public List findByCourse(String course) {
+ ViewQuery query = queryBuilder.findByCourse(course);
+ ViewResult result = bucket.query(query);
+ return extractDocuments(result);
+ }
+
+ public List findByCourses(String... courses) {
+ ViewQuery query = queryBuilder.findByCourses(courses);
+ ViewResult result = bucket.query(query);
+ return extractDocuments(result);
+ }
+
+ public List findByGradeInRange(int lower, int upper, boolean inclusiveEnd) {
+ ViewQuery query = queryBuilder.findByGradeInRange(lower, upper, inclusiveEnd);
+ ViewResult result = bucket.query(query);
+ return extractDocuments(result);
+ }
+
+ public List findByGradeLessThan(int upper) {
+ ViewQuery query = queryBuilder.findByGradeLessThan(upper);
+ ViewResult result = bucket.query(query);
+ return extractDocuments(result);
+ }
+
+ public List findByGradeGreaterThan(int lower) {
+ ViewQuery query = queryBuilder.findByGradeGreaterThan(lower);
+ ViewResult result = bucket.query(query);
+ return extractDocuments(result);
+ }
+
+ public List findByCourseAndGradeInRange(String course, int minGrade, int maxGrade, boolean inclusiveEnd) {
+ ViewQuery query = queryBuilder.findByCourseAndGradeInRange(course, minGrade, maxGrade, inclusiveEnd);
+ ViewResult result = bucket.query(query);
+ return extractDocuments(result);
+ }
+
+ public List findTopGradesByCourse(String course, int limit) {
+ ViewQuery query = queryBuilder.findTopGradesByCourse(course, limit);
+ ViewResult result = bucket.query(query);
+ return extractDocuments(result);
+ }
+
+ public Map countStudentsByCourse() {
+ ViewQuery query = ViewQuery.from("studentGrades", "countStudentsByCourse")
+ .reduce()
+ .groupLevel(1);
+ ViewResult result = bucket.query(query);
+
+ Map numStudentsByCourse = new HashMap<>();
+ for(ViewRow row : result.allRows()) {
+ JsonArray keyArray = (JsonArray) row.key();
+ String course = keyArray.getString(0);
+ long count = Long.valueOf(row.value().toString());
+ numStudentsByCourse.put(course, count);
+ }
+
+ return numStudentsByCourse;
+ }
+
+ public Map sumCreditHoursByStudent() {
+ ViewQuery query = ViewQuery.from("studentGrades", "sumHoursByStudent")
+ .reduce()
+ .groupLevel(1);
+ ViewResult result = bucket.query(query);
+
+ Map creditHoursByStudent = new HashMap<>();
+ for(ViewRow row : result.allRows()) {
+ String course = (String) row.key();
+ long sum = Long.valueOf(row.value().toString());
+ creditHoursByStudent.put(course, sum);
+ }
+
+ return creditHoursByStudent;
+ }
+
+ public Map sumGradePointsByStudent() {
+ ViewQuery query = ViewQuery.from("studentGrades", "sumGradePointsByStudent")
+ .reduce()
+ .groupLevel(1);
+ ViewResult result = bucket.query(query);
+
+ Map gradePointsByStudent = new HashMap<>();
+ for(ViewRow row : result.allRows()) {
+ String course = (String) row.key();
+ long sum = Long.valueOf(row.value().toString());
+ gradePointsByStudent.put(course, sum);
+ }
+
+ return gradePointsByStudent;
+ }
+
+ public Map calculateGpaByStudent() {
+ Map creditHoursByStudent = sumCreditHoursByStudent();
+ Map gradePointsByStudent = sumGradePointsByStudent();
+
+ Map result = new HashMap<>();
+ for(Entry creditHoursEntry : creditHoursByStudent.entrySet()) {
+ String name = creditHoursEntry.getKey();
+ long totalHours = creditHoursEntry.getValue();
+ long totalGradePoints = gradePointsByStudent.get(name);
+ result.put(name, ((float) totalGradePoints / totalHours));
+ }
+ return result;
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/n1ql/BucketFactory.java b/couchbase/src/main/java/com/baeldung/couchbase/n1ql/BucketFactory.java
new file mode 100644
index 0000000000..98fbe17e60
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/n1ql/BucketFactory.java
@@ -0,0 +1,26 @@
+package com.baeldung.couchbase.n1ql;
+
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.Cluster;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class BucketFactory {
+
+ @Autowired
+ private Cluster cluster;
+
+ private Bucket travelSampleBucket;
+ private Bucket testBucket;
+
+ public Bucket getTravelSampleBucket() {
+ return (travelSampleBucket != null) ?
+ travelSampleBucket : cluster.openBucket("travel-sample");
+ }
+
+ public Bucket getTestBucket() {
+ return (testBucket != null) ?
+ testBucket : cluster.openBucket("test");
+ }
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/n1ql/CodeSnippets.java b/couchbase/src/main/java/com/baeldung/couchbase/n1ql/CodeSnippets.java
new file mode 100644
index 0000000000..45067911cb
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/n1ql/CodeSnippets.java
@@ -0,0 +1,34 @@
+package com.baeldung.couchbase.n1ql;
+
+import com.couchbase.client.java.query.N1qlQueryResult;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+public class CodeSnippets {
+
+ private static ObjectMapper objectMapper = new ObjectMapper();
+
+ private static final Logger logger = Logger.getLogger(CodeSnippets.class.getName());
+
+ public static List extractJsonResult(N1qlQueryResult result) {
+ return result.allRows().stream()
+ .map(row -> {
+ try {
+ return objectMapper.readTree(row.value().toString());
+ }catch (IOException e) {
+ logger.log(Level.WARNING, e.getLocalizedMessage());
+ return null;
+ }
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/person/Person.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/person/Person.java
new file mode 100644
index 0000000000..403b7c8d3b
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/person/Person.java
@@ -0,0 +1,86 @@
+package com.baeldung.couchbase.spring.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/src/main/java/com/baeldung/couchbase/spring/person/PersonCrudService.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonCrudService.java
new file mode 100644
index 0000000000..163f6417ca
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonCrudService.java
@@ -0,0 +1,69 @@
+package com.baeldung.couchbase.spring.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.spring.service.CrudService;
+import com.baeldung.couchbase.spring.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/src/main/java/com/baeldung/couchbase/spring/person/PersonDocumentConverter.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonDocumentConverter.java
new file mode 100644
index 0000000000..71108d16dd
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/person/PersonDocumentConverter.java
@@ -0,0 +1,28 @@
+package com.baeldung.couchbase.spring.person;
+
+import org.springframework.stereotype.Service;
+
+import com.baeldung.couchbase.spring.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/src/main/java/com/baeldung/couchbase/spring/person/RegistrationService.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/person/RegistrationService.java
new file mode 100644
index 0000000000..cad3bdd5a5
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/person/RegistrationService.java
@@ -0,0 +1,28 @@
+package com.baeldung.couchbase.spring.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/src/main/java/com/baeldung/couchbase/spring/service/BucketService.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/BucketService.java
new file mode 100644
index 0000000000..1ea9c72114
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/BucketService.java
@@ -0,0 +1,9 @@
+package com.baeldung.couchbase.spring.service;
+
+import com.couchbase.client.java.Bucket;
+
+public interface BucketService {
+
+ Bucket getBucket();
+
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterService.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterService.java
new file mode 100644
index 0000000000..da7a10141f
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterService.java
@@ -0,0 +1,17 @@
+package com.baeldung.couchbase.spring.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/src/main/java/com/baeldung/couchbase/spring/service/ClusterServiceImpl.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterServiceImpl.java
new file mode 100644
index 0000000000..1cceb11ccc
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/ClusterServiceImpl.java
@@ -0,0 +1,81 @@
+package com.baeldung.couchbase.spring.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/src/main/java/com/baeldung/couchbase/spring/service/CrudService.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/CrudService.java
new file mode 100644
index 0000000000..5b12af7003
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/CrudService.java
@@ -0,0 +1,16 @@
+package com.baeldung.couchbase.spring.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/src/main/java/com/baeldung/couchbase/spring/service/JsonDocumentConverter.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/JsonDocumentConverter.java
new file mode 100644
index 0000000000..f63bb8691b
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/JsonDocumentConverter.java
@@ -0,0 +1,10 @@
+package com.baeldung.couchbase.spring.service;
+
+import com.couchbase.client.java.document.JsonDocument;
+
+public interface JsonDocumentConverter {
+
+ JsonDocument toDocument(T t);
+
+ T fromDocument(JsonDocument doc);
+}
diff --git a/couchbase/src/main/java/com/baeldung/couchbase/spring/service/TutorialBucketService.java b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/TutorialBucketService.java
new file mode 100644
index 0000000000..b91c131912
--- /dev/null
+++ b/couchbase/src/main/java/com/baeldung/couchbase/spring/service/TutorialBucketService.java
@@ -0,0 +1,29 @@
+package com.baeldung.couchbase.spring.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/src/main/resources/application.properties b/couchbase/src/main/resources/application.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/couchbase/src/main/resources/logback.xml b/couchbase/src/main/resources/logback.xml
new file mode 100644
index 0000000000..ec0dc2469a
--- /dev/null
+++ b/couchbase/src/main/resources/logback.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ web - %date [%thread] %-5level %logger{36} - %message%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTest.java b/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTest.java
new file mode 100644
index 0000000000..3079fc928a
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTest.java
@@ -0,0 +1,13 @@
+package com.baeldung.couchbase.async;
+
+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 = { AsyncIntegrationTestConfig.class })
+@TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
+public abstract class AsyncIntegrationTest {
+}
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTestConfig.java b/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTestConfig.java
new file mode 100644
index 0000000000..efc3e9957f
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/async/AsyncIntegrationTestConfig.java
@@ -0,0 +1,9 @@
+package com.baeldung.couchbase.async;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ComponentScan(basePackages = { "com.baeldung.couchbase.async" })
+public class AsyncIntegrationTestConfig {
+}
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceIntegrationTest.java b/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceIntegrationTest.java
new file mode 100644
index 0000000000..565aaed5da
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/async/person/PersonCrudServiceIntegrationTest.java
@@ -0,0 +1,216 @@
+package com.baeldung.couchbase.async.person;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+import com.baeldung.couchbase.async.AsyncIntegrationTest;
+import com.baeldung.couchbase.async.person.Person;
+import com.baeldung.couchbase.async.person.PersonCrudService;
+import com.baeldung.couchbase.async.person.PersonDocumentConverter;
+import com.baeldung.couchbase.async.service.BucketService;
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.document.JsonDocument;
+
+public class PersonCrudServiceIntegrationTest extends AsyncIntegrationTest {
+
+ @Autowired
+ private PersonCrudService personService;
+
+ @Autowired
+ @Qualifier("TutorialBucketService")
+ private BucketService bucketService;
+
+ @Autowired
+ private PersonDocumentConverter converter;
+
+ private Bucket bucket;
+
+ @PostConstruct
+ private void init() {
+ bucket = bucketService.getBucket();
+ }
+
+ @Test
+ public final void givenRandomPerson_whenCreate_thenPersonPersisted() {
+ // create person
+ Person person = randomPerson();
+ personService.create(person);
+
+ // check results
+ assertNotNull(person.getId());
+ assertNotNull(bucket.get(person.getId()));
+
+ // cleanup
+ bucket.remove(person.getId());
+ }
+
+ @Test
+ public final void givenId_whenRead_thenReturnsPerson() {
+ // create and insert person document
+ String id = insertRandomPersonDocument().id();
+
+ // read person and check results
+ assertNotNull(personService.read(id));
+
+ // cleanup
+ bucket.remove(id);
+ }
+
+ @Test
+ public final void givenNewHometown_whenUpdate_thenNewHometownPersisted() {
+ // create and insert person document
+ JsonDocument doc = insertRandomPersonDocument();
+
+ // update person
+ Person expected = converter.fromDocument(doc);
+ String updatedHomeTown = RandomStringUtils.randomAlphabetic(12);
+ expected.setHomeTown(updatedHomeTown);
+ personService.update(expected);
+
+ // check results
+ JsonDocument actual = bucket.get(expected.getId());
+ assertNotNull(actual);
+ assertNotNull(actual.content());
+ assertEquals(expected.getHomeTown(), actual.content().getString("homeTown"));
+
+ // cleanup
+ bucket.remove(expected.getId());
+ }
+
+ @Test
+ public final void givenRandomPerson_whenDelete_thenPersonNotInBucket() {
+ // create and insert person document
+ String id = insertRandomPersonDocument().id();
+
+ // delete person and check results
+ personService.delete(id);
+ assertNull(bucket.get(id));
+ }
+
+ @Test
+ public final void givenIds_whenReadBulk_thenReturnsOnlyPersonsWithMatchingIds() {
+ List ids = new ArrayList<>();
+
+ // add some person documents
+ for (int i = 0; i < 5; i++) {
+ ids.add(insertRandomPersonDocument().id());
+ }
+
+ // perform bulk read
+ List persons = personService.readBulk(ids);
+
+ // check results
+ for (Person person : persons) {
+ assertTrue(ids.contains(person.getId()));
+ }
+
+ // cleanup
+ for (String id : ids) {
+ bucket.remove(id);
+ }
+ }
+
+ @Test
+ public final void givenPersons_whenInsertBulk_thenPersonsAreInserted() {
+
+ // create some persons
+ List persons = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ persons.add(randomPerson());
+ }
+
+ // perform bulk insert
+ personService.createBulk(persons);
+
+ // check results
+ for (Person person : persons) {
+ assertNotNull(bucket.get(person.getId()));
+ }
+
+ // cleanup
+ for (Person person : persons) {
+ bucket.remove(person.getId());
+ }
+ }
+
+ @Test
+ public final void givenPersons_whenUpdateBulk_thenPersonsAreUpdated() {
+
+ List ids = new ArrayList<>();
+
+ // add some person documents
+ for (int i = 0; i < 5; i++) {
+ ids.add(insertRandomPersonDocument().id());
+ }
+
+ // load persons from Couchbase
+ List persons = new ArrayList<>();
+ for (String id : ids) {
+ persons.add(converter.fromDocument(bucket.get(id)));
+ }
+
+ // modify persons
+ for (Person person : persons) {
+ person.setHomeTown(RandomStringUtils.randomAlphabetic(10));
+ }
+
+ // perform bulk update
+ personService.updateBulk(persons);
+
+ // check results
+ for (Person person : persons) {
+ JsonDocument doc = bucket.get(person.getId());
+ assertEquals(person.getName(), doc.content().getString("name"));
+ assertEquals(person.getHomeTown(), doc.content().getString("homeTown"));
+ }
+
+ // cleanup
+ for (String id : ids) {
+ bucket.remove(id);
+ }
+ }
+
+ @Test
+ public void givenIds_whenDeleteBulk_thenPersonsAreDeleted() {
+
+ List ids = new ArrayList<>();
+
+ // add some person documents
+ for (int i = 0; i < 5; i++) {
+ ids.add(insertRandomPersonDocument().id());
+ }
+
+ // perform bulk delete
+ personService.deleteBulk(ids);
+
+ // check results
+ for (String id : ids) {
+ assertNull(bucket.get(id));
+ }
+
+ }
+
+ private JsonDocument insertRandomPersonDocument() {
+ Person expected = randomPersonWithId();
+ JsonDocument doc = converter.toDocument(expected);
+ return bucket.insert(doc);
+ }
+
+ private Person randomPerson() {
+ return Person.Builder.newInstance().name(RandomStringUtils.randomAlphabetic(10)).homeTown(RandomStringUtils.randomAlphabetic(10)).build();
+ }
+
+ private Person randomPersonWithId() {
+ return Person.Builder.newInstance().id(UUID.randomUUID().toString()).name(RandomStringUtils.randomAlphabetic(10)).homeTown(RandomStringUtils.randomAlphabetic(10)).build();
+ }
+}
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/async/service/ClusterServiceIntegrationTest.java b/couchbase/src/test/java/com/baeldung/couchbase/async/service/ClusterServiceIntegrationTest.java
new file mode 100644
index 0000000000..d0db5d37a3
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/async/service/ClusterServiceIntegrationTest.java
@@ -0,0 +1,35 @@
+package com.baeldung.couchbase.async.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.async.AsyncIntegrationTest;
+import com.baeldung.couchbase.async.AsyncIntegrationTestConfig;
+import com.baeldung.couchbase.async.service.ClusterService;
+import com.couchbase.client.java.Bucket;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { AsyncIntegrationTestConfig.class })
+@TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
+public class ClusterServiceIntegrationTest extends AsyncIntegrationTest {
+
+ @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();
+ }
+}
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/mapreduce/StudentGradeServiceIntegrationTest.java b/couchbase/src/test/java/com/baeldung/couchbase/mapreduce/StudentGradeServiceIntegrationTest.java
new file mode 100644
index 0000000000..00d462e32a
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/mapreduce/StudentGradeServiceIntegrationTest.java
@@ -0,0 +1,150 @@
+package com.baeldung.couchbase.mapreduce;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.couchbase.client.java.document.JsonDocument;
+import com.couchbase.client.java.view.ViewResult;
+import com.couchbase.client.java.view.ViewRow;
+
+public class StudentGradeServiceIntegrationTest {
+ private static final Logger logger = LoggerFactory.getLogger(StudentGradeServiceIntegrationTest.class);
+
+ static StudentGradeService studentGradeService;
+ static Set gradeIds = new HashSet<>();
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ studentGradeService = new StudentGradeService(new StudentGradeKeyGenerator());
+ insertStudentGrade(new StudentGrade("John Doe", "History", 80, 3));
+ insertStudentGrade(new StudentGrade("Jane Doe", "History", 89, 3));
+ insertStudentGrade(new StudentGrade("Bob Smith", "History", 90, 3));
+ insertStudentGrade(new StudentGrade("Mary Jones", "History", 92, 3));
+ insertStudentGrade(new StudentGrade("Jane Doe", "Math", 59, 3));
+ insertStudentGrade(new StudentGrade("Bob Smith", "Math", 91, 3));
+ insertStudentGrade(new StudentGrade("Mary Jones", "Math", 86, 3));
+ insertStudentGrade(new StudentGrade("John Doe", "Science", 85, 4));
+ insertStudentGrade(new StudentGrade("Bob Smith", "Science", 97, 4));
+ insertStudentGrade(new StudentGrade("Mary Jones", "Science", 84, 4));
+ }
+
+ private static void insertStudentGrade(StudentGrade studentGrade) {
+ try {
+ String id = studentGradeService.insert(studentGrade);
+ gradeIds.add(id);
+ } catch (DuplicateKeyException e) {
+ }
+ }
+
+ @Test
+ public final void whenFindAll_thenSuccess() {
+ List docs = studentGradeService.findAll();
+ printDocuments(docs);
+ }
+
+ @Test
+ public final void whenFindByCourse_thenSuccess() {
+ List docs = studentGradeService.findByCourse("History");
+ printDocuments(docs);
+ }
+
+ @Test
+ public final void whenFindByCourses_thenSuccess() {
+ List docs = studentGradeService.findByCourses("History", "Science");
+ printDocuments(docs);
+ }
+
+ @Test
+ public final void whenFindByGradeInRange_thenSuccess() {
+ List docs = studentGradeService.findByGradeInRange(80, 89, true);
+ printDocuments(docs);
+ }
+
+ @Test
+ public final void whenFindByGradeLessThan_thenSuccess() {
+ List docs = studentGradeService.findByGradeLessThan(60);
+ printDocuments(docs);
+ }
+
+ @Test
+ public final void whenFindByGradeGreaterThan_thenSuccess() {
+ List docs = studentGradeService.findByGradeGreaterThan(90);
+ printDocuments(docs);
+ }
+
+ @Test
+ public final void whenFindByCourseAndGradeInRange_thenSuccess() {
+ List docs = studentGradeService.findByCourseAndGradeInRange("Math", 80, 89, true);
+ printDocuments(docs);
+ }
+
+ @Test
+ public final void whenFindTopGradesByCourse_thenSuccess() {
+ List docs = studentGradeService.findTopGradesByCourse("Science", 2);
+ printDocuments(docs);
+ }
+
+ @Test
+ public final void whenCountStudentsByCourse_thenSuccess() {
+ Map map = studentGradeService.countStudentsByCourse();
+ printMap(map);
+ }
+
+ @Test
+ public final void whenSumCreditHoursByStudent_thenSuccess() {
+ Map map = studentGradeService.sumCreditHoursByStudent();
+ printMap(map);
+ }
+
+ @Test
+ public final void whenSumGradePointsByStudent_thenSuccess() {
+ Map map = studentGradeService.sumGradePointsByStudent();
+ printMap(map);
+ }
+
+ @Test
+ public final void whenCalculateGpaByStudent_thenSuccess() {
+ Map map = studentGradeService.calculateGpaByStudent();
+ printGpaMap(map);
+ }
+
+ private void printMap(Map map) {
+ for(Map.Entry entry : map.entrySet()) {
+ logger.info(entry.getKey() + "=" + entry.getValue());
+ }
+ }
+
+ private void printGpaMap(Map map) {
+ for(Map.Entry entry : map.entrySet()) {
+ logger.info(entry.getKey() + "=" + entry.getValue());
+ }
+ }
+
+ private void printDocuments(List docs) {
+ for(JsonDocument doc : docs) {
+ String key = doc.id();
+ logger.info(key + " = " + doc.content().toString());
+ }
+ }
+
+ private void printViewResultDocuments(ViewResult result) {
+ for(ViewRow row : result.allRows()) {
+ JsonDocument doc = row.document();
+ String key = doc.id();
+ logger.info(key + "=" + doc.content().toString());
+ }
+ }
+
+ private void printViewResultRows(ViewResult result) {
+ for(ViewRow row : result.allRows()) {
+ logger.info(row.toString());
+ }
+ }
+}
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/n1ql/IntegrationTestConfig.java b/couchbase/src/test/java/com/baeldung/couchbase/n1ql/IntegrationTestConfig.java
new file mode 100644
index 0000000000..ef7e31b224
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/n1ql/IntegrationTestConfig.java
@@ -0,0 +1,26 @@
+package com.baeldung.couchbase.n1ql;
+
+import com.couchbase.client.java.Cluster;
+import com.couchbase.client.java.CouchbaseCluster;
+import com.couchbase.client.java.env.CouchbaseEnvironment;
+import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.TimeUnit;
+
+@Configuration
+@ComponentScan(basePackages = { "com.baeldung.couchbase.n1ql" })
+public class IntegrationTestConfig {
+
+ @Bean
+ public Cluster cluster() {
+ CouchbaseEnvironment env = DefaultCouchbaseEnvironment.builder()
+ .connectTimeout(60000)
+ .build();
+ return CouchbaseCluster.create(env, "127.0.0.1");
+ }
+
+
+}
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/n1ql/N1QLIntegrationTest.java b/couchbase/src/test/java/com/baeldung/couchbase/n1ql/N1QLIntegrationTest.java
new file mode 100644
index 0000000000..8112d7d222
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/n1ql/N1QLIntegrationTest.java
@@ -0,0 +1,248 @@
+package com.baeldung.couchbase.n1ql;
+
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.Cluster;
+import com.couchbase.client.java.document.JsonDocument;
+import com.couchbase.client.java.document.json.JsonArray;
+import com.couchbase.client.java.document.json.JsonObject;
+import com.couchbase.client.java.query.N1qlQuery;
+import com.couchbase.client.java.query.N1qlQueryResult;
+import com.couchbase.client.java.query.N1qlQueryRow;
+import com.couchbase.client.java.query.Statement;
+import com.fasterxml.jackson.databind.JsonNode;
+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.junit4.SpringJUnit4ClassRunner;
+import rx.Observable;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import static com.baeldung.couchbase.n1ql.CodeSnippets.extractJsonResult;
+import static com.couchbase.client.java.query.Select.select;
+import static com.couchbase.client.java.query.dsl.Expression.*;
+import static org.junit.Assert.assertNotNull;
+
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { IntegrationTestConfig.class })
+public class N1QLIntegrationTest {
+
+
+ @Autowired
+ private Cluster cluster;
+
+ @Autowired
+ private BucketFactory bucketFactory;
+
+ @Test
+ public void givenAutowiredCluster_whenNotNull_thenNotNull() {
+ assertNotNull(cluster);
+ }
+
+ @Test
+ public void givenBucketFactory_whenGetTestBucket_thenNotNull() {
+ assertNotNull(bucketFactory.getTestBucket());
+ }
+
+ @Test
+ public void givenBucketFactory_whenGetTravelSampleBucket_thenNotNull() {
+ assertNotNull(bucketFactory.getTravelSampleBucket());
+ }
+
+ @Test
+ public void givenDocument_whenInsert_thenResult() {
+ Bucket bucket = bucketFactory.getTestBucket();
+ JsonObject personObj = JsonObject.create()
+ .put("name", "John")
+ .put("email", "john@doe.com")
+ .put("interests", JsonArray.from("Java", "Nigerian Jollof"));
+
+ String id = UUID.randomUUID().toString();
+ JsonDocument doc = JsonDocument.create(id, personObj);
+ bucket.insert(doc);
+ assertNotNull(bucket.get(id));
+ }
+
+ @Test
+ public void whenBasicSelectQuery_thenGetQueryResult() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ N1qlQueryResult result
+ = bucket.query(N1qlQuery.simple("SELECT * FROM test"));
+
+ result.forEach(System.out::println);
+
+ System.out.println("result count: " + result.info().resultCount());
+ System.out.println("error count: " + result.info().errorCount());
+ }
+
+ @Test
+ public void givenSelectStatement_whenQuery_thenResult() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ String query = "SELECT name FROM `travel-sample` " +
+ "WHERE type = 'airport' LIMIT 100";
+ N1qlQueryResult result1 = bucket.query(N1qlQuery.simple(query));
+
+ System.out.println("Result Count " + result1.info().resultCount());
+
+ N1qlQueryRow row = result1.allRows().get(0);
+ JsonObject rowJson = row.value();
+ System.out.println("Name in First Row " + rowJson.get("name"));
+
+ }
+
+ @Test
+ public void givenSelectStatement2_whenQuery_thenResult() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ JsonObject pVal = JsonObject.create().put("type", "airport");
+ String query = "SELECT * FROM `travel-sample` " +
+ "WHERE type = $type LIMIT 100";
+ N1qlQueryResult r2 = bucket.query(N1qlQuery.parameterized(query, pVal));
+
+ System.out.println(r2.allRows());
+
+ List list = extractJsonResult(r2);
+ System.out.println(
+ list.get(0).get("travel-sample").get("airportname").asText());
+ }
+
+ @Test
+ public void givenSelectDSL_whenQuery_thenResult() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ Statement statement = select("*")
+ .from(i("travel-sample"))
+ .where(x("type").eq(s("airport")))
+ .limit(100);
+ N1qlQueryResult r3 = bucket.query(N1qlQuery.simple(statement));
+
+ List list2 = extractJsonResult(r3);
+ System.out.println("First Airport Name: " + list2.get(0).get("travel-sample").get("airportname").asText());
+
+ }
+
+ @Test
+ public void givenSelectStatementWithOperators_whenQuery_thenResult() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ String query2 = "SELECT t.city, " +
+ "t.airportname || \" (\" || t.faa || \")\" AS portname_faa " +
+ "FROM `travel-sample` t " +
+ "WHERE t.type=\"airport\"" +
+ "AND t.country LIKE '%States'" +
+ "AND t.geo.lat >= 70 " +
+ "LIMIT 2";
+ N1qlQueryResult r4 = bucket.query(N1qlQuery.simple(query2));
+ List list3 = extractJsonResult(r4);
+ System.out.println("First Doc : " + list3.get(0));
+ }
+
+ @Test
+ public void givenSelectStatementWithDSL2_whenQuery_thenResult() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ Statement st2 = select(
+ x("t.city, t.airportname")
+ .concat(s(" (")).concat(x("t.faa")).concat(s(")")).as("portname_faa"))
+ .from(i("travel-sample").as("t"))
+ .where( x("t.type").eq(s("airport"))
+ .and(x("t.country").like(s("%States")))
+ .and(x("t.geo.lat").gte(70)))
+ .limit(2);
+ N1qlQueryResult r5 = bucket.query(N1qlQuery.simple(st2));
+ List list5 = extractJsonResult(r5);
+ System.out.println("First Doc : " + list5.get(0));
+ System.out.println("Query from Statement2: " + st2.toString());
+ }
+
+ @Test
+ public void givenInsertStatement_whenQuery_thenUpdate() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ String query = "INSERT INTO `travel-sample` (KEY, VALUE) " +
+ " VALUES(" +
+ "\"cust1293\", " +
+ "{\"id\":\"1293\",\"name\":\"Sample Airline\", \"type\":\"airline\"})" +
+ " RETURNING META().id as docid, *";
+ N1qlQueryResult r1 = bucket.query(N1qlQuery.simple(query));
+ r1.forEach(System.out::println);
+ }
+
+ @Test
+ public void givenDocument_whenInsert_thenResults() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ JsonObject ob = JsonObject.create()
+ .put("id", "1293")
+ .put("name", "Sample Airline")
+ .put("type", "airline");
+ bucket.insert(JsonDocument.create("cust1295", ob));
+ }
+
+ @Test
+ public void givenDocuments_whenBatchInsert_thenResult() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+
+ List documents = IntStream.rangeClosed(0,10)
+ .mapToObj( i -> {
+ JsonObject content = JsonObject.create()
+ .put("id", i)
+ .put("type", "airline")
+ .put("name", "Sample Airline " + i);
+ return JsonDocument.create("cust_" + i, content);
+ })
+ .collect(Collectors.toList());
+
+ List r5 = Observable
+ .from(documents)
+ .flatMap(doc -> bucket.async().insert(doc))
+ .toList()
+ .last()
+ .toBlocking()
+ .single();
+
+ r5.forEach(System.out::println);
+ }
+
+ @Test
+ public void givenUpdateStatement_whenQuery_thenUpdate() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ String query2 = "UPDATE `travel-sample` USE KEYS \"cust_1\" " +
+ "SET name=\"Sample Airline Updated\" RETURNING name";
+ N1qlQueryResult result = bucket.query(N1qlQuery.simple(query2));
+ result.forEach(System.out::println);
+ }
+
+ @Test
+ public void givenDocument_whenUpsert_thenUpdate() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ JsonObject o2 = JsonObject.create()
+ .put("name", "Sample Airline Updated");
+ bucket.upsert(JsonDocument.create("cust_1", o2));
+ }
+
+ @Test
+ public void givenUnestUpdateStatement_whenQuery_thenResult() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ String query3 = "UPDATE `travel-sample` USE KEYS \"cust_2\" " +
+ "UNSET name RETURNING *";
+ N1qlQueryResult result1 = bucket.query(N1qlQuery.simple(query3));
+ result1.forEach(System.out::println);
+ }
+
+ @Test
+ public void givenDeleteStatement_whenQuery_thenDelete() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ String query4 = "DELETE FROM `travel-sample` USE KEYS \"cust_50\"";
+ N1qlQueryResult result4 = bucket.query(N1qlQuery.simple(query4));
+ }
+
+ @Test
+ public void givenDeleteStatement2_whenQuery_thenDelete() {
+ Bucket bucket = bucketFactory.getTravelSampleBucket();
+ String query5 = "DELETE FROM `travel-sample` WHERE id = 0 RETURNING *";
+ N1qlQueryResult result5 = bucket.query(N1qlQuery.simple(query5));
+ }
+
+
+}
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTest.java b/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTest.java
new file mode 100644
index 0000000000..9c0b0a50c1
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTest.java
@@ -0,0 +1,13 @@
+package com.baeldung.couchbase.spring;
+
+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/src/test/java/com/baeldung/couchbase/spring/IntegrationTestConfig.java b/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTestConfig.java
new file mode 100644
index 0000000000..d814b31a07
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/spring/IntegrationTestConfig.java
@@ -0,0 +1,9 @@
+package com.baeldung.couchbase.spring;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ComponentScan(basePackages = { "com.baeldung.couchbase.spring" })
+public class IntegrationTestConfig {
+}
diff --git a/couchbase/src/test/java/com/baeldung/couchbase/spring/person/PersonCrudServiceIntegrationTest.java b/couchbase/src/test/java/com/baeldung/couchbase/spring/person/PersonCrudServiceIntegrationTest.java
new file mode 100644
index 0000000000..ec15be1acc
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/spring/person/PersonCrudServiceIntegrationTest.java
@@ -0,0 +1,75 @@
+package com.baeldung.couchbase.spring.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.spring.IntegrationTest;
+
+public class PersonCrudServiceIntegrationTest 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/src/test/java/com/baeldung/couchbase/spring/service/ClusterServiceIntegrationTest.java b/couchbase/src/test/java/com/baeldung/couchbase/spring/service/ClusterServiceIntegrationTest.java
new file mode 100644
index 0000000000..ead247dfbc
--- /dev/null
+++ b/couchbase/src/test/java/com/baeldung/couchbase/spring/service/ClusterServiceIntegrationTest.java
@@ -0,0 +1,34 @@
+package com.baeldung.couchbase.spring.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.spring.IntegrationTest;
+import com.baeldung.couchbase.spring.IntegrationTestConfig;
+import com.couchbase.client.java.Bucket;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { IntegrationTestConfig.class })
+@TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
+public class ClusterServiceIntegrationTest 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();
+ }
+}
diff --git a/couchbase/src/test/resources/logback.xml b/couchbase/src/test/resources/logback.xml
new file mode 100644
index 0000000000..ec0dc2469a
--- /dev/null
+++ b/couchbase/src/test/resources/logback.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ web - %date [%thread] %-5level %logger{36} - %message%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file