This commit is contained in:
yungez 2017-09-18 14:54:30 +08:00
Родитель aa5767c7b6
Коммит de8b0b1cee
65 изменённых файлов: 4599 добавлений и 10 удалений

21
.gitignore поставляемый
Просмотреть файл

@ -1,5 +1,6 @@
# Compiled class file
*.class
.classpath
# Log file
*.log
@ -20,3 +21,23 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# IntelliJ
.idea
*.iml
.project
.settings
# Eclipse
.metadata
.checkstyle
.fbExcludeFilterFile
#Spring
.springBeans
.factorypath
# Maven
target
/bin/
!.mvn/wrapper/maven-wrapper.jar

163
README.md
Просмотреть файл

@ -1,14 +1,157 @@
## Spring Data for Azure Cosmos DB DocumentDB API
[Azure Cosmos DB](https://docs.microsoft.com/en-us/azure/cosmos-db/introduction) is a globally-distributed database service that allows developers to work with data using a variety of standard APIs, such as DocumentDB, MongoDB, Graph, and Table APIs. Azure DocumentDB Spring Data provides initial Spring Data support for [Azure Cosmos DB Document API](https://docs.microsoft.com/en-us/azure/cosmos-db/documentdb-introduction) based on Spring Data framework, the other 3 APIs are not supported in this package. Key functionalities supported so far include save, delete and find. More features will coming soon.
# Contributing
## Sample Code
Please refer to [sample project here](./samplecode).
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.microsoft.com.
## Feature List
- Spring Data CRUDRepository basic CRUD functionality
- save
- findAll
- findOne by Id
- deleteAll
- delete by Id
- delete entity
- Spring Data [@Id](https://github.com/spring-projects/spring-data-commons/blob/db62390de90c93a78743c97cc2cc9ccd964994a5/src/main/java/org/springframework/data/annotation/Id.java) annotation.
There're 2 ways to map a field in domain class to `id` of Azure Cosmos DB document.
- annotate a field in domain class with `@Id`, this field will be mapped to document `id` in Cosmos DB.
- set name of this field to `id`, this field will be mapped to document `id` in Cosmos DB.
- Custom collection Name.
By default, collection name will be class name of user domain class. To customize it, add annoataion `@Document(collection="myCustomCollectionName")` to your domain class, that's all.
- Supports [Azure Cosmos DB partition](https://docs.microsoft.com/en-us/azure/cosmos-db/partition-data). To specify a field of your domain class to be partition key field, just annotate it with `@PartitionKey`. When you do CRUD operation, pls specify your partition value. For more sample on partition CRUD, pls refer to [test here](./test/java/com/microsoft/azure/spring/data/documentdb/repository/AddressRepositoryIT.java)
## Quick Start
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
### Add the dependency
`spring-data-azure-cosmosdb-documentdb` is published on Maven Central Repository.
If you are using Maven, add the following dependency.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
```xml
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>spring-data-azure-cosmosdb-documentdb</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
```
### Setup Configuration
Setup Azure Cosmos DB DocumentDB configuration class. Enabling Spring Data Azure DocumentDB repository support is auto-configured.
```
@Configuration
public class AppConfiguration extends AbstractDocumentDbConfiguration {
@Value("${azure.documentdb.uri}")
private String uri;
@Value("${azure.documentdb.key}")
private String key;
@Value("${azure.documentdb.database}")
private String dbName;
public DocumentClient documentClient() {
return new DocumentClient(uri, key, ConnectionPolicy.GetDefault(), ConsistencyLevel.Session);
}
public String getDatabase() {
return dbName;
}
}
```
By default, `@EnableDocumentDbRepositories` will scan the current package for any interfaces that extend one of Spring Data's repository interfaces. Using it to annotate your Configuration class to scan a different root package by type if your project layout has multiple projects and it's not finding your repositories.
```
@Configuration
@EnableDocumentDbRepositories(basePackageClass=UserRepository.class)
public class AppConfiguration extends AbstractDocumentDbConfiguration {
// configuration code
}
```
### Define en entity
Define a simple entity as Document in DocumentDB.
```
@Document(collection = "mycollection")
public class User {
private String id;
private String firstName;
@PartitionKey
private String lastName;
... // setters and getters
public User(String id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("User: %s %s, %s", firstName, lastName);
}
}
```
`id` field will be used as document id in Azure DocumentDB. If you want use another field like `emailAddress` as document `id`, just annotate that field with `@Id` annotation.
Annotation `@Document(collection="mycollection")` is used to specify collection name of your document in Azure Cosmos DB.
Annotation `@PartitionKey` on lastName field is used to specify this field be partition key in Azure Cosmos DB.
```
@Document(collection = "mycollection")
public class User {
@Id
private String emailAddress;
...
}
```
### Create repositories
Extends DocumentDbRepository interface, which provides Spring Data repository support.
```
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.DocumentDbRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends DocumentDbRepository<User, String> {
}
```
So far DocumentDbRepository provides basic save, delete and find operations. More operations will be supported later.
### Create an Application class
Here create an application class with all the components
```
@SpringBootApplication
public class SampleApplication implements CommandLineRunner {
@Autowired
private UserRepository repository;
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
public void run(String... var1) throws Exception {
final User testUser = new User("testId", "testFirstName", "testLastName");
repository.deleteAll();
repository.save(testUser);
// to find by Id, please specify partition key value if collection is partitioned
final User result = repository.findOne(testUser.getId(), testUser.getLastName);
// if emailAddress is mapped to id, then
// final User result = respository.findOne(testUser.getEmailAddress(), testUser.getLastName());
}
}
```
Autowired UserRepository interface, then can do save, delete and find operations. Azure Cosmos DB DocumentDB Spring Data uses the DocumentTemplate to execute the queries behind *find*, *save* methods. You can use the template yourself for more complex queries.
## Further info
If you'd like to save effort of configuration, you could directly use Azure Cosmos DB DocumentDB API Spring boot starter at [here](../azure-documentdb-spring-boot-starter).

37
build.xml Normal file
Просмотреть файл

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<project name="test resource prepration and cleanup">
<target name="setup">
<echo message="setup test resource"/>
<exec osfamily="windows" executable="cmd.exe">
<arg value="/c"/>
<arg value=".\src\libs\setup.bat"/>
<arg value="${azure.test.resourcegroup}"/>
<arg value="${azure.test.dbname}"/>
<redirector outputproperty="documentdb.key"/>
</exec>
<exec osfamily="unix" executable="bash">
<arg value="./src/libs/setup.sh"/>
<arg value="${azure.test.resourcegroup}"/>
<arg value="${azure.test.dbname}"/>
<redirector outputproperty="documentdb.key"/>
</exec>
<propertyfile file="./src/test/resources/application.properties">
<entry key="documentdb.key" value="${documentdb.key}"/>
<entry key="documentdb.uri" value="https://${azure.test.dbname}.documents.azure.com:443"/>
</propertyfile>
</target>
<target name="cleanup">
<echo message="cleanup test resource"/>
<exec osfamily="windows" executable="cmd.exe">
<arg value="/c"/>
<arg value=".\src\libs\cleanup.bat"/>
<arg value="${azure.test.resourcegroup}"/>
<arg value="${azure.test.dbname}"/>
</exec>
<exec osfamily="unix" executable="bash">
<arg value="./src/libs/cleanup.sh"/>
<arg value="${azure.test.resourcegroup}"/>
<arg value="${azure.test.dbname}"/>
</exec>
</target>
</project>

296
config/checkstyle.xml Normal file
Просмотреть файл

@ -0,0 +1,296 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<!-- This is a checkstyle configuration file. For descriptions of
what the following rules do, please see the checkstyle configuration
page at http://checkstyle.sourceforge.net/config.html -->
<module name="Checker">
<module name="SuppressionFilter">
</module>
<module name="Header">
<property name="header"
value="/**\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See LICENSE in the project root for\n * license information.\n */"/>
<property name="fileExtensions" value="java"/>
</module>
<module name="FileTabCharacter">
<!-- Checks that there are no tab characters in the file.
-->
</module>
<module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf"/>
</module>
<module name="RegexpSingleline">
<!-- Checks that FIXME is not used in comments. TODO is preferred.
-->
<property name="format" value="((//.*)|(\*.*))FIXME"/>
<property name="message"
value='TODO is preferred to FIXME. e.g. "TODO(johndoe): Refactor when v2 is released."'/>
</module>
<module name="RegexpSingleline">
<!-- Checks that TODOs are named. (Actually, just that they are followed
by an open paren.)
-->
<property name="format" value="((//.*)|(\*.*))TODO [^(]"/>
<property name="message"
value='All TODOs should be named. e.g. "TODO (johndoe): Refactor when v2 is released."'/>
</module>
<!-- All Java AST specific tests live under TreeWalker module. -->
<module name="TreeWalker">
<!--
IMPORT CHECKS
-->
<module name="RedundantImport">
<!-- Checks for redundant import statements. -->
<property name="severity" value="error"/>
</module>
<!--
NAMING CHECKS
-->
<!-- Item 38 - Adhere to generally accepted naming conventions -->
<module name="PackageName">
<!-- Validates identifiers for package names against the
supplied expression. -->
<!-- Here the default checkstyle rule restricts package name parts to
seven characters, this is not in line with common practice at Google.
-->
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
<property name="severity" value="warning"/>
</module>
<module name="TypeNameCheck">
<!-- Validates static, final fields against the
expression "^[A-Z][a-zA-Z0-9]*$". -->
<metadata name="altname" value="TypeName"/>
<property name="severity" value="warning"/>
</module>
<module name="ConstantNameCheck">
<!-- Validates non-private, static, final fields against the supplied
public/package final fields "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$". -->
<metadata name="altname" value="ConstantName"/>
<property name="applyToPublic" value="true"/>
<property name="applyToProtected" value="true"/>
<property name="applyToPackage" value="true"/>
<property name="applyToPrivate" value="false"/>
<property name="format" value="^([A-Z][A-Z0-9]*(_[A-Z0-9]+)*|FLAG_.*)$"/>
<message key="name.invalidPattern"
value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)."/>
<property name="severity" value="warning"/>
</module>
<module name="StaticVariableNameCheck">
<!-- Validates static, non-final fields against the supplied
expression "^[a-z][a-zA-Z0-9]*_?$". -->
<metadata name="altname" value="StaticVariableName"/>
<property name="applyToPublic" value="true"/>
<property name="applyToProtected" value="true"/>
<property name="applyToPackage" value="true"/>
<property name="applyToPrivate" value="true"/>
<property name="format" value="^[a-z][a-zA-Z0-9]*_?$"/>
<property name="severity" value="warning"/>
</module>
<module name="MemberNameCheck">
<!-- Validates non-static members against the supplied expression. -->
<metadata name="altname" value="MemberName"/>
<property name="applyToPublic" value="true"/>
<property name="applyToProtected" value="true"/>
<property name="applyToPackage" value="true"/>
<property name="applyToPrivate" value="true"/>
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
<property name="severity" value="warning"/>
</module>
<module name="MethodNameCheck">
<!-- Validates identifiers for method names. -->
<metadata name="altname" value="MethodName"/>
<property name="format" value="^[a-z][a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$"/>
<property name="severity" value="warning"/>
</module>
<module name="ParameterName">
<!-- Validates identifiers for method parameters against the
expression "^[a-z][a-zA-Z0-9]*$". -->
<property name="severity" value="warning"/>
</module>
<module name="LocalFinalVariableName">
<!-- Validates identifiers for local final variables against the
expression "^[a-z][a-zA-Z0-9]*$". -->
<property name="severity" value="warning"/>
</module>
<module name="LocalVariableName">
<!-- Validates identifiers for local variables against the
expression "^[a-z][a-zA-Z0-9]*$". -->
<property name="severity" value="warning"/>
</module>
<module name="FinalLocalVariable">
<!-- Checks that local variables that never have their values changed are declared final. -->
<property name="tokens" value="VARIABLE_DEF"/>
<property name="validateEnhancedForLoopVariable" value="true"/>
</module>
<!--
LENGTH and CODING CHECKS
-->
<module name="LineLength">
<!-- Checks if a line is too long. -->
<property name="max" value="120"/>
<property name="severity" value="error"/>
<!--
The default ignore pattern exempts the following elements:
- import statements
- long URLs inside comments
-->
<property name="ignorePattern"
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
default="^(package .*;\s*)|(import .*;\s*)|( *\* *https?://.*)$"/>
</module>
<module name="LeftCurly">
<!-- Checks for placement of the left curly brace ('{'). -->
<property name="severity" value="warning"/>
</module>
<module name="RightCurly">
<!-- Checks right curlies on CATCH, ELSE, and TRY blocks are on
the same line. e.g., the following example is fine:
<pre>
if {
...
} else
</pre>
-->
<!-- This next example is not fine:
<pre>
if {
...
}
else
</pre>
-->
<property name="option" value="same"/>
<property name="severity" value="warning"/>
</module>
<!-- Checks for braces around if and else blocks -->
<module name="NeedBraces">
<property name="severity" value="warning"/>
<property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
</module>
<module name="UpperEll">
<!-- Checks that long constants are defined with an upper ell.-->
<property name="severity" value="error"/>
</module>
<module name="FallThrough">
<!-- Warn about falling through to the next case statement. Similar to
javac -Xlint:fallthrough, but the check is suppressed if a single-line comment
on the last non-blank line preceding the fallen-into case contains 'fall through' (or
some other variants which we don't publicized to promote consistency).
-->
<property name="reliefPattern"
value="fall through|Fall through|fallthru|Fallthru|falls through|Falls through|fallthrough|Fallthrough|No break|NO break|no break|continue on"/>
<property name="severity" value="error"/>
</module>
<!--
MODIFIERS CHECKS
-->
<module name="ModifierOrder">
<!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
8.4.3. The prescribed order is:
public, protected, private, abstract, static, final, transient, volatile,
synchronized, native, strictfp
-->
</module>
<!--
WHITESPACE CHECKS
-->
<module name="WhitespaceAround">
<!-- Checks that various tokens are surrounded by whitespace.
This includes most binary operators and keywords followed
by regular or curly braces.
-->
<property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
EQUAL, GE, GT, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN"/>
<property name="severity" value="error"/>
</module>
<module name="WhitespaceAfter">
<!-- Checks that commas, semicolons and typecasts are followed by
whitespace.
-->
<property name="tokens" value="COMMA, SEMI, TYPECAST"/>
</module>
<module name="NoWhitespaceAfter">
<!-- Checks that there is no whitespace after various unary operators.
Linebreaks are allowed.
-->
<property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS,
UNARY_PLUS"/>
<property name="allowLineBreaks" value="true"/>
<property name="severity" value="error"/>
</module>
<module name="NoWhitespaceBefore">
<!-- Checks that there is no whitespace before various unary operators.
Linebreaks are allowed.
-->
<property name="tokens" value="SEMI, DOT, POST_DEC, POST_INC"/>
<property name="allowLineBreaks" value="true"/>
<property name="severity" value="error"/>
</module>
<module name="ParenPad">
<!-- Checks that there is no whitespace before close parens or after
open parens.
-->
<property name="severity" value="warning"/>
</module>
</module>
</module>

Просмотреть файл

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<Class name="com.microsoft.azure.spring.data.cosmosdb.documentdb.common.GetHashMac"/>
<Bug pattern="NP_NONNULL_PARAM_VIOLATION"/>
<Bug pattern="Unwritten field"/>
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON"/>
<Bug pattern="SIC_INNER_SHOULD_BE_STATIC_NEEDS_THIS"/>
<Bug pattern="UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD"/>
</FindBugsFilter>

225
mvnw поставляемый Normal file
Просмотреть файл

@ -0,0 +1,225 @@
#!/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
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
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
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
echo $MAVEN_PROJECTBASEDIR
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# 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"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
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} $MAVEN_CONFIG "$@"

143
mvnw.cmd поставляемый Normal file
Просмотреть файл

@ -0,0 +1,143 @@
@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
@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="%MAVEN_PROJECTBASEDIR%\.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_CONFIG% %*
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%

353
pom.xml Normal file
Просмотреть файл

@ -0,0 +1,353 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.azure</groupId>
<artifactId>spring-data-azure-cosmosdb-documentdb</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>Spring Data for Azure Cosmos DB DocumentDB API</name>
<description>Spring Data for Azure Cosmos DB DocumentDB API</description>
<url>https://github.com/Microsoft/spring-data-azure-cosmosdb-documentdb</url>
<licenses>
<license>
<name>MIT</name>
<url>https://github.com/Microsoft/spring-data-azure-cosmosdb-documentdb/blob/master/LICENSE</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>yungez</id>
<name>Yunge Zhu</name>
<email>yungez@microsoft.com</email>
</developer>
</developers>
<organization>
<name>Microsoft</name>
<url>https://www.microsoft.com</url>
</organization>
<scm>
<connection>scm:git:git://github.com/Microsoft/spring-data-azure-cosmosdb-documentdb.git</connection>
<developerConnection>scm:git:ssh://github.com:Microsoft/spring-data-azure-cosmosdb-documentdb.git
</developerConnection>
<url>https://github.com/Microsoft/spring-data-azure-cosmosdb-documentdb/tree/master</url>
</scm>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<azure.documentdb.version>1.13.0</azure.documentdb.version>
<spring.boot.dependencies.version>1.5.4.RELEASE</spring.boot.dependencies.version>
<mockito.core.version>2.8.9</mockito.core.version>
<azure.test.resourcegroup>documentdbtest</azure.test.resourcegroup>
<azure.test.dbname>springdocdbtestdb</azure.test.dbname>
<skip.integration.tests>true</skip.integration.tests>
<test.on.azure>false</test.on.azure>
<test.on.emualator>false</test.on.emualator>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>com.microsoft.azure</groupId>-->
<!--<artifactId>azure-spring-common</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-documentdb</artifactId>
<version>${azure.documentdb.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<configuration>
<show>private</show>
<failOnError>false</failOnError>
<sourceFileExcludes>
<exclude>
com/microsoft/azure/spring/data/documentdb/core/mapping/BasicDocumentDbPersistentProperty.java
</exclude>
</sourceFileExcludes>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<additionalparam>${javadoc.opts}</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.17</version>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<configuration>
<configLocation>${project.basedir}/config/checkstyle.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<linkXRef>false</linkXRef>
</configuration>
<inherited>true</inherited>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<xmlOutput>true</xmlOutput>
<findbugsXmlOutputDirectory>${project.build.directory}/findbugs
</findbugsXmlOutputDirectory>
<excludeFilterFile>${project.basedir}/config/findbugs-exclude.xml</excludeFilterFile>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<formats>
<format>html</format>
<format>xml</format>
</formats>
<check>
<haltOnFailure>true</haltOnFailure>
<branchRate>60</branchRate>
<totalBranchRate>60</totalBranchRate>
</check>
<instrumentation>
<excludes>
<exclude>com/microsoft/azure/**/GetHashMac.class</exclude>
<exclude>com/microsoft/azure/**/Constants.class</exclude>
</excludes>
</instrumentation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19</version>
<configuration>
<systemPropertiesFile>src/test/resources/application.properties</systemPropertiesFile>
<skipITs>${skip.integration.tests}</skipITs>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>setup</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target if="${test.on.azure}">
<ant antfile="build.xml" target="setup">
</ant>
</target>
</configuration>
</execution>
<execution>
<id>cleanup</id>
<phase>post-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target if="${test.on.azure}">
<ant antfile="build.xml" target="cleanup"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>dev</build.profile.id>
<skip.integration.tests>true</skip.integration.tests>
<test.on.azure>false</test.on.azure>
<test.on.emulator>false</test.on.emulator>
</properties>
</profile>
<profile>
<id>integration-test-azure</id>
<properties>
<build.profile.id>integration-test-azure</build.profile.id>
<skip.integration.tests>false</skip.integration.tests>
<test.on.azure>true</test.on.azure>
<test.on.emulator>false</test.on.emulator>
</properties>
</profile>
<profile>
<id>integration-test-emulator</id>
<properties>
<build.profile.id>integration-test-emulator</build.profile.id>
<skip.integration.tests>false</skip.integration.tests>
<test.on.azure>false</test.on.azure>
<test.on.emulator>true</test.on.emulator>
</properties>
</profile>
<profile>
<id>doclint-java8-disable</id>
<activation>
<jdk>[1.8,)</jdk>
</activation>
<properties>
<javadoc.opts>-Xdoclint:none</javadoc.opts>
</properties>
</profile>
</profiles>
</project>

132
samplecode/pom.xml Normal file
Просмотреть файл

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>spring-data-azure-cosmodb-documentdb-sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Spring Data Azure Cosmos DB DocumentDB Sample</name>
<description>Sample project for Spring Data Azure Cosmos DB DocumentDB</description>
<url>https://github.com/Microsoft/spring-data-azure-cosmosdb-documentdb</url>
<licenses>
<license>
<name>MIT</name>
<url>https://github.com/Microsoft/spring-data-azure-cosmosdb-documentdb/blob/master/LICENSE</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<id>yungez</id>
<name>yunge zhu</name>
<email>yungez@microsoft.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/Microsoft/spring-data-azure-cosmosdb-documentdb.git</connection>
<developerConnection>scm:git:ssh://github.com:Microsoft/spring-data-azure-cosmosdb-documentdb.git</developerConnection>
<url>https://github.com/Microsoft/spring-data-azure-cosmosdb-documentdb/tree/master</url>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.data.azure.cosmosdb.documentdb.version>0.1.0-SNAPSHOT</spring.data.azure.cosmosdb.documentdb.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>spring-data-azure-cosmosdb-documentdb</artifactId>
<version>${spring.data.azure.cosmosdb.documentdb.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.17</version>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<configuration>
<configLocation>${project.basedir}/../config/checkstyle.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<failOnViolation>true</failOnViolation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<linkXRef>false</linkXRef>
</configuration>
<inherited>true</inherited>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<xmlOutput>true</xmlOutput>
<findbugsXmlOutputDirectory>${project.build.directory}/findbugs
</findbugsXmlOutputDirectory>
<excludeFilterFile>${project.basedir}/../config/findbugs-exclude.xml</excludeFilterFile>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Просмотреть файл

@ -0,0 +1,37 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.sample;
import com.microsoft.azure.documentdb.ConnectionPolicy;
import com.microsoft.azure.documentdb.ConsistencyLevel;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.config.AbstractDocumentDbConfiguration;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.config.EnableDocumentDbRepositories;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableDocumentDbRepositories
public class AppConfiguration extends AbstractDocumentDbConfiguration {
@Value("${azure.documentdb.uri}")
private String uri;
@Value("${azure.documentdb.key}")
private String key;
@Value("${azure.documentdb.database}")
private String dbName;
public DocumentClient documentClient() {
return new DocumentClient(uri, key, ConnectionPolicy.GetDefault(), ConsistencyLevel.Session);
}
public String getDatabase() {
return dbName;
}
}

Просмотреть файл

@ -0,0 +1,44 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.sample;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.util.Assert;
@SpringBootApplication
public class SampleApplication implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(SampleApplication.class);
@Autowired
private UserRepository repository;
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
public void run(String... var1) throws Exception {
final User testUser = new User("test@test.com", "testFirstName", "testLastName");
repository.deleteAll();
repository.save(testUser);
final User result = repository.findOne(testUser.getEmailAddress(), testUser.getLastName());
Assert.state(result.getFirstName().equals(testUser.getFirstName()), "query result firstName doesn't match!");
Assert.state(result.getLastName().equals(testUser.getLastName()), "query result lastName doesn't match!");
LOGGER.info("findOne in User collection get result: {}", result.toString());
System.out.println("findOne in User collection get result:" + result.toString());
}
}

Просмотреть файл

@ -0,0 +1,58 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.sample;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.Document;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.PartitionKey;
import org.springframework.data.annotation.Id;
@Document(collection = "mycollection")
public class User {
@Id
private String emailAddress;
private String firstName;
@PartitionKey
private String lastName;
public User(String emailAddress, String firstName, String lastName) {
this.emailAddress = emailAddress;
this.firstName = firstName;
this.lastName = lastName;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("%s: %s %s", emailAddress, firstName, lastName);
}
}

Просмотреть файл

@ -0,0 +1,15 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.sample;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.DocumentDbRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends DocumentDbRepository<User, String> {
}

Просмотреть файл

@ -0,0 +1,3 @@
azure.documentdb.uri=put-your-documentdb-uri-here
azure.documentdb.key=put-your-documentdb-key-here
azure.documentdb.database=put-your-documentdb-databasename-here

31
src/libs/cleanup.bat Normal file
Просмотреть файл

@ -0,0 +1,31 @@
@echo off
rem cleanup test resource
set clientId=%CLIENT_ID%
set clientKey=%CLIENT_KEY%
set tenantId=%TENANT_ID%
if "%clientId%" == "" (
goto :end
)
if "%clientKey%" == "" (
goto :end
)
if "%tenantId%" == "" (
goto :end
)
set resourcegroup=%1
set dbname=%2
if "%resourcegroup" == "" (
goto :end
)
if "%dbname" == "" (
goto :end
)
call az login --service-principal -u %clientId% -p %clientKey% --tenant %tenantId% >> tmp.txt
call az cosmosdb delete --name %dbname% --resource-group %resourcegroup%
:end

17
src/libs/cleanup.sh Normal file
Просмотреть файл

@ -0,0 +1,17 @@
# cleanup test resources
#!/bin/bash
resourcegroup=$1
dbname=$2
if [ "$CLIENT_ID" == "" ]; then
exit 0
fi
if [ "$CLIENT_KEY" == "" ]; then
exit 0
fi
if [ "$TENANT_ID" == "" ]; then
exit 0
fi
az login --service-principal -u $CLIENT_ID -p $CLIENT_KEY --tenant $TENANT_ID >> tmp.txt
az cosmosdb delete --name $dbname --resource-group $resourcegroup

41
src/libs/setup.bat Normal file
Просмотреть файл

@ -0,0 +1,41 @@
@echo off
set clientId=%CLIENT_ID%
set clientKey=%CLIENT_KEY%
set tenantId=%TENANT_ID%
if "%clientId%" == "" (
goto :noSetup
)
if "%clientKey%" == "" (
goto :noSetup
)
if "%tenantId%" == "" (
goto :noSetup
)
set resourcegroup=%1
set dbname=%2
if "%resourcegroup" == "" (
goto :noSetup
)
if "%dbname" == "" (
goto :noSetup
)
call az login --service-principal -u %clientId% -p %clientKey% --tenant %tenantId% >> null
set createcmd='az cosmosdb create --name %dbname% --resource-group %resourcegroup% --kind GlobalDocumentDB --query documentEndpoint'
for /f "tokens=*" %%a in (%createcmd%) do (set documentdburi=%%a)
set listcmd='az cosmosdb list-keys --name %dbname% --resource-group %resourcegroup% --query primaryMasterKey'
for /f "tokens=*" %%a in (%listcmd%) do (set documentdbkey=%%a)
echo %documentdbkey%
goto :end
:noSetup
echo not to setup test resources
exit 0
:end

20
src/libs/setup.sh Normal file
Просмотреть файл

@ -0,0 +1,20 @@
# setup test resources
#!/bin/bash
resourcegroup=$1
dbname=$2
if [ -z "$CLIENT_ID" ]; then
exit 0
fi
if [ -z "$CLIENT_KEY" ]; then
exit 0
fi
if [ -z "$TENANT_ID" ]; then
exit 0
fi
az login --service-principal -u $CLIENT_ID -p $CLIENT_KEY --tenant $TENANT_ID >> tmp.txt
documentDbUri=$(az cosmosdb create --name $dbname --resource-group $resourcegroup --kind GlobalDocumentDB --query documentEndpoint)
documentDbKey=$(az cosmosdb list-keys --name $dbname --resource-group $resourcegroup --query primaryMasterKey)
echo $documentDbKey

Просмотреть файл

@ -0,0 +1,47 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb;
import com.microsoft.azure.documentdb.ConnectionPolicy;
import com.microsoft.azure.documentdb.ConsistencyLevel;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.common.GetHashMac;
import org.springframework.util.Assert;
public class DocumentDbFactory {
private static final String USER_AGENT_SUFFIX = "spring-data/0.1.8-SNAPSHOT";
private DocumentClient documentClient;
public DocumentDbFactory(String host, String key) {
this(host, key, true);
}
public DocumentDbFactory(String host, String key, boolean isBiEnabled) {
Assert.hasText(host, "host must not be empty!");
Assert.hasText(key, "key must not be empty!");
final ConnectionPolicy policy = ConnectionPolicy.GetDefault();
String userAgent = ";" + USER_AGENT_SUFFIX;
if (isBiEnabled && GetHashMac.getHashMac() != null) {
userAgent += ";" + GetHashMac.getHashMac();
}
policy.setUserAgentSuffix(userAgent);
documentClient = new DocumentClient(host, key, policy, ConsistencyLevel.Session);
}
public DocumentDbFactory(DocumentClient client) {
this.documentClient = client;
}
public DocumentClient getDocumentClient() {
return documentClient;
}
}

Просмотреть файл

@ -0,0 +1,115 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
/*
* Disclaimer:
* This class is copied from https://github.com/Microsoft/azure-tools-for-java/ with minor modification (fixing
* static analysis error).
* Location in the repo: /Utils/azuretools-core/src/com/microsoft/azuretools/azurecommons/util/GetHashMac.java
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.common;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GetHashMac {
public static final String MAC_REGEX = "([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}";
public static final String MAC_REGEX_ZERO = "([0]{2}[:-]){5}[0]{2}";
public static final String HASHED_MAC_REGEX = "[0-9a-f]{64}";
private GetHashMac() {
super();
}
public static boolean isValidHashMacFormat(String hashMac) {
if (hashMac == null || hashMac.isEmpty()) {
return false;
}
final Pattern hashedMacPattern = Pattern.compile(HASHED_MAC_REGEX);
final Matcher matcher = hashedMacPattern.matcher(hashMac);
return matcher.matches();
}
public static String getHashMac() {
final String rawMac = getRawMac();
if (rawMac == null || rawMac.isEmpty()) {
return null;
}
final Pattern pattern = Pattern.compile(MAC_REGEX);
final Pattern patternZero = Pattern.compile(MAC_REGEX_ZERO);
final Matcher matcher = pattern.matcher(rawMac);
String mac = "";
while (matcher.find()) {
mac = matcher.group(0);
if (!patternZero.matcher(mac).matches()) {
break;
}
}
return hash(mac);
}
private static String getRawMac() {
final StringBuilder ret = new StringBuilder();
final String os = System.getProperty("os.name");
String[] command = {"ifconfig", "-a"};
if (os != null && !os.isEmpty() && os.toLowerCase().startsWith("win")) {
command = new String[]{"getmac"};
}
try {
final ProcessBuilder builder = new ProcessBuilder(command);
final Process process = builder.start();
try (final InputStream inputStream = process.getInputStream();
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
final BufferedReader br = new BufferedReader(inputStreamReader)) {
String tmp;
while ((tmp = br.readLine()) != null) {
ret.append(tmp);
}
}
} catch (IOException e) {
return null;
}
return ret.toString();
}
private static String hash(String mac) {
if (mac == null || mac.isEmpty()) {
return null;
}
final String ret;
try {
final MessageDigest md = MessageDigest.getInstance("SHA-256");
final byte[] bytes = mac.getBytes("UTF-8");
md.update(bytes);
final byte[] bytesAfterDigest = md.digest();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytesAfterDigest.length; i++) {
sb.append(Integer.toString((bytesAfterDigest[i] & 0xff) + 0x100, 16).substring(1));
}
ret = sb.toString();
} catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
return null;
}
return ret;
}
}

Просмотреть файл

@ -0,0 +1,43 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.config;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.DocumentDbFactory;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.DocumentDbTemplate;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.convert.MappingDocumentDbConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public abstract class AbstractDocumentDbConfiguration extends DocumentDbConfigurationSupport {
public abstract String getDatabase();
public abstract DocumentClient documentClient();
@Bean
public DocumentDbFactory documentDbFactory() throws Exception {
return new DocumentDbFactory(this.documentClient());
}
@Bean
public DocumentDbTemplate documentDbTemplate() throws Exception {
return new DocumentDbTemplate(this.documentDbFactory(), this.mappingDocumentDbConverter(), this.getDatabase());
}
@Bean
public MappingDocumentDbConverter mappingDocumentDbConverter() throws Exception {
return new MappingDocumentDbConverter(this.documentDbMappingContext());
}
protected String getMappingBasePackage() {
final Package mappingBasePackage = getClass().getPackage();
return mappingBasePackage == null ? null : mappingBasePackage.getName();
}
}

Просмотреть файл

@ -0,0 +1,79 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.config;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbMappingContext;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.support.CachingIsNewStrategyFactory;
import org.springframework.data.support.IsNewStrategyFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.util.*;
public abstract class DocumentDbConfigurationSupport {
@Bean
public DocumentDbMappingContext documentDbMappingContext() throws ClassNotFoundException {
final DocumentDbMappingContext mappingContext = new DocumentDbMappingContext();
mappingContext.setInitialEntitySet(getInitialEntitySet());
return mappingContext;
}
protected Collection<String> getMappingBasePackages() {
final Package mappingBasePackage = getClass().getPackage();
return Collections.singleton(mappingBasePackage == null ? null : mappingBasePackage.getName());
}
@Bean
public IsNewStrategyFactory isNewStrategyFactory() throws ClassNotFoundException {
return new CachingIsNewStrategyFactory(new MappingContextIsNewStrategyFactory(
new PersistentEntities(Arrays.<MappingContext<?, ?>>asList(
new MappingContext[]{documentDbMappingContext()}))));
}
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
final Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
for (final String basePackage : getMappingBasePackages()) {
initialEntitySet.addAll(scanForEntities(basePackage));
}
return initialEntitySet;
}
protected Set<Class<?>> scanForEntities(String basePackage) throws ClassNotFoundException {
if (!StringUtils.hasText(basePackage)) {
return Collections.emptySet();
}
final Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
if (StringUtils.hasText(basePackage)) {
final ClassPathScanningCandidateComponentProvider componentProvider =
new ClassPathScanningCandidateComponentProvider(false);
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
for (final BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
initialEntitySet
.add(ClassUtils.forName(candidate.getBeanClassName(),
DocumentDbConfigurationSupport.class.getClassLoader()));
}
}
return initialEntitySet;
}
}

Просмотреть файл

@ -0,0 +1,58 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core;
import com.microsoft.azure.documentdb.DocumentCollection;
import java.util.List;
public interface DocumentDbOperations {
String getCollectionName(Class<?> entityClass);
DocumentCollection createCollectionIfNotExists(String collectionName,
String partitionKeyFieldName,
Integer requestUnit);
<T> List<T> findAll(Class<T> entityClass,
String partitionKeyFieldName,
String partitionKeyFieldValue);
<T> List<T> findAll(String collectionName,
Class<T> entityClass,
String partitionKeyFieldName,
String partitionKeyFieldValue);
<T> T findById(Object id,
Class<T> entityClass,
String partitionKeyFieldValue);
<T> T findById(String collectionName,
Object id,
Class<T> entityClass,
String partitionKeyFieldValue);
<T> T insert(T objectToSave, String partitionKeyFieldValue);
<T> T insert(String collectionName,
T objectToSave,
String partitionKeyFieldValue);
<T> void update(T object, String id, String partitionKeyFieldValue);
<T> void update(String collectionName,
T object,
String id,
String partitionKeyFieldValue);
<T> void deleteById(String collectionName,
Object id,
Class<T> domainClass,
String partitionKeyFieldValue);
void deleteAll(String collectionName);
}

Просмотреть файл

@ -0,0 +1,376 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core;
import com.microsoft.azure.documentdb.*;
import com.microsoft.azure.documentdb.internal.HttpConstants;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.DocumentDbFactory;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.convert.MappingDocumentDbConverter;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbPersistentEntity;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbPersistentProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
public class DocumentDbTemplate implements DocumentDbOperations, ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory.getLogger(DocumentDbTemplate.class);
private final DocumentDbFactory documentDbFactory;
private final MappingDocumentDbConverter mappingDocumentDbConverter;
private final String databaseName;
private final MappingContext<? extends DocumentDbPersistentEntity<?>, DocumentDbPersistentProperty> mappingContext;
private Database databaseCache;
private List<String> collectionCache;
public DocumentDbTemplate(DocumentDbFactory documentDbFactory,
MappingDocumentDbConverter mappingDocumentDbConverter,
String dbName) {
Assert.notNull(documentDbFactory, "DocumentDbFactory must not be null!");
Assert.notNull(mappingDocumentDbConverter, "MappingDocumentDbConverter must not be null!");
this.databaseName = dbName;
this.documentDbFactory = documentDbFactory;
this.mappingDocumentDbConverter = mappingDocumentDbConverter;
this.mappingContext = mappingDocumentDbConverter.getMappingContext();
this.collectionCache = new ArrayList<>();
}
public DocumentDbTemplate(DocumentClient client,
MappingDocumentDbConverter mappingDocumentDbConverter,
String dbName) {
this(new DocumentDbFactory(client), mappingDocumentDbConverter, dbName);
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
public <T> T insert(T objectToSave, String partitionKeyFieldValue) {
return insert(getCollectionName(objectToSave.getClass()),
objectToSave,
partitionKeyFieldValue);
}
public <T> T insert(String collectionName,
T objectToSave,
String partitionKeyFieldValue) {
final Document document = new Document();
mappingDocumentDbConverter.write(objectToSave, document);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("execute createDocument in database {} collection {}",
this.databaseName, collectionName);
}
try {
documentDbFactory.getDocumentClient()
.createDocument(getCollectionLink(this.databaseName, collectionName), document,
getRequestOptions(partitionKeyFieldValue, null), false);
return objectToSave;
} catch (DocumentClientException e) {
throw new RuntimeException("insert exception", e);
}
}
public <T> T findById(Object id,
Class<T> entityClass,
String partitionKeyFieldValue) {
return findById(getCollectionName(entityClass),
id,
entityClass,
partitionKeyFieldValue);
}
public <T> T findById(String collectionName,
Object id,
Class<T> entityClass,
String partitionKeyFieldValue) {
try {
final Resource resource = documentDbFactory.getDocumentClient()
.readDocument(getDocumentLink(this.databaseName, collectionName, (String) id),
getRequestOptions(partitionKeyFieldValue, null)).getResource();
if (resource instanceof Document) {
final Document document = (Document) resource;
return mappingDocumentDbConverter.read(entityClass, document);
} else {
return null;
}
} catch (DocumentClientException e) {
if (e.getStatusCode() == HttpConstants.StatusCodes.NOTFOUND) {
return null;
}
throw new RuntimeException("findById exception", e);
}
}
public <T> void update(T object, String id, String partitionKeyFieldValue) {
update(getCollectionName(object.getClass()), object, id, partitionKeyFieldValue);
}
public <T> void update(String collectionName, T object, String id, String partitionKeyFieldValue) {
try {
final Resource resource = documentDbFactory.getDocumentClient()
.readDocument(getDocumentLink(this.databaseName, collectionName, id),
getRequestOptions(partitionKeyFieldValue, null))
.getResource();
if (resource instanceof Document) {
final Document originalDoc = (Document) resource;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("execute replaceDocument in database {} collection {} with id {}",
this.databaseName, collectionName, id);
}
mappingDocumentDbConverter.write(object, originalDoc);
documentDbFactory.getDocumentClient().replaceDocument(
originalDoc.getSelfLink(),
originalDoc,
getRequestOptions(partitionKeyFieldValue, null));
} else {
LOGGER.error("invalid Document to update {}", resource.getSelfLink());
throw new RuntimeException("invalid Document to update " + resource.getSelfLink());
}
} catch (DocumentClientException ex) {
throw new RuntimeException("update exception", ex);
}
}
public <T> List<T> findAll(Class<T> entityClass,
String partitionKeyFieldName,
String partitionKeyFieldValue) {
return findAll(getCollectionName(entityClass),
entityClass,
partitionKeyFieldName,
partitionKeyFieldValue);
}
public <T> List<T> findAll(String collectionName,
final Class<T> entityClass,
String partitionKeyFieldName,
String partitionKeyFieldValue) {
final List<DocumentCollection> collections = documentDbFactory.getDocumentClient().
queryCollections(
getDatabaseLink(this.databaseName),
new SqlQuerySpec("SELECT * FROM ROOT r WHERE r.id=@id",
new SqlParameterCollection(new SqlParameter("@id", collectionName))), null)
.getQueryIterable().toList();
if (collections.size() != 1) {
throw new RuntimeException("expect only one collection: " + collectionName
+ " in database: " + this.databaseName + ", but found " + collections.size());
}
SqlQuerySpec sqlQuerySpec = new SqlQuerySpec("SELECT * FROM root c");
if (partitionKeyFieldName != null && !partitionKeyFieldName.isEmpty()) {
sqlQuerySpec = new SqlQuerySpec("SELECT * FROM root c WHERE c." + partitionKeyFieldName + "=@partition",
new SqlParameterCollection(new SqlParameter("@partition", partitionKeyFieldValue)));
}
final FeedOptions feedOptions = new FeedOptions();
feedOptions.setEnableCrossPartitionQuery(true);
final List<Document> results = documentDbFactory.getDocumentClient()
.queryDocuments(collections.get(0).getSelfLink(),
sqlQuerySpec, feedOptions)
.getQueryIterable().toList();
final List<T> entities = new ArrayList<>();
for (int i = 0; i < results.size(); i++) {
final T entity = mappingDocumentDbConverter.read(entityClass, results.get(i));
entities.add(entity);
}
return entities;
}
public void deleteAll(String collectionName) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("execute deleteCollection in database {} collection {} with id {}",
this.databaseName, collectionName);
}
try {
documentDbFactory.getDocumentClient()
.deleteCollection(getCollectionLink(this.databaseName, collectionName), null);
if (this.collectionCache.contains(collectionName)) {
this.collectionCache.remove(collectionName);
}
} catch (DocumentClientException ex) {
if (ex.getStatusCode() == 404) {
LOGGER.warn("deleteAll in database {} collection {} met NOTFOUND error {}",
this.databaseName, collectionName, ex.getMessage());
} else {
throw new RuntimeException("deleteAll exception", ex);
}
}
}
public String getCollectionName(Class<?> entityClass) {
return entityClass.getSimpleName();
}
private Database createDatabaseIfNotExists(String dbName) {
try {
final List<Database> dbList = documentDbFactory.getDocumentClient()
.queryDatabases(new SqlQuerySpec("SELECT * FROM root r WHERE r.id=@id",
new SqlParameterCollection(new SqlParameter("@id", dbName))), null)
.getQueryIterable().toList();
if (!dbList.isEmpty()) {
return dbList.get(0);
} else {
// create new database
final Database db = new Database();
db.setId(dbName);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("execute createDatabase {}", dbName);
}
final Resource resource = documentDbFactory.getDocumentClient()
.createDatabase(db, null).getResource();
if (resource instanceof Database) {
return (Database) resource;
} else {
LOGGER.error("create database {} get unexpected result: {}" + resource.getSelfLink());
throw new RuntimeException("create database {} get unexpected result: " + resource.getSelfLink());
}
}
} catch (DocumentClientException ex) {
throw new RuntimeException("createOrGetDatabase exception", ex);
}
}
public DocumentCollection createCollection(String collectionName,
RequestOptions collectionOptions,
String partitionKeyFieldName) {
return createCollection(this.databaseName, collectionName, collectionOptions, partitionKeyFieldName);
}
public DocumentCollection createCollection(String dbName,
String collectionName,
RequestOptions collectionOptions,
String partitionKeyFieldName) {
DocumentCollection collection = new DocumentCollection();
collection.setId(collectionName);
if (partitionKeyFieldName != null && !partitionKeyFieldName.isEmpty()) {
final PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition();
final ArrayList<String> paths = new ArrayList<String>();
paths.add(getPartitionKeyPath(partitionKeyFieldName));
partitionKeyDefinition.setPaths(paths);
collection.setPartitionKey(partitionKeyDefinition);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("execute createCollection in database {} collection {}", dbName, collectionName);
}
try {
final Resource resource = documentDbFactory.getDocumentClient()
.createCollection(getDatabaseLink(dbName), collection, collectionOptions)
.getResource();
if (resource instanceof DocumentCollection) {
collection = (DocumentCollection) resource;
}
return collection;
} catch (DocumentClientException e) {
throw new RuntimeException("createCollection exception", e);
}
}
public DocumentCollection createCollectionIfNotExists(String collectionName,
String partitionKeyFieldName,
Integer requestUnit) {
if (this.databaseCache == null) {
this.databaseCache = createDatabaseIfNotExists(this.databaseName);
}
final List<DocumentCollection> collectionList = documentDbFactory.getDocumentClient()
.queryCollections(getDatabaseLink(this.databaseName),
new SqlQuerySpec("SELECT * FROM root r WHERE r.id=@id",
new SqlParameterCollection(new SqlParameter("@id", collectionName))), null)
.getQueryIterable().toList();
if (!collectionList.isEmpty()) {
return collectionList.get(0);
} else {
final RequestOptions requestOptions = getRequestOptions(null, requestUnit);
return createCollection(this.databaseName, collectionName, requestOptions, partitionKeyFieldName);
}
}
public <T> void deleteById(String collectionName,
Object id,
Class<T> domainClass,
String partitionKeyFieldValue) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("execute deleteById in database {} collection {}", this.databaseName, collectionName);
}
try {
documentDbFactory.getDocumentClient().deleteDocument(
getDocumentLink(this.databaseName, collectionName, id.toString()),
getRequestOptions(partitionKeyFieldValue, null));
} catch (DocumentClientException ex) {
throw new RuntimeException("deleteById exception", ex);
}
}
private String getDatabaseLink(String databaseName) {
return "dbs/" + databaseName;
}
private String getCollectionLink(String databaseName, String collectionName) {
return getDatabaseLink(databaseName) + "/colls/" + collectionName;
}
private String getDocumentLink(String databaseName, String collectionName, String documentId) {
return getCollectionLink(databaseName, collectionName) + "/docs/" + documentId;
}
private String getPartitionKeyPath(String partitionKey) {
return "/" + partitionKey;
}
private RequestOptions getRequestOptions(String partitionKeyValue, Integer requestUnit) {
if ((partitionKeyValue == null || partitionKeyValue.isEmpty()) && requestUnit == null) {
return null;
}
final RequestOptions requestOptions = new RequestOptions();
if (!(partitionKeyValue == null || partitionKeyValue.isEmpty())) {
requestOptions.setPartitionKey(new PartitionKey(partitionKeyValue));
}
if (requestUnit != null) {
requestOptions.setOfferThroughput(requestUnit);
}
return requestOptions;
}
}

Просмотреть файл

@ -0,0 +1,30 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.convert;
import com.google.gson.Gson;
import com.microsoft.azure.documentdb.Document;
public class DocumentDbConverter {
private final Gson gson;
public DocumentDbConverter() {
gson = new Gson();
}
public <T> Document convertToDocument(T entity) {
final String json = this.gson.toJson(entity);
return new Document(json);
}
public <T> T convertFromDocument(Document document, Class<T> entityClass) {
return this.gson.fromJson(document.toJson(), entityClass);
}
}

Просмотреть файл

@ -0,0 +1,153 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.convert;
import com.microsoft.azure.documentdb.Document;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbPersistentEntity;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbPersistentProperty;
import org.apache.commons.lang3.ClassUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.convert.EntityConverter;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PropertyHandler;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.MappingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
public class MappingDocumentDbConverter
implements EntityConverter<DocumentDbPersistentEntity<?>, DocumentDbPersistentProperty, Object, Document>,
ApplicationContextAware {
protected final MappingContext<? extends DocumentDbPersistentEntity<?>,
DocumentDbPersistentProperty> mappingContext;
protected GenericConversionService conversionService;
private ApplicationContext applicationContext;
public MappingDocumentDbConverter(
MappingContext<? extends DocumentDbPersistentEntity<?>, DocumentDbPersistentProperty> mappingContext) {
this.mappingContext = mappingContext;
this.conversionService = new GenericConversionService();
}
@Override
public <R extends Object> R read(Class<R> type, Document sourceDocument) {
if (sourceDocument == null) {
return null;
}
final DocumentDbPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
return readInternal(entity, type, sourceDocument);
}
protected <R extends Object> R readInternal(final DocumentDbPersistentEntity<?> entity, Class<R> type,
final Document sourceDocument) {
final R result = instantiate(type);
final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(result);
final DocumentDbPersistentProperty idProperty = entity.getIdProperty();
final Object idValue = sourceDocument.getId();
if (idProperty != null) {
accessor.setProperty(idProperty, idValue);
}
entity.doWithProperties((PropertyHandler<DocumentDbPersistentProperty>) prop -> {
if (idProperty != null && idProperty.equals(prop)) {
return;
}
accessor.setProperty(prop, sourceDocument.get(prop.getName()));
}
);
return result;
}
@Override
public void write(Object sourceEntity, Document document) {
if (sourceEntity == null) {
return;
}
final DocumentDbPersistentEntity<?> entity = mappingContext.getPersistentEntity(sourceEntity.getClass());
writeInternal(sourceEntity, document, entity);
}
public void writeInternal(final Object entity,
final Document targetDocument,
final DocumentDbPersistentEntity<?> entityInformation) {
if (entity == null) {
return;
}
if (entityInformation == null) {
throw new MappingException("no mapping metadata for entity type: " + entity.getClass().getName());
}
final ConvertingPropertyAccessor accessor = getPropertyAccessor(entity);
final DocumentDbPersistentProperty idProperty = entityInformation.getIdProperty();
if (idProperty != null) {
targetDocument.setId((String) accessor.getProperty(idProperty));
}
for (final Field field : entity.getClass().getDeclaredFields()) {
if (null != idProperty && field.getName().equals(idProperty.getName())) {
continue;
}
targetDocument.set(field.getName(),
accessor.getProperty(entityInformation.getPersistentProperty(field.getName())));
}
}
public ApplicationContext getApplicationContext() {
return this.applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public ConversionService getConversionService() {
return conversionService;
}
public MappingContext<? extends DocumentDbPersistentEntity<?>, DocumentDbPersistentProperty> getMappingContext() {
return mappingContext;
}
private ConvertingPropertyAccessor getPropertyAccessor(Object entity) {
final DocumentDbPersistentEntity<?> entityInformation = mappingContext.getPersistentEntity(entity.getClass());
final PersistentPropertyAccessor accessor = entityInformation.getPropertyAccessor(entity);
return new ConvertingPropertyAccessor(accessor, conversionService);
}
private <T> T instantiate(Class<T> tClass) {
try {
final Constructor<T> constructor = (Constructor<T>) tClass.getConstructors()[0];
final List<Object> params = new ArrayList<>();
for (final Class<?> paramType : constructor.getParameterTypes()) {
params.add((paramType.isPrimitive()) ? ClassUtils.primitiveToWrapper(paramType).newInstance() : null);
}
return constructor.newInstance(params.toArray());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e.getMessage());
}
}
}

Просмотреть файл

@ -0,0 +1,43 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryAccessor;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.spel.support.StandardEvaluationContext;
public class BasicDocumentDbPersistentEntity<T> extends BasicPersistentEntity<T, DocumentDbPersistentProperty>
implements DocumentDbPersistentEntity<T>, ApplicationContextAware {
private final StandardEvaluationContext context;
public BasicDocumentDbPersistentEntity(TypeInformation<T> typeInformation) {
super(typeInformation);
this.context = new StandardEvaluationContext();
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context.addPropertyAccessor(new BeanFactoryAccessor());
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
context.setRootObject(applicationContext);
}
public String getCollection() {
return "";
}
@Override
public String getLanguage() {
return "";
}
}

Просмотреть файл

@ -0,0 +1,43 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
public class BasicDocumentDbPersistentProperty extends AnnotationBasedPersistentProperty<DocumentDbPersistentProperty>
implements DocumentDbPersistentProperty {
private static final String ID_PROPERTY_NAME = "id";
public BasicDocumentDbPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
DocumentDbPersistentEntity<?> owner,
SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
}
@Override
protected Association<DocumentDbPersistentProperty> createAssociation() {
return new Association<>(this, null);
}
@Override
public boolean isIdProperty() {
if (super.isIdProperty()) {
return true;
}
return getName().equals(ID_PROPERTY_NAME);
}
}

Просмотреть файл

@ -0,0 +1,21 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import org.springframework.data.annotation.Persistent;
import java.lang.annotation.*;
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Document {
String collection() default "";
String ru() default "4000";
}

Просмотреть файл

@ -0,0 +1,47 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
public class DocumentDbMappingContext
extends AbstractMappingContext<BasicDocumentDbPersistentEntity<?>, DocumentDbPersistentProperty>
implements ApplicationContextAware {
private ApplicationContext context;
@Override
protected <T> BasicDocumentDbPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
final BasicDocumentDbPersistentEntity<T> entity = new BasicDocumentDbPersistentEntity<>(typeInformation);
if (context != null) {
entity.setApplicationContext(context);
}
return entity;
}
@Override
public DocumentDbPersistentProperty createPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
BasicDocumentDbPersistentEntity<?> owner,
SimpleTypeHolder simpleTypeHolder) {
return new BasicDocumentDbPersistentProperty(field, propertyDescriptor, owner,
simpleTypeHolder);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.context = applicationContext;
}
}

Просмотреть файл

@ -0,0 +1,17 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import org.springframework.data.mapping.PersistentEntity;
public interface DocumentDbPersistentEntity<T> extends PersistentEntity<T, DocumentDbPersistentProperty> {
String getCollection();
String getLanguage();
}

Просмотреть файл

@ -0,0 +1,13 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import org.springframework.data.mapping.PersistentProperty;
public interface DocumentDbPersistentProperty extends PersistentProperty<DocumentDbPersistentProperty> {
}

Просмотреть файл

@ -0,0 +1,14 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface PartitionKey {
}

Просмотреть файл

@ -0,0 +1,33 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.io.Serializable;
import java.util.List;
@NoRepositoryBean
public interface DocumentDbRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
@Override
List<T> findAll();
void update(T entity);
List<T> findAll(String partitionKeyValue);
T findOne(ID id, String partitionKeyValue);
void delete(ID id, String partitionKeyValue);
void delete(T entity, String partitionKeyValue);
void update(T entity, String partitionKeyValue);
}

Просмотреть файл

@ -0,0 +1,28 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.config;
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import java.lang.annotation.Annotation;
public class DocumentDbRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableDocumentDbRepositories.class;
}
@Override
protected RepositoryConfigurationExtension getExtension() {
return new DocumentDbRepositoryConfigurationExtension();
}
}

Просмотреть файл

@ -0,0 +1,65 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.config;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbMappingContext;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.DocumentDbRepository;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support.DocumentDbRepositoryFactoryBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
public class DocumentDbRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport {
@Override
public String getModuleName() {
return "documentdb";
}
@Override
public String getModulePrefix() {
return "documentdb";
}
public String getRepositoryFactoryBeanClassName() {
return DocumentDbRepositoryFactoryBean.class.getName();
}
@Override
public String getRepositoryFactoryClassName() {
return DocumentDbRepositoryFactoryBean.class.getName();
}
@Override
protected Collection<Class<?>> getIdentifyingTypes() {
return Collections.<Class<?>>singleton(DocumentDbRepository.class);
}
@Override
protected Collection<Class<? extends Annotation>> getIdentifyingAnnotations() {
return Collections.emptyList();
}
@Override
public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource config) {
super.registerBeansForRoot(registry, config);
final RootBeanDefinition definition = new RootBeanDefinition(DocumentDbMappingContext.class);
definition.setRole(AbstractBeanDefinition.ROLE_INFRASTRUCTURE);
definition.setSource(config.getSource());
registry.registerBeanDefinition("documentDbMappingContext", definition);
}
}

Просмотреть файл

@ -0,0 +1,47 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.config;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support.DocumentDbRepositoryFactoryBean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Import;
import org.springframework.data.repository.config.DefaultRepositoryBaseClass;
import org.springframework.data.repository.query.QueryLookupStrategy;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(DocumentDbRepositoriesRegistrar.class)
public @interface EnableDocumentDbRepositories {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Filter[] includeFilters() default {};
Filter[] excludeFilters() default {};
String repositoryImplementationPostfix() default "Impl";
String namedQueriesLocation() default "";
QueryLookupStrategy.Key queryLookupStrategy() default QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND;
Class<?> repositoryFactoryBeanClass() default DocumentDbRepositoryFactoryBean.class;
Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;
boolean considerNestedRepositories() default false;
}

Просмотреть файл

@ -0,0 +1,129 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.Document;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.PartitionKey;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.data.annotation.Id;
import org.springframework.data.repository.core.support.AbstractEntityInformation;
import org.springframework.util.ReflectionUtils;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;
public class DocumentDbEntityInformation<T, ID extends Serializable>
extends AbstractEntityInformation<T, ID> {
private Field id;
private Field partitionKeyField;
private String collectionName;
private Integer requestUnit;
public DocumentDbEntityInformation(Class<T> domainClass) {
super(domainClass);
this.id = getIdField(domainClass);
if (this.id != null) {
ReflectionUtils.makeAccessible(this.id);
}
this.collectionName = getCollectionName(domainClass);
this.partitionKeyField = getPartitionKeyField(domainClass);
if (this.partitionKeyField != null) {
ReflectionUtils.makeAccessible(this.partitionKeyField);
}
this.requestUnit = getRequestUnit(domainClass);
}
public ID getId(T entity) {
return (ID) ReflectionUtils.getField(id, entity);
}
public Class<ID> getIdType() {
return (Class<ID>) id.getType();
}
public String getCollectionName() {
return this.collectionName;
}
public Integer getRequestUint() {
return this.requestUnit;
}
public String getPartitionKeyFieldName() {
return partitionKeyField == null ? null : partitionKeyField.getName();
}
public String getPartitionKeyFieldValue(T entity) {
return partitionKeyField == null ? null : (String) ReflectionUtils.getField(partitionKeyField, entity);
}
private Field getIdField(Class<?> domainClass) {
Field idField = null;
final List<Field> fields = FieldUtils.getFieldsListWithAnnotation(domainClass, Id.class);
if (fields.isEmpty()) {
idField = ReflectionUtils.findField(getJavaType(), "id");
} else if (fields.size() == 1) {
idField = fields.get(0);
} else {
throw new IllegalArgumentException("only one field with @Id annotation!");
}
if (idField != null && idField.getType() != String.class) {
throw new IllegalArgumentException("type of id field must be String");
}
return idField;
}
private String getCollectionName(Class<?> domainClass) {
String customCollectionName = domainClass.getSimpleName();
final Document annotation = domainClass.getAnnotation(Document.class);
if (annotation != null && annotation.collection() != null && !annotation.collection().isEmpty()) {
customCollectionName = annotation.collection();
}
return customCollectionName;
}
private Field getPartitionKeyField(Class<?> domainClass) {
Field partitionKeyField = null;
final List<Field> fields = FieldUtils.getFieldsListWithAnnotation(domainClass, PartitionKey.class);
if (fields.size() == 1) {
partitionKeyField = fields.get(0);
} else if (fields.size() > 1) {
throw new IllegalArgumentException("Azure Cosmos DB supports only one partition key, " +
"only one field with @PartitionKey annotation!");
}
if (partitionKeyField != null && partitionKeyField.getType() != String.class) {
throw new IllegalArgumentException("type of PartitionKey field must be String");
}
return partitionKeyField;
}
private Integer getRequestUnit(Class<?> domainClass) {
Integer ru = 4000;
final Document annotation = domainClass.getAnnotation(Document.class);
if (annotation != null && annotation.ru() != null && !annotation.ru().isEmpty()) {
ru = Integer.parseInt(annotation.ru());
}
return ru;
}
}

Просмотреть файл

@ -0,0 +1,42 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support;
import org.springframework.context.ApplicationContext;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import java.io.Serializable;
public class DocumentDbRepositoryFactory extends RepositoryFactorySupport {
private final ApplicationContext applicationContext;
public DocumentDbRepositoryFactory(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleDocumentDbRepository.class;
}
@Override
protected Object getTargetRepository(RepositoryInformation information) {
final EntityInformation<?, Serializable> entityInformation = getEntityInformation(information.getDomainType());
return getTargetRepositoryViaReflection(information, entityInformation, this.applicationContext);
}
@Override
public <T, ID extends Serializable> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
return new DocumentDbEntityInformation<T, ID>(domainClass);
}
}

Просмотреть файл

@ -0,0 +1,50 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.DocumentDbOperations;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import java.io.Serializable;
public class DocumentDbRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
extends RepositoryFactoryBeanSupport<T, S, ID>
implements ApplicationContextAware {
private ApplicationContext applicationContext;
private DocumentDbOperations operations;
public DocumentDbRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
public void setDocumentDbOperations(DocumentDbOperations operations) {
this.operations = operations;
}
@Override
protected final RepositoryFactorySupport createRepositoryFactory() {
return getFactoryInstance(applicationContext);
}
protected RepositoryFactorySupport getFactoryInstance(ApplicationContext applicationContext) {
return new DocumentDbRepositoryFactory(applicationContext);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

Просмотреть файл

@ -0,0 +1,270 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.DocumentDbOperations;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.DocumentDbRepository;
import org.springframework.context.ApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.List;
public class SimpleDocumentDbRepository<T, ID extends Serializable> implements DocumentDbRepository<T, ID> {
private final DocumentDbOperations documentDbOperations;
private final DocumentDbEntityInformation<T, ID> entityInformation;
public SimpleDocumentDbRepository(DocumentDbEntityInformation<T, ID> metadata,
ApplicationContext applicationContext) {
this.documentDbOperations = applicationContext.getBean(DocumentDbOperations.class);
this.entityInformation = metadata;
}
public SimpleDocumentDbRepository(DocumentDbEntityInformation<T, ID> metadata,
DocumentDbOperations dbOperations) {
this.documentDbOperations = dbOperations;
this.entityInformation = metadata;
}
/**
* save entity without partition
*
* @param entity to be saved
* @param <S>
* @return entity
*/
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "entity must not be null");
// create collection if not exists
documentDbOperations.createCollectionIfNotExists(entityInformation.getCollectionName(),
entityInformation.getPartitionKeyFieldName(),
entityInformation.getRequestUint());
// save entity
documentDbOperations.insert(entityInformation.getCollectionName(),
entity,
entityInformation.getPartitionKeyFieldValue(entity));
return entity;
}
/**
* batch save entities
*
* @param entities
* @param <S>
* @return
*/
@Override
public <S extends T> Iterable<S> save(Iterable<S> entities) {
throw new UnsupportedOperationException("save not supported yet.");
}
/**
* find all entities from one collection without partition
*
* @return
*/
@Override
public List<T> findAll() {
return documentDbOperations.findAll(entityInformation.getCollectionName(),
entityInformation.getJavaType(), null, null);
}
/**
* find entities based on id list from one collection without partitions
*
* @param ids
* @return
*/
@Override
public List<T> findAll(Iterable<ID> ids) {
throw new UnsupportedOperationException("findAll not supported yet.");
}
/**
* find one entity per id without partitions
*
* @param id
* @return
*/
@Override
public T findOne(ID id) {
Assert.notNull(id, "id must not be null");
return documentDbOperations.findById(
entityInformation.getCollectionName(), id, entityInformation.getJavaType(), null);
}
@Override
public Page<T> findAll(Pageable pageable) {
throw new UnsupportedOperationException("findAll(Pageable pageable) not supported yet.");
}
@Override
public List<T> findAll(Sort sort) {
throw new UnsupportedOperationException("findAll(Sort sort) Sort not supported yet.");
}
/**
* return count of documents in one collection without partitions
*
* @return
*/
@Override
public long count() {
return findAll().size();
}
/**
* delete one document per id without partitions
*
* @param id
*/
@Override
public void delete(ID id) {
documentDbOperations.deleteById(entityInformation.getCollectionName(),
id,
entityInformation.getJavaType(),
null);
}
/**
* delete one document per entity without partitions
*
* @param entity
*/
@Override
public void delete(T entity) {
documentDbOperations.deleteById(entityInformation.getCollectionName(),
entityInformation.getId(entity),
entityInformation.getJavaType(),
null);
}
/**
* delete an collection
*/
@Override
public void deleteAll() {
documentDbOperations.deleteAll(entityInformation.getCollectionName());
}
/**
* delete list of entities without partitions
*
* @param entities
*/
@Override
public void delete(Iterable<? extends T> entities) {
throw new UnsupportedOperationException("delete not supported yet.");
}
/**
* check if an entity exists per id without partition
*
* @param primaryKey
* @return
*/
@Override
public boolean exists(ID primaryKey) {
return findOne(primaryKey) != null;
}
/**
* update an entity without partitions
*
* @param entity
*/
@Override
public void update(T entity) {
documentDbOperations.update(entityInformation.getCollectionName(),
entity,
((String) entityInformation.getId(entity)),
null);
}
/**
* find all entities from one collection with partitions
*
* @param partitionKeyValue
* @return
*/
public List<T> findAll(String partitionKeyValue) {
return documentDbOperations.findAll(entityInformation.getCollectionName(),
entityInformation.getJavaType(),
entityInformation.getPartitionKeyFieldName(),
partitionKeyValue);
}
/**
* find one entity per id with partitions
*
* @param id
* @param partitionKeyValue
* @return
*/
public T findOne(ID id, String partitionKeyValue) {
Assert.notNull(id, "id must not be null");
Assert.notNull(partitionKeyValue, "partitionKeyValue must not be null");
return documentDbOperations.findById(
entityInformation.getCollectionName(),
id,
entityInformation.getJavaType(),
partitionKeyValue);
}
/**
* delete an entity per id with partitions
*
* @param id
* @param partitionKeyValue
*/
public void delete(ID id, String partitionKeyValue) {
documentDbOperations.deleteById(entityInformation.getCollectionName(),
id,
entityInformation.getJavaType(),
partitionKeyValue);
}
/**
* delete an entity with partitions
*
* @param entity
* @param partitionKeyValue
*/
public void delete(T entity, String partitionKeyValue) {
documentDbOperations.deleteById(entityInformation.getCollectionName(),
entityInformation.getId(entity),
entityInformation.getJavaType(),
partitionKeyValue);
}
/**
* update an entity with partitions
*
* @param entity
* @param partitionKeyValue
*/
public void update(T entity, String partitionKeyValue) {
documentDbOperations.update(entityInformation.getCollectionName(),
entity,
((String) entityInformation.getId(entity)),
partitionKeyValue);
}
}

Просмотреть файл

@ -0,0 +1 @@
org.springframework.data.repository.core.support.RepositoryFactorySupport=com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support.DocumentDbRepositoryFactory

Просмотреть файл

@ -0,0 +1,27 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
public class DocumentDbFactoryUnitTest {
@Test(expected = IllegalArgumentException.class)
public void testNullKey() throws Exception {
new DocumentDbFactory("https://fakeuri", null);
}
@Test
public void testInvalidEndpoint() {
final DocumentDbFactory factory = new DocumentDbFactory("https://fakeuri", "fakekey");
assertThat(factory).isNotNull();
}
}

Просмотреть файл

@ -0,0 +1,50 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.config;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.DocumentDbFactory;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.AbstractApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
public class AbstractDocumentDbConfiguratinUnitTest {
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void containsDocumentDbFactory() throws ClassNotFoundException {
final AbstractApplicationContext context = new AnnotationConfigApplicationContext(
TestDocumentDbConfiguration.class);
assertThat(context.getBean(DocumentDbFactory.class)).isNotNull();
}
@Configuration
static class TestDocumentDbConfiguration extends AbstractDocumentDbConfiguration {
@MockBean
private DocumentClient mockClient;
@Override
public String getDatabase() {
return "testdb";
}
@Override
public DocumentClient documentClient() {
return mockClient;
}
}
}

Просмотреть файл

@ -0,0 +1,209 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core;
import com.microsoft.azure.documentdb.ConnectionPolicy;
import com.microsoft.azure.documentdb.ConsistencyLevel;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.convert.MappingDocumentDbConverter;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbMappingContext;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Person;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.domain.EntityScanner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.annotation.Persistent;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@PropertySource(value = {"classpath:application.properties"})
public class DocumentDbTemplateIT {
private static final String TEST_ID = "testid";
private static final String TEST_NOTEXIST_ID = "testid2";
private static final String TEST_DB_NAME = "testdb";
private static final Person TEST_PERSON = new Person(TEST_ID, "testfirstname", "testlastname");
private static final String PARTITION_KEY = "lastName";
@Value("${documentdb.uri}")
private String documentDbUri;
@Value("${documentdb.key}")
private String documentDbKey;
private DocumentClient documentClient;
private DocumentDbTemplate dbTemplate;
private MappingDocumentDbConverter dbConverter;
private DocumentDbMappingContext mappingContext;
@Autowired
private ApplicationContext applicationContext;
@Before
public void setup() {
mappingContext = new DocumentDbMappingContext();
try {
mappingContext.setInitialEntitySet(new EntityScanner(this.applicationContext)
.scan(Persistent.class));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e.getMessage());
}
dbConverter = new MappingDocumentDbConverter(mappingContext);
documentClient = new DocumentClient(documentDbUri, documentDbKey,
ConnectionPolicy.GetDefault(), ConsistencyLevel.Session);
dbTemplate = new DocumentDbTemplate(documentClient, dbConverter, TEST_DB_NAME);
dbTemplate.createCollectionIfNotExists(Person.class.getSimpleName(), null, null);
dbTemplate.insert(Person.class.getSimpleName(), TEST_PERSON, null);
}
@After
public void cleanup() {
dbTemplate.deleteAll(Person.class.getSimpleName());
}
@Test(expected = RuntimeException.class)
public void testInsertDuplicateId() throws Exception {
dbTemplate.insert(Person.class.getSimpleName(), TEST_PERSON, null);
}
@Test
public void testFindAll() {
final List<Person> result = dbTemplate.findAll(Person.class.getSimpleName(), Person.class, null, null);
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getId()).isEqualTo(TEST_PERSON.getId());
assertThat(result.get(0).getFirstName()).isEqualTo(TEST_PERSON.getFirstName());
assertThat(result.get(0).getLastName()).isEqualTo(TEST_PERSON.getLastName());
}
@Test
public void testFindAllPartition() {
setupPartition();
final List<Person> result = dbTemplate.findAll(Person.class.getSimpleName(),
Person.class, PARTITION_KEY, TEST_PERSON.getLastName());
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getId()).isEqualTo(TEST_PERSON.getId());
assertThat(result.get(0).getFirstName()).isEqualTo(TEST_PERSON.getFirstName());
assertThat(result.get(0).getLastName()).isEqualTo(TEST_PERSON.getLastName());
}
@Test
public void testFindById() {
final Person result = dbTemplate.findById(Person.class.getSimpleName(),
TEST_PERSON.getId(), Person.class, null);
assertThat(result.getId()).isEqualTo(TEST_PERSON.getId());
assertThat(result.getFirstName()).isEqualTo(TEST_PERSON.getFirstName());
assertThat(result.getLastName()).isEqualTo(TEST_PERSON.getLastName());
final Person nullResult = dbTemplate.findById(Person.class.getSimpleName(),
TEST_NOTEXIST_ID, Person.class, null);
assertThat(nullResult).isNull();
}
@Test
public void testFindByIdPartition() {
setupPartition();
final Person result = dbTemplate.findById(Person.class.getSimpleName(),
TEST_PERSON.getId(), Person.class, TEST_PERSON.getLastName());
assertThat(result.getId()).isEqualTo(TEST_PERSON.getId());
assertThat(result.getFirstName()).isEqualTo(TEST_PERSON.getFirstName());
assertThat(result.getLastName()).isEqualTo(TEST_PERSON.getLastName());
final Person nullResult = dbTemplate.findById(Person.class.getSimpleName(),
TEST_NOTEXIST_ID, Person.class, TEST_PERSON.getLastName());
assertThat(nullResult).isNull();
}
@Test
public void testUpdate() {
final Person updated = new Person(TEST_PERSON.getId(), "updatedname",
TEST_PERSON.getLastName());
dbTemplate.update(Person.class.getSimpleName(), updated, updated.getId(), null);
final Person result = dbTemplate.findById(Person.class.getSimpleName(),
updated.getId(), Person.class, null);
assertThat(result.getId()).isEqualTo(updated.getId());
assertThat(result.getFirstName()).isEqualTo(updated.getFirstName());
assertThat(result.getLastName()).isEqualTo(updated.getLastName());
}
@Test
public void testUpdatePartition() {
setupPartition();
final Person updated = new Person(TEST_PERSON.getId(), "updatedname",
TEST_PERSON.getLastName());
dbTemplate.update(Person.class.getSimpleName(), updated, updated.getId(), updated.getLastName());
final Person result = dbTemplate.findById(Person.class.getSimpleName(),
updated.getId(), Person.class, updated.getLastName());
assertThat(result.getId()).isEqualTo(updated.getId());
assertThat(result.getFirstName()).isEqualTo(updated.getFirstName());
assertThat(result.getLastName()).isEqualTo(updated.getLastName());
}
@Test
public void testDeleteById() {
final Person person2 = new Person("newid", "newfn", "newln");
dbTemplate.insert(person2, null);
assertThat(dbTemplate.findAll(Person.class, null, null).size()).isEqualTo(2);
dbTemplate.deleteById(Person.class.getSimpleName(), TEST_PERSON.getId(), null, null);
final List<Person> result = dbTemplate.findAll(Person.class, null, null);
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getId()).isEqualTo(person2.getId());
assertThat(result.get(0).getFirstName()).isEqualTo(person2.getFirstName());
assertThat(result.get(0).getLastName()).isEqualTo(person2.getLastName());
}
@Test
public void testDeleteByIdPartition() {
setupPartition();
// insert new document with same partition key
final Person person2 = new Person("newid", "newfn", TEST_PERSON.getLastName());
dbTemplate.insert(Person.class.getSimpleName(), person2, person2.getLastName());
assertThat(dbTemplate.findAll(Person.class, PARTITION_KEY, person2.getLastName()).size()).isEqualTo(2);
dbTemplate.deleteById(Person.class.getSimpleName(),
TEST_PERSON.getId(), Person.class, TEST_PERSON.getLastName());
final List<Person> result = dbTemplate.findAll(Person.class, PARTITION_KEY, person2.getLastName());
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getId()).isEqualTo(person2.getId());
assertThat(result.get(0).getFirstName()).isEqualTo(person2.getFirstName());
assertThat(result.get(0).getLastName()).isEqualTo(person2.getLastName());
}
private void setupPartition() {
cleanup();
dbTemplate.createCollectionIfNotExists(Person.class.getSimpleName(), PARTITION_KEY, 1000);
dbTemplate.insert(Person.class.getSimpleName(), TEST_PERSON, TEST_PERSON.getLastName());
}
}

Просмотреть файл

@ -0,0 +1,40 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.DocumentDbFactory;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.convert.MappingDocumentDbConverter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class DocumentDbTemplateUnitTest {
DocumentDbTemplate dbTemplate;
@Mock
DocumentClient documentClient;
@Mock
MappingDocumentDbConverter dbConverter;
@Before
public void setUp() {
this.dbTemplate = new DocumentDbTemplate(new DocumentDbFactory(documentClient), dbConverter, "testdb");
}
@Test(expected = IllegalArgumentException.class)
public void rejectNullDbFactory() throws Exception {
new DocumentDbTemplate(documentClient, null, "testdb");
}
}

Просмотреть файл

@ -0,0 +1,61 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.converter;
import com.microsoft.azure.documentdb.Document;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.convert.DocumentDbConverter;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Person;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class DocumentDbConverterUnitTest {
private static final String id = "testId";
private static final String firstName = "testFirstName";
private static final String lastName = "testLastName";
private static final String idPropertyName = "id";
private static final String firstNamePropertyName = "firstName";
private static final String lastNamePropertyName = "lastName";
private DocumentDbConverter dbConverter;
@Before
public void setup() {
dbConverter = new DocumentDbConverter();
}
@Test
public void testConvertFromEntityToDocument() {
final Person person = new Person(id, firstName, lastName);
final Document document = dbConverter.convertToDocument(person);
assertThat(document.has(idPropertyName)).isTrue();
assertThat(document.has(firstNamePropertyName)).isTrue();
assertThat(document.has(lastNamePropertyName)).isTrue();
assertThat(document.getId()).isEqualTo(id);
assertThat(document.getString(firstNamePropertyName)).isEqualTo(firstName);
assertThat(document.getString(lastNamePropertyName)).isEqualTo(lastName);
}
@Test
public void testConvertFromDocumentToEntity() {
final JSONObject json = new JSONObject();
json.put(idPropertyName, id);
json.put(firstNamePropertyName, firstName);
json.put(lastNamePropertyName, lastName);
final Document document = new Document(JSONObject.valueToString(json));
final Person person = dbConverter.convertFromDocument(document, Person.class);
assertThat(person.getId()).isEqualTo(id);
assertThat(person.getFirstName()).isEqualTo(firstName);
assertThat(person.getLastName()).isEqualTo(lastName);
}
}

Просмотреть файл

@ -0,0 +1,73 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.converter;
import com.microsoft.azure.documentdb.Document;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.convert.MappingDocumentDbConverter;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbMappingContext;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Address;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.context.ApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(MockitoJUnitRunner.class)
public class MappingDocumentDbConverterUnitTest {
MappingDocumentDbConverter dbConverter;
DocumentDbMappingContext mappingContext;
@Mock
ApplicationContext applicationContext;
@Before
public void setup() {
mappingContext = new DocumentDbMappingContext();
mappingContext.setApplicationContext(applicationContext);
mappingContext.afterPropertiesSet();
mappingContext.getPersistentEntity(Address.class);
dbConverter = new MappingDocumentDbConverter(mappingContext);
}
@Test
public void covertAddressToDocumentCorrectly() {
final Address testAddress = new Address("98052", "testCity", "testStreet");
final Document document = new Document();
dbConverter.write(testAddress, document);
assertThat(document.getId()).isEqualTo(testAddress.getPostalCode());
assertThat(document.getString("city")).isEqualTo(testAddress.getCity());
assertThat(document.getString("street")).isEqualTo(testAddress.getStreet());
}
@Test
public void convertDocumentToAddressCorrectly() {
final Document document = new Document();
document.setId("testId");
document.set("city", "testCity");
document.set("street", "testStreet");
final Address address = dbConverter.read(Address.class, document);
assertThat(address.getPostalCode()).isEqualTo("testId");
assertThat(address.getCity()).isEqualTo("testCity");
assertThat(address.getStreet()).isEqualTo("testStreet");
}
}

Просмотреть файл

@ -0,0 +1,31 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Person;
import org.junit.Test;
import org.springframework.data.util.ClassTypeInformation;
import static org.assertj.core.api.Assertions.assertThat;
public class BasicDocumentDbPersistentEntityUnitTest {
@Test
public void testGetCollection() {
final BasicDocumentDbPersistentEntity entity = new BasicDocumentDbPersistentEntity<Person>(
ClassTypeInformation.from(Person.class));
assertThat(entity.getCollection()).isEqualTo("");
}
@Test
public void testGetLanguage() {
final BasicDocumentDbPersistentEntity entity = new BasicDocumentDbPersistentEntity<Person>(
ClassTypeInformation.from(Person.class));
assertThat(entity.getLanguage()).isEqualTo("");
}
}

Просмотреть файл

@ -0,0 +1,36 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.context.ApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(MockitoJUnitRunner.class)
public class DocumentDbMappingContextUnitTest {
@Mock
ApplicationContext context;
@Test
public void mappingContextWithImplicitIdProperty() {
final DocumentDbMappingContext context = new DocumentDbMappingContext();
final BasicDocumentDbPersistentEntity<?> entity = context.getPersistentEntity(ClassWithId.class);
assertThat(entity).isNotNull();
}
class ClassWithId {
String field;
String id;
}
}

Просмотреть файл

@ -0,0 +1,49 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.domain;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.Document;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.PartitionKey;
import org.springframework.data.annotation.Id;
@Document(ru = "1000")
public class Address {
@Id
String postalCode;
String street;
@PartitionKey
String city;
public Address(String postalCode, String city, String street) {
this.postalCode = postalCode;
this.city = city;
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getPostalCode() {
return this.postalCode;
}
public void setPostalCode(String code) {
this.postalCode = code;
}
}

Просмотреть файл

@ -0,0 +1,49 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.domain;
public class Person {
private String firstName;
private String lastName;
private String id;
public Person() {
this(null, null, null);
}
public Person(String id, String fname, String lname) {
this.firstName = fname;
this.lastName = lname;
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String fname) {
this.firstName = fname;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}

Просмотреть файл

@ -0,0 +1,14 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.domain;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.DocumentDbRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PersonRepository extends DocumentDbRepository<Person, String> {
}

Просмотреть файл

@ -0,0 +1,13 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Address;
import org.springframework.stereotype.Repository;
@Repository
public interface AddressRepository extends DocumentDbRepository<Address, String> {
}

Просмотреть файл

@ -0,0 +1,96 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Address;
import org.junit.After;
import org.junit.Before;
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 java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ContactRepositoryConfig.class)
public class AddressRepositoryIT {
private static final Address TEST_ADDRESS1_PARTITION1 = new Address("111", "redmond", "111st avenue");
private static final Address TEST_ADDRESS2_PARTITION1 = new Address("222", "redmond", "98th street");
private static final Address TEST_ADDRESS1_PARTITION2 = new Address("333", "bellevue", "103rd street");
@Autowired
AddressRepository repository;
@Before
public void setup() {
repository.save(TEST_ADDRESS1_PARTITION1);
repository.save(TEST_ADDRESS1_PARTITION2);
repository.save(TEST_ADDRESS2_PARTITION1);
}
@After
public void cleanup() {
repository.deleteAll();
}
@Test
public void testFindAll() {
// findAll cross partition
final List<Address> result = repository.findAll();
assertThat(result.size()).isEqualTo(3);
// findAll per partition
final List<Address> partition1 = repository.findAll(TEST_ADDRESS1_PARTITION1.getCity());
assertThat(partition1.size()).isEqualTo(2);
final List<Address> partition2 = repository.findAll(TEST_ADDRESS1_PARTITION2.getCity());
assertThat(partition2.size()).isEqualTo(1);
}
@Test
public void testCountAndDeleteByID() {
long count = repository.count();
assertThat(count).isEqualTo(3);
repository.delete(TEST_ADDRESS1_PARTITION1.getPostalCode(), TEST_ADDRESS1_PARTITION1.getCity());
final List<Address> result = repository.findAll();
assertThat(result.size()).isEqualTo(2);
count = repository.count();
assertThat(count).isEqualTo(2);
}
@Test
public void testCountAndDeleteEntity() {
repository.delete(TEST_ADDRESS1_PARTITION1, TEST_ADDRESS1_PARTITION1.getCity());
final List<Address> result = repository.findAll();
assertThat(result.size()).isEqualTo(2);
}
@Test
public void testUpdateEntity() {
final Address updatedAddress = new Address(TEST_ADDRESS1_PARTITION1.getPostalCode(),
TEST_ADDRESS1_PARTITION1.getCity(), "new street");
repository.update(updatedAddress, updatedAddress.getCity());
final Address address = repository.findOne(updatedAddress.getPostalCode(), updatedAddress.getCity());
assertThat(address.getStreet()).isEqualTo(updatedAddress.getStreet());
assertThat(address.getPostalCode()).isEqualTo(updatedAddress.getPostalCode());
}
}

Просмотреть файл

@ -0,0 +1,36 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository;
import org.springframework.data.annotation.Id;
public class Contact {
@Id
private String logicId;
private String title;
public Contact(String id, String title) {
this.logicId = id;
this.title = title;
}
public String getLogicId() {
return logicId;
}
public void setLogicId(String logicId) {
this.logicId = logicId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}

Просмотреть файл

@ -0,0 +1,12 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository;
import org.springframework.stereotype.Repository;
@Repository
public interface ContactRepository extends DocumentDbRepository<Contact, String> {
}

Просмотреть файл

@ -0,0 +1,36 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository;
import com.microsoft.azure.documentdb.ConnectionPolicy;
import com.microsoft.azure.documentdb.ConsistencyLevel;
import com.microsoft.azure.documentdb.DocumentClient;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.config.AbstractDocumentDbConfiguration;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.config.EnableDocumentDbRepositories;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource(value = {"classpath:application.properties"})
@EnableDocumentDbRepositories
public class ContactRepositoryConfig extends AbstractDocumentDbConfiguration {
@Value("${documentdb.uri}")
String dbUri;
@Value("${documentdb.key}")
String dbKey;
@Override
public DocumentClient documentClient() {
return new DocumentClient(dbUri, dbKey, ConnectionPolicy.GetDefault(), ConsistencyLevel.Session);
}
@Override
public String getDatabase() {
return "itdb";
}
}

Просмотреть файл

@ -0,0 +1,102 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository;
import org.junit.After;
import org.junit.Before;
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 java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ContactRepositoryConfig.class)
public class ContactRepositoryIT {
private static final Contact TEST_CONTACT = new Contact("testId", "faketitle");
@Autowired
ContactRepository repository;
@Before
public void setup() {
repository.save(TEST_CONTACT);
}
@After
public void cleanup() {
repository.deleteAll();
}
@Test
public void testFindAll() {
final List<Contact> result = repository.findAll();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getLogicId()).isEqualTo(TEST_CONTACT.getLogicId());
assertThat(result.get(0).getTitle()).isEqualTo(TEST_CONTACT.getTitle());
final Contact contact = repository.findOne(TEST_CONTACT.getLogicId());
assertThat(contact.getLogicId()).isEqualTo(TEST_CONTACT.getLogicId());
assertThat(contact.getTitle()).isEqualTo(TEST_CONTACT.getTitle());
}
@Test
public void testCountAndDeleteByID() {
final Contact contact2 = new Contact("newid", "newtitle");
repository.save(contact2);
final List<Contact> all = repository.findAll();
assertThat(all.size()).isEqualTo(2);
long count = repository.count();
assertThat(count).isEqualTo(2);
repository.delete(contact2.getLogicId());
final List<Contact> result = repository.findAll();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getLogicId()).isEqualTo(TEST_CONTACT.getLogicId());
assertThat(result.get(0).getTitle()).isEqualTo(TEST_CONTACT.getTitle());
count = repository.count();
assertThat(count).isEqualTo(1);
}
@Test
public void testCountAndDeleteEntity() {
final Contact contact2 = new Contact("newid", "newtitle");
repository.save(contact2);
final List<Contact> all = repository.findAll();
assertThat(all.size()).isEqualTo(2);
repository.delete(contact2);
final List<Contact> result = repository.findAll();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getLogicId()).isEqualTo(TEST_CONTACT.getLogicId());
assertThat(result.get(0).getTitle()).isEqualTo(TEST_CONTACT.getTitle());
}
@Test
public void testUpdateEntity() {
final Contact updatedContact = new Contact(TEST_CONTACT.getLogicId(), "updated");
repository.update(updatedContact);
final Contact contact = repository.findOne(TEST_CONTACT.getLogicId());
assertThat(contact.getLogicId()).isEqualTo(updatedContact.getLogicId());
assertThat(contact.getTitle()).isEqualTo(updatedContact.getTitle());
}
}

Просмотреть файл

@ -0,0 +1,82 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.DocumentDbOperations;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Person;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support.DocumentDbEntityInformation;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support.SimpleDocumentDbRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class SimpleDocumentDbRepositoryUnitTest {
private static final Person TEST_PERSON = new Person("aaa", "firstname", "lastname");
SimpleDocumentDbRepository<Person, String> repository;
@Mock
DocumentDbOperations dbOperations;
@Mock
DocumentDbEntityInformation<Person, String> entityInformation;
@Before
public void setUp() {
when(entityInformation.getJavaType()).thenReturn(Person.class);
when(entityInformation.getCollectionName()).thenReturn(Person.class.getSimpleName());
when(entityInformation.getPartitionKeyFieldName()).thenReturn("lastName");
when(entityInformation.getRequestUint()).thenReturn(1000);
when(dbOperations.findAll(anyString(), any(), anyString(), anyString()))
.thenReturn(Arrays.asList(TEST_PERSON));
repository = new SimpleDocumentDbRepository<Person, String>(entityInformation, dbOperations);
}
@Test
public void testSave() {
repository.save(TEST_PERSON);
assertEquals(1, repository.findAll(TEST_PERSON.getLastName()).size());
assertEquals(TEST_PERSON.getFirstName(), repository.findAll(TEST_PERSON.getLastName()).get(0).getFirstName());
}
@Test
public void testFindOne() {
when(dbOperations.findById(anyString(), any(), any(), anyString())).thenReturn(TEST_PERSON);
repository.save(TEST_PERSON);
final Person result = repository.findOne(TEST_PERSON.getId(), TEST_PERSON.getLastName());
assertEquals(result.getId(), TEST_PERSON.getId());
assertEquals(result.getFirstName(), TEST_PERSON.getFirstName());
assertEquals(result.getLastName(), TEST_PERSON.getLastName());
}
@Test
public void testUpdate() {
final Person updatedPerson = new Person(TEST_PERSON.getId(), "updated", "updated");
repository.update(updatedPerson);
when(dbOperations.findById(anyString(), any(), any(), anyString())).thenReturn(updatedPerson);
final Person result = repository.findOne(TEST_PERSON.getId(), TEST_PERSON.getLastName());
assertEquals(result.getId(), updatedPerson.getId());
assertEquals(result.getFirstName(), updatedPerson.getFirstName());
assertEquals(result.getLastName(), updatedPerson.getLastName());
}
}

Просмотреть файл

@ -0,0 +1,57 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.config;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.DocumentDbRepository;
import org.junit.Test;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfiguration;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import java.util.Collection;
import static org.assertj.core.api.Assertions.fail;
public class DocumentDbRepositoryConfigurationExtensionUnitTest {
StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(Config.class, true);
ResourceLoader loader = new PathMatchingResourcePatternResolver();
Environment environment = new StandardEnvironment();
RepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(metadata,
EnableDocumentDbRepositories.class, loader, environment);
private static void assertHashRepo(Class<?> repositoryInterface,
Collection<RepositoryConfiguration<RepositoryConfigurationSource>> configs) {
for (final RepositoryConfiguration<?> config : configs) {
if (config.getRepositoryInterface().equals(repositoryInterface.getName())) {
return;
}
}
fail("expected to find config for repository interface "
+ repositoryInterface.getName() + ", but got: " + configs.toString());
}
@Test
public void isStrictMatchIfRepositoryExtendsStoreSpecificBase() {
final DocumentDbRepositoryConfigurationExtension extension = new DocumentDbRepositoryConfigurationExtension();
assertHashRepo(TestRepository.class, extension.getRepositoryConfigurations(configurationSource, loader, true));
}
interface TestRepository extends DocumentDbRepository<Object, String> {
}
@EnableDocumentDbRepositories(considerNestedRepositories = true)
static class Config {
}
}

Просмотреть файл

@ -0,0 +1,59 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.Document;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Person;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class DocumentDbEntityInformationUnitTest {
@Test
public void testGetId() {
final Person testPerson = new Person("test", "test", "test");
final DocumentDbEntityInformation<Person, String> entityInformation =
new DocumentDbEntityInformation<Person, String>(Person.class);
final String idField = entityInformation.getId(testPerson);
assertThat(idField).isEqualTo(testPerson.getId());
}
@Test
public void testGetIdType() {
final DocumentDbEntityInformation<Person, String> entityInformation =
new DocumentDbEntityInformation<Person, String>(Person.class);
final Class<?> idType = entityInformation.getIdType();
assertThat(idType.getSimpleName()).isEqualTo(String.class.getSimpleName());
}
@Test
public void testGetCollectionName() {
final DocumentDbEntityInformation<Person, String> entityInformation =
new DocumentDbEntityInformation<Person, String>(Person.class);
final String collectionName = entityInformation.getCollectionName();
assertThat(collectionName).isEqualTo(Person.class.getSimpleName());
}
@Test
public void testCustomCollectionName() {
final DocumentDbEntityInformation<Volunteer, String> entityInformation =
new DocumentDbEntityInformation<Volunteer, String>(Volunteer.class);
final String collectionName = entityInformation.getCollectionName();
assertThat(collectionName).isEqualTo("testCollection");
}
@Document(collection = "testCollection")
class Volunteer {
String id;
String name;
}
}

Просмотреть файл

@ -0,0 +1,21 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.PersonRepository;
import org.junit.Test;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import static org.assertj.core.api.Assertions.assertThat;
public class DocumentDbRepositoryFactoryBeanUnitTest {
@Test
public void testCreateRepositoryFactory() {
final DocumentDbRepositoryFactoryBean factoryBean = new DocumentDbRepositoryFactoryBean(PersonRepository.class);
final RepositoryFactorySupport factory = factoryBean.createRepositoryFactory();
assertThat(factory).isNotNull();
}
}

Просмотреть файл

@ -0,0 +1,39 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for
* license information.
*/
package com.microsoft.azure.spring.data.cosmosdb.documentdb.repository.support;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.core.mapping.DocumentDbPersistentEntity;
import com.microsoft.azure.spring.data.cosmosdb.documentdb.domain.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.core.EntityInformation;
import static org.junit.Assert.assertTrue;
@RunWith(MockitoJUnitRunner.class)
public class DocumentDbRepositoryFactoryUnitTest {
@Mock
MappingContext mappingContext;
@Mock
DocumentDbPersistentEntity entity;
@Autowired
ApplicationContext applicationContext;
@Test
public void useMappingDocumentDBEntityInfoIfMappingContextSet() {
final DocumentDbRepositoryFactory factory = new DocumentDbRepositoryFactory(applicationContext);
final EntityInformation<Person, String> entityInfo = factory.getEntityInformation(Person.class);
assertTrue(entityInfo instanceof DocumentDbEntityInformation);
}
}

Просмотреть файл

@ -0,0 +1,4 @@
#Mon, 07 Aug 2017 11:09:48 +0800
#test properties for documentdb emulator, from https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator
documentdb.key=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
documentdb.uri=${DOCUMENTDB_URI}