Merge branch 'master' of https://github.com/thombergs/code-examples into circuitbreaker
This commit is contained in:
117
aws/cdk/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
117
aws/cdk/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2007-present the original author or authors.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.6";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
aws/cdk/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
aws/cdk/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
aws/cdk/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
aws/cdk/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
||||
0
aws/cdk/mvnw
vendored
Normal file
0
aws/cdk/mvnw
vendored
Normal file
182
aws/cdk/mvnw.cmd
vendored
Normal file
182
aws/cdk/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
@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 Maven 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 keystroke 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 set title of command window
|
||||
title %0
|
||||
@REM enable echoing by 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
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
|
||||
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%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%
|
||||
23
aws/cdk/src/main/java/com/myorg/SecondStack.java
Normal file
23
aws/cdk/src/main/java/com/myorg/SecondStack.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package com.myorg;
|
||||
|
||||
import software.amazon.awscdk.core.Construct;
|
||||
import software.amazon.awscdk.core.Stack;
|
||||
import software.amazon.awscdk.core.StackProps;
|
||||
import software.amazon.awscdk.services.s3.Bucket;
|
||||
|
||||
public class SecondStack extends Stack {
|
||||
public SecondStack(final Construct scope, final String id) {
|
||||
this(scope, id, null);
|
||||
}
|
||||
|
||||
public SecondStack(final Construct scope, final String id, final StackProps props) {
|
||||
super(scope, id, props);
|
||||
|
||||
String bucketName = (String) this.getNode().tryGetContext("bucketName2");
|
||||
|
||||
Bucket bucket = Bucket.Builder.create(this, "bucket")
|
||||
.bucketName(bucketName)
|
||||
.build();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,9 @@ if [[ "$MODULE" == "module5" ]]
|
||||
then
|
||||
# ADD NEW MODULES HERE
|
||||
# (add new modules above the rest so you get quicker feedback if it fails)
|
||||
build_gradle_module "spring-boot/spring-boot-mocking-modules"
|
||||
build_gradle_module "spring-boot/specification"
|
||||
build_gradle_module "spring-boot/hibernate-search"
|
||||
build_maven_module "core-java/streams/fileswithstreams"
|
||||
build_maven_module "spring-boot/spring-boot-health-check"
|
||||
build_maven_module "spring-boot/spring-boot-logging-2"
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
{
|
||||
"provider": {
|
||||
"name": "customerServiceProvider"
|
||||
},
|
||||
"consumer": {
|
||||
"name": "addressClient"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"description": "a request to the address collection resource",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"path": "/addresses/"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"Content-Type": "application/hal+json"
|
||||
},
|
||||
"body": {
|
||||
"_embedded": {
|
||||
"addresses": [
|
||||
{
|
||||
"street": "Elm Street",
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "http://localhost:8080/addresses/1"
|
||||
},
|
||||
"address": {
|
||||
"href": "http://localhost:8080/addresses/1"
|
||||
},
|
||||
"customer": {
|
||||
"href": "http://localhost:8080/addresses/1/customer"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"street": "High Street",
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "http://localhost:8080/addresses/2"
|
||||
},
|
||||
"address": {
|
||||
"href": "http://localhost:8080/addresses/2"
|
||||
},
|
||||
"customer": {
|
||||
"href": "http://localhost:8080/addresses/2/customer"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "http://localhost:8080/addresses{?page,size,sort}",
|
||||
"templated": true
|
||||
},
|
||||
"profile": {
|
||||
"href": "http://localhost:8080/profile/addresses"
|
||||
},
|
||||
"search": {
|
||||
"href": "http://localhost:8080/addresses/search"
|
||||
}
|
||||
},
|
||||
"page": {
|
||||
"size": 20,
|
||||
"totalElements": 2,
|
||||
"totalPages": 1,
|
||||
"number": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"providerStates": [
|
||||
{
|
||||
"name": "a collection of 2 addresses"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "a request to the address resource",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"path": "/addresses/1"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"Content-Type": "application/hal+json"
|
||||
},
|
||||
"body": {
|
||||
"street": "Elm Street",
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "http://localhost:8080/addresses/1"
|
||||
},
|
||||
"address": {
|
||||
"href": "http://localhost:8080/addresses/1"
|
||||
},
|
||||
"customer": {
|
||||
"href": "http://localhost:8080/addresses/1/customer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"providerStates": [
|
||||
{
|
||||
"name": "a single address"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"pact-specification": {
|
||||
"version": "3.0.0"
|
||||
},
|
||||
"pact-jvm": {
|
||||
"version": "3.5.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
{
|
||||
"provider": {
|
||||
"name": "userservice"
|
||||
},
|
||||
"consumer": {
|
||||
"name": "userclient"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"description": "a request to PUT a person",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"path": "/user-service/users/42"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"firstName": "Zaphod",
|
||||
"lastName": "Beeblebrox"
|
||||
},
|
||||
"matchingRules": {
|
||||
"body": {
|
||||
"$.firstName": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
},
|
||||
"$.lastName": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"Content-Type": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "regex",
|
||||
"regex": "application/json"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"providerStates": [
|
||||
{
|
||||
"name": "person 42 exists"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "a request to POST a person",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"path": "/user-service/users"
|
||||
},
|
||||
"response": {
|
||||
"status": 201,
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"id": 42
|
||||
},
|
||||
"matchingRules": {
|
||||
"header": {
|
||||
"Content-Type": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "regex",
|
||||
"regex": "application/json"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"$.id": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "integer"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"providerStates": [
|
||||
{
|
||||
"name": "provider accepts a new person"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"pactSpecification": {
|
||||
"version": "3.0.0"
|
||||
},
|
||||
"pact-jvm": {
|
||||
"version": "3.5.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
{
|
||||
"consumer": {
|
||||
"name": "userclient"
|
||||
},
|
||||
"provider": {
|
||||
"name": "userservice"
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"description": "a user created message",
|
||||
"metaData": {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
"contents": {
|
||||
"messageUuid": "string",
|
||||
"user": {
|
||||
"id": 42,
|
||||
"name": "Zaphod Beeblebrox"
|
||||
}
|
||||
},
|
||||
"matchingRules": {
|
||||
"body": {
|
||||
"$.messageUuid": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
},
|
||||
"$.user.id": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "number"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
},
|
||||
"$.user.name": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"pactSpecification": {
|
||||
"version": "3.0.0"
|
||||
},
|
||||
"pact-jvm": {
|
||||
"version": "3.5.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
spring-boot/hibernate-search/README.md
Normal file
5
spring-boot/hibernate-search/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Hibernate Search Tutorial
|
||||
This example code demonstrates the following:
|
||||
* How to configure Hibernate search with Elasticsearch integration
|
||||
* How to configure entities for indexing
|
||||
* Some examples to queries
|
||||
40
spring-boot/hibernate-search/build.gradle
Normal file
40
spring-boot/hibernate-search/build.gradle
Normal file
@@ -0,0 +1,40 @@
|
||||
plugins {
|
||||
id 'org.springframework.boot' version '2.2.2.RELEASE'
|
||||
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'io.reflectoring'
|
||||
version = '1.0.0'
|
||||
sourceCompatibility = '11'
|
||||
|
||||
configurations {
|
||||
compileOnly {
|
||||
extendsFrom annotationProcessor
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.hibernate:hibernate-search-orm:5.11.5.Final'
|
||||
implementation 'org.hibernate:hibernate-search-elasticsearch:5.11.5.Final'
|
||||
implementation 'org.mapstruct:mapstruct:1.3.1.Final'
|
||||
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.mapstruct:mapstruct-processor:1.3.1.Final'
|
||||
|
||||
testImplementation('org.springframework.boot:spring-boot-starter-test') {
|
||||
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
BIN
spring-boot/hibernate-search/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
spring-boot/hibernate-search/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
spring-boot/hibernate-search/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
spring-boot/hibernate-search/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Mon Sep 07 12:46:19 IST 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
184
spring-boot/hibernate-search/gradlew
vendored
Normal file
184
spring-boot/hibernate-search/gradlew
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
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
|
||||
SAVED="$(pwd)"
|
||||
cd "$(dirname \"$PRG\")/" >/dev/null
|
||||
APP_HOME="$(pwd -P)"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=$(basename "$0")
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn() {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die() {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$(uname)" in
|
||||
CYGWIN*)
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin*)
|
||||
darwin=true
|
||||
;;
|
||||
MINGW*)
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP*)
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
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
|
||||
if [ ! -x "$JAVACMD" ]; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ]; then
|
||||
MAX_FD_LIMIT=$(ulimit -H -n)
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ]; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ]; then
|
||||
APP_HOME=$(cygpath --path --mixed "$APP_HOME")
|
||||
CLASSPATH=$(cygpath --path --mixed "$CLASSPATH")
|
||||
|
||||
JAVACMD=$(cygpath --unix "$JAVACMD")
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=$(find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ]; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@"; do
|
||||
CHECK=$(echo "$arg" | egrep -c "$OURCYGPATTERN" -)
|
||||
CHECK2=$(echo "$arg" | egrep -c "^-") ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ]; then ### Added a condition
|
||||
eval $(echo args$i)=$(cygpath --path --ignore --mixed "$arg")
|
||||
else
|
||||
eval $(echo args$i)="\"$arg\""
|
||||
fi
|
||||
i=$(expr $i + 1)
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save() {
|
||||
for i; do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
104
spring-boot/hibernate-search/gradlew.bat
vendored
Normal file
104
spring-boot/hibernate-search/gradlew.bat
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
1
spring-boot/hibernate-search/settings.gradle
Normal file
1
spring-boot/hibernate-search/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'hibernate-search'
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.reflectoring.hibernatesearch;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class HibernateSearchApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HibernateSearchApplication.class, args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.reflectoring.hibernatesearch.configuration;
|
||||
|
||||
import io.reflectoring.hibernatesearch.service.IndexingService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class StartupEvent implements ApplicationListener<ApplicationReadyEvent> {
|
||||
|
||||
private final IndexingService service;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
try {
|
||||
service.initiateIndexing();
|
||||
} catch (InterruptedException e) {
|
||||
log.error("Failed to reindex entities ",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package io.reflectoring.hibernatesearch.controller;
|
||||
|
||||
import io.reflectoring.hibernatesearch.controller.dto.PostResponse;
|
||||
import io.reflectoring.hibernatesearch.controller.dto.UserResponse;
|
||||
import io.reflectoring.hibernatesearch.controller.mapper.PostMapper;
|
||||
import io.reflectoring.hibernatesearch.controller.mapper.UserMapper;
|
||||
import io.reflectoring.hibernatesearch.service.IndexingService;
|
||||
import io.reflectoring.hibernatesearch.service.SearchService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
class IndexController {
|
||||
private final IndexingService indexingService;
|
||||
private final SearchService searchService;
|
||||
private final PostMapper postMapper;
|
||||
private final UserMapper userMapper;
|
||||
|
||||
@PostMapping("/reindex")
|
||||
public void reindex() throws InterruptedException {
|
||||
indexingService.initiateIndexing();
|
||||
}
|
||||
|
||||
@GetMapping("/user")
|
||||
public List<UserResponse> getUser(@RequestParam String first,
|
||||
@RequestParam Integer max,
|
||||
@RequestParam Integer page){
|
||||
return searchService.getUserByFirst(first, max, page)
|
||||
.stream().map(userMapper::toResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/user/projection")
|
||||
public List<UserResponse> getProjectUser(@RequestParam String first,
|
||||
@RequestParam Integer max,
|
||||
@RequestParam Integer page){
|
||||
return searchService.getUserByFirstWithProjection(first, max, page)
|
||||
.stream().map(userMapper::toResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/post")
|
||||
public List<PostResponse> getPost(@RequestParam Long likeCount,
|
||||
@RequestParam(required = false) String hashTags,
|
||||
@RequestParam(required = false) String tag){
|
||||
return searchService.getBasedOnLikeCountTags(likeCount, hashTags, tag)
|
||||
.stream().map(postMapper::toResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/post/word")
|
||||
public List<PostResponse> getPostByWord(@RequestParam String word){
|
||||
return searchService.getPostBasedOnWord(word)
|
||||
.stream().map(postMapper::toResponse).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.reflectoring.hibernatesearch.controller.dto;
|
||||
|
||||
import io.reflectoring.hibernatesearch.domain.Tag;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PostResponse {
|
||||
private String id;
|
||||
private String body;
|
||||
private UserResponse user;
|
||||
private Tag tag;
|
||||
private String imageUrl;
|
||||
private String imageDescription;
|
||||
private String hashTags;
|
||||
private long likeCount;
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.reflectoring.hibernatesearch.controller.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class UserResponse {
|
||||
private String id;
|
||||
private String first;
|
||||
private String middle;
|
||||
private String last;
|
||||
private Integer age;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.reflectoring.hibernatesearch.controller.mapper;
|
||||
|
||||
import io.reflectoring.hibernatesearch.controller.dto.PostResponse;
|
||||
import io.reflectoring.hibernatesearch.domain.Post;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
@Mapper(componentModel = "spring", uses = UserMapper.class)
|
||||
public interface PostMapper {
|
||||
PostResponse toResponse(Post post);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.reflectoring.hibernatesearch.controller.mapper;
|
||||
|
||||
import io.reflectoring.hibernatesearch.controller.dto.UserResponse;
|
||||
import io.reflectoring.hibernatesearch.domain.User;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface UserMapper {
|
||||
UserResponse toResponse(User user);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package io.reflectoring.hibernatesearch.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.lucene.analysis.core.LowerCaseFilterFactory;
|
||||
import org.hibernate.search.annotations.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Indexed(index = "idx_post")
|
||||
@NormalizerDef(name = "lower",
|
||||
filters = @TokenFilterDef(factory = LowerCaseFilterFactory.class))
|
||||
public class Post {
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Field(name = "body")
|
||||
@Field(name = "bodyFiltered", analyzer = @Analyzer(definition = "stop"))
|
||||
private String body;
|
||||
|
||||
@ManyToOne
|
||||
@IndexedEmbedded
|
||||
private User user;
|
||||
|
||||
@Field(normalizer = @Normalizer(definition = "lower"))
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Tag tag;
|
||||
|
||||
private String imageUrl;
|
||||
|
||||
private String imageDescription;
|
||||
|
||||
@Field
|
||||
private String hashTags;
|
||||
|
||||
@Field
|
||||
@SortableField
|
||||
private long likeCount;
|
||||
|
||||
@Field(analyze = Analyze.NO)
|
||||
@SortableField
|
||||
private LocalDateTime createdAt;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.reflectoring.hibernatesearch.domain;
|
||||
|
||||
public enum Tag {
|
||||
MOVIE,
|
||||
MUSIC,
|
||||
LITERATURE
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.reflectoring.hibernatesearch.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.search.annotations.*;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Indexed(index = "idx_user")
|
||||
public class User {
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Field(store = Store.YES)
|
||||
@Field(name = "fullName")
|
||||
private String first;
|
||||
|
||||
@Field(index = Index.NO, store = Store.YES)
|
||||
private String middle;
|
||||
|
||||
@Field(store = Store.YES)
|
||||
@Field(name = "fullName")
|
||||
private String last;
|
||||
|
||||
@Field
|
||||
private Integer age;
|
||||
|
||||
@ContainedIn
|
||||
@OneToMany(mappedBy = "user")
|
||||
private List<Post> post;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package io.reflectoring.hibernatesearch.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.search.jpa.FullTextEntityManager;
|
||||
import org.hibernate.search.jpa.Search;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class IndexingService {
|
||||
|
||||
private final EntityManager em;
|
||||
|
||||
@Transactional
|
||||
public void initiateIndexing() throws InterruptedException {
|
||||
log.info("Initiating indexing...");
|
||||
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
|
||||
fullTextEntityManager.createIndexer().startAndWait();
|
||||
log.info("All entities indexed");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.reflectoring.hibernatesearch.service;
|
||||
|
||||
import io.reflectoring.hibernatesearch.domain.Post;
|
||||
import io.reflectoring.hibernatesearch.domain.User;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.hibernate.search.jpa.FullTextEntityManager;
|
||||
import org.hibernate.search.jpa.FullTextQuery;
|
||||
import org.hibernate.search.jpa.Search;
|
||||
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class SearchService {
|
||||
private final EntityManager entityManager;
|
||||
|
||||
public List<Post> getBasedOnLikeCountTags(Long likeCount, String hashTags, String tag){
|
||||
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
|
||||
QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder()
|
||||
.forEntity(Post.class)
|
||||
.get();
|
||||
Query likeCountGreater = qb.range().onField("likeCount").above(likeCount).createQuery();
|
||||
Query hashTagsQuery = qb.keyword().onField("hashTags").matching(hashTags).createQuery();
|
||||
Query tagQuery = qb.keyword().onField("tag").matching(tag).createQuery();
|
||||
Query finalQuery = qb.bool().must(likeCountGreater).should(tagQuery).should(hashTagsQuery).createQuery();
|
||||
|
||||
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(finalQuery, Post.class);
|
||||
fullTextQuery.setSort(qb.sort().byScore().createSort());
|
||||
return (List<Post>) fullTextQuery.getResultList();
|
||||
}
|
||||
|
||||
public List<Post> getPostBasedOnWord(String word){
|
||||
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
|
||||
QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder()
|
||||
.forEntity(Post.class)
|
||||
.get();
|
||||
Query foodQuery = qb.keyword().onFields("bodyFiltered","hashTags").matching(word).createQuery();
|
||||
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(foodQuery, Post.class);
|
||||
return (List<Post>) fullTextQuery.getResultList();
|
||||
}
|
||||
|
||||
public List<User> getUserByFirst(String first, int max, int page){
|
||||
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
|
||||
QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder()
|
||||
.forEntity(User.class)
|
||||
.get();
|
||||
Query similarToUser = qb.keyword().wildcard().onField("first")
|
||||
.matching(first).createQuery();
|
||||
Query finalQuery = qb.bool().must(similarToUser).createQuery();
|
||||
|
||||
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(finalQuery, User.class);
|
||||
fullTextQuery.setSort(qb.sort().byField("age").desc().andByScore().createSort());
|
||||
fullTextQuery.setMaxResults(max);
|
||||
fullTextQuery.setFirstResult(page);
|
||||
return (List<User>) fullTextQuery.getResultList();
|
||||
}
|
||||
|
||||
public List<User> getUserByFirstWithProjection(String first, int max, int page){
|
||||
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
|
||||
QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder()
|
||||
.forEntity(User.class)
|
||||
.get();
|
||||
Query similarToUser = qb.keyword().fuzzy().withEditDistanceUpTo(2).onField("first")
|
||||
.matching(first).createQuery();
|
||||
Query finalQuery = qb.bool().must(similarToUser).createQuery();
|
||||
|
||||
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(finalQuery, User.class);
|
||||
fullTextQuery.setProjection(FullTextQuery.ID, "first","last","middle","age");
|
||||
fullTextQuery.setSort(qb.sort().byField("age").desc().andByScore().createSort());
|
||||
fullTextQuery.setMaxResults(max);
|
||||
fullTextQuery.setFirstResult(page);
|
||||
return getUserList(fullTextQuery.getResultList());
|
||||
}
|
||||
|
||||
private List<User> getUserList(List<Object[]> resultList) {
|
||||
List<User> users = new ArrayList<>();
|
||||
for (Object[] objects : resultList) {
|
||||
User user = new User();
|
||||
user.setId((String) objects[0]);
|
||||
user.setFirst((String) objects[1]);
|
||||
user.setLast((String) objects[2]);
|
||||
user.setMiddle((String) objects[3]);
|
||||
user.setAge((Integer) objects[4]);
|
||||
users.add(user);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
spring:
|
||||
jpa:
|
||||
show-sql: true
|
||||
generate-ddl: true
|
||||
hibernate:
|
||||
ddl-auto: create-drop
|
||||
properties:
|
||||
hibernate:
|
||||
search:
|
||||
default:
|
||||
indexmanager: elasticsearch
|
||||
elasticsearch:
|
||||
host: http://192.168.0.103:9200
|
||||
index_schema_management_strategy: drop-and-create
|
||||
required_index_status: yellow
|
||||
47
spring-boot/hibernate-search/src/main/resources/data.sql
Normal file
47
spring-boot/hibernate-search/src/main/resources/data.sql
Normal file
@@ -0,0 +1,47 @@
|
||||
insert into user (id, first, last, middle, age) values ( 'c_1', 'John', 'Doe', 'Maven' , 31);
|
||||
insert into user (id, first, last, middle, age) values ( 'c_2', 'Jane', 'Dove', 'Gradle', 41);
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_1', 'The tattered work gloves speak of the many hours of hard labor he endured throughout his life', now(),
|
||||
'#work#labour', 'Office', 'uri://sample1', 20, 'LITERATURE', 'c_1' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_2', 'Dolores wouldn''t have eaten the meal if she had known what it actually was.', now(),
|
||||
'#food', 'Office', 'uri://sample1', 7686, 'MUSIC', 'c_1' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_3', 'It caught him off guard that space smelled of seared steak.', now(),
|
||||
'#food#stale#caughtinact', 'Office', 'uri://sample1', 1234, 'LITERATURE', 'c_1' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_4', '25 years later, she still regretted that specific moment.', now(),
|
||||
'#ages', 'Office', 'uri://sample1', 679, 'MOVIE', 'c_1' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_5', 'She had a habit of taking showers in lemonade.', now(),
|
||||
'#bath', 'Office', 'uri://sample1', 23, 'LITERATURE', 'c_1' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_6', 'She is never happy until she finds something to be unhappy about; then, she is overjoyed.', now(),
|
||||
'#feelings', 'Office', 'uri://sample1', 4569877, 'MOVIE', 'c_2' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_7', 'They throw cabbage that turns your brain into emotional baggage.', now(),
|
||||
'#food', 'Office', 'uri://sample1', 1000, 'MUSIC', 'c_2' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_8', 'There''s a message for you if you look up.', now(),
|
||||
'#message', 'Office', 'uri://sample1', 20, 'LITERATURE', 'c_2' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_9', 'Please wait outside of the house.', now(),
|
||||
'#house#labour', 'Office', 'uri://sample1', 40, 'MUSIC', 'c_2' );
|
||||
|
||||
insert into post (id, body, created_at, hash_tags, image_description, image_url, like_count, tag, user_id)
|
||||
values ( 'p_10', 'Honestly, I didn''t care much for the first season, so I didn''t bother with the second.', now(),
|
||||
'#honest#season#time', 'Office', 'uri://sample1', 20000, 'MOVIE', 'c_2' );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
34
spring-boot/specification/.gitignore
vendored
Normal file
34
spring-boot/specification/.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
4
spring-boot/specification/README.md
Normal file
4
spring-boot/specification/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Intro to specification Tutorial
|
||||
This example code demonstrates the following:
|
||||
* How to write queries with Specification
|
||||
* How to generate type safe queries dynamically with Specification
|
||||
35
spring-boot/specification/build.gradle
Normal file
35
spring-boot/specification/build.gradle
Normal file
@@ -0,0 +1,35 @@
|
||||
plugins {
|
||||
id 'org.springframework.boot' version '2.3.4.RELEASE'
|
||||
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'io.reflectoring'
|
||||
version = '1.0.0'
|
||||
sourceCompatibility = '11'
|
||||
|
||||
configurations {
|
||||
compileOnly {
|
||||
extendsFrom annotationProcessor
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.hibernate:hibernate-jpamodelgen'
|
||||
testImplementation('org.springframework.boot:spring-boot-starter-test') {
|
||||
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
BIN
spring-boot/specification/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
spring-boot/specification/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
spring-boot/specification/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
spring-boot/specification/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Sun Oct 18 17:44:53 IST 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
184
spring-boot/specification/gradlew
vendored
Normal file
184
spring-boot/specification/gradlew
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
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
|
||||
SAVED="$(pwd)"
|
||||
cd "$(dirname \"$PRG\")/" >/dev/null
|
||||
APP_HOME="$(pwd -P)"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=$(basename "$0")
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn() {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die() {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$(uname)" in
|
||||
CYGWIN*)
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin*)
|
||||
darwin=true
|
||||
;;
|
||||
MINGW*)
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP*)
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
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
|
||||
if [ ! -x "$JAVACMD" ]; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ]; then
|
||||
MAX_FD_LIMIT=$(ulimit -H -n)
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ]; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ]; then
|
||||
APP_HOME=$(cygpath --path --mixed "$APP_HOME")
|
||||
CLASSPATH=$(cygpath --path --mixed "$CLASSPATH")
|
||||
|
||||
JAVACMD=$(cygpath --unix "$JAVACMD")
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=$(find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ]; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@"; do
|
||||
CHECK=$(echo "$arg" | egrep -c "$OURCYGPATTERN" -)
|
||||
CHECK2=$(echo "$arg" | egrep -c "^-") ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ]; then ### Added a condition
|
||||
eval $(echo args$i)=$(cygpath --path --ignore --mixed "$arg")
|
||||
else
|
||||
eval $(echo args$i)="\"$arg\""
|
||||
fi
|
||||
i=$(expr $i + 1)
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save() {
|
||||
for i; do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
spring-boot/specification/gradlew.bat
vendored
Normal file
89
spring-boot/specification/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
1
spring-boot/specification/settings.gradle
Normal file
1
spring-boot/specification/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'specification'
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.reflectoring.specification;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpecificationApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpecificationApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package io.reflectoring.specification.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
public class Address {
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String line1;
|
||||
|
||||
private String line2;
|
||||
|
||||
private String city;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private STATE state;
|
||||
|
||||
private String pincode;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.reflectoring.specification.model;
|
||||
|
||||
public enum Category {
|
||||
MOBILE,
|
||||
TV_APPLIANCES,
|
||||
MEN_FASHION,
|
||||
WOMEN_FASHION,
|
||||
BOOKS,
|
||||
BEAUTY
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.reflectoring.specification.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
public class Distributor {
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToOne
|
||||
private Address address;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package io.reflectoring.specification.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
public class Product {
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Double price;
|
||||
|
||||
private LocalDateTime manufacturingDate;
|
||||
|
||||
@ManyToOne
|
||||
private Address manufacturingPlace;
|
||||
|
||||
private Double weight;
|
||||
|
||||
@Embedded
|
||||
private Dimension dimension;
|
||||
|
||||
@ManyToOne
|
||||
private Distributor distributor;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Category category;
|
||||
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public static class Dimension {
|
||||
private Double height;
|
||||
|
||||
private Double width;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package io.reflectoring.specification.model;
|
||||
|
||||
public enum STATE {
|
||||
TEXAS,
|
||||
CALIFORNIA
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package io.reflectoring.specification.repository;
|
||||
|
||||
import io.reflectoring.specification.model.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.data.jpa.domain.Specification.where;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CustomProductRepository {
|
||||
private static final Double PREMIUM_PRICE = 1000D;
|
||||
private final ProductRepository productRepository;
|
||||
|
||||
public List<Product> getLowRangeProducts(List<Category> categories) {
|
||||
return productRepository.findAll(where(belongsToCategory(categories)).and(pricesAreBetween(0D, PREMIUM_PRICE)));
|
||||
}
|
||||
|
||||
public List<Product> getPremiumProducts(List<Category> categories) {
|
||||
return productRepository.findAll(
|
||||
where(belongsToCategory(categories)).and(isPremium()));
|
||||
}
|
||||
|
||||
public List<Product> getPremiumProducts(String name, List<Category> categories) {
|
||||
return productRepository.findAll(
|
||||
where(belongsToCategory(categories))
|
||||
.and(nameLike(name))
|
||||
.and(isPremium()));
|
||||
}
|
||||
|
||||
|
||||
public List<Product> getQueryResult(List<Filter> filters){
|
||||
if(filters.size()>0) {
|
||||
return productRepository.findAll(getSpecificationFromFilters(filters));
|
||||
}else {
|
||||
return productRepository.findAll();
|
||||
}
|
||||
}
|
||||
|
||||
private Specification<Product> getSpecificationFromFilters(List<Filter> filter) {
|
||||
Specification<Product> specification = where(createSpecification(filter.remove(0)));
|
||||
for (Filter input : filter) {
|
||||
specification = specification.and(createSpecification(input));
|
||||
}
|
||||
return specification;
|
||||
}
|
||||
|
||||
private Specification<Product> createSpecification(Filter input) {
|
||||
switch (input.getOperator()){
|
||||
case EQUALS:
|
||||
return (root, query, criteriaBuilder) ->
|
||||
criteriaBuilder.equal(root.get(input.getField()),
|
||||
castToRequiredType(root.get(input.getField()).getJavaType(), input.getValue()));
|
||||
case NOT_EQ:
|
||||
return (root, query, criteriaBuilder) ->
|
||||
criteriaBuilder.notEqual(root.get(input.getField()),
|
||||
castToRequiredType(root.get(input.getField()).getJavaType(), input.getValue()));
|
||||
case GREATER_THAN:
|
||||
return (root, query, criteriaBuilder) ->
|
||||
criteriaBuilder.gt(root.get(input.getField()),
|
||||
(Number) castToRequiredType(root.get(input.getField()).getJavaType(), input.getValue()));
|
||||
case LESS_THAN:
|
||||
return (root, query, criteriaBuilder) ->
|
||||
criteriaBuilder.lt(root.get(input.getField()),
|
||||
(Number) castToRequiredType(root.get(input.getField()).getJavaType(), input.getValue()));
|
||||
case LIKE:
|
||||
return (root, query, criteriaBuilder) ->
|
||||
criteriaBuilder.like(root.get(input.getField()), "%"+input.getValue()+"%");
|
||||
case IN:
|
||||
return (root, query, criteriaBuilder) ->
|
||||
criteriaBuilder.in(root.get(input.getField()))
|
||||
.value(castToRequiredType(root.get(input.getField()).getJavaType(), input.getValues()));
|
||||
default:
|
||||
throw new RuntimeException("Operation not supported yet");
|
||||
}
|
||||
}
|
||||
|
||||
private Object castToRequiredType(Class fieldType, String value) {
|
||||
if(fieldType.isAssignableFrom(Double.class)){
|
||||
return Double.valueOf(value);
|
||||
}else if(fieldType.isAssignableFrom(Integer.class)){
|
||||
return Integer.valueOf(value);
|
||||
}else if(Enum.class.isAssignableFrom(fieldType)){
|
||||
return Enum.valueOf(fieldType, value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object castToRequiredType(Class fieldType, List<String> value) {
|
||||
List<Object> lists = new ArrayList<>();
|
||||
for (String s : value) {
|
||||
lists.add(castToRequiredType(fieldType, s));
|
||||
}
|
||||
return lists;
|
||||
}
|
||||
|
||||
private Specification<Product> nameLike(String name){
|
||||
return (root, query, criteriaBuilder) -> criteriaBuilder.like(root.get(Product_.NAME), "%"+name+"%");
|
||||
}
|
||||
|
||||
|
||||
private Specification<Product> pricesAreBetween(Double min, Double max){
|
||||
return (root, query, criteriaBuilder)-> criteriaBuilder.between(root.get(Product_.PRICE), min, max);
|
||||
}
|
||||
|
||||
private Specification<Product> belongsToCategory(List<Category> categories){
|
||||
return (root, query, criteriaBuilder)-> criteriaBuilder.in(root.get(Product_.CATEGORY)).value(categories);
|
||||
}
|
||||
|
||||
private Specification<Product> isPremium() {
|
||||
return (root, query, criteriaBuilder) ->
|
||||
criteriaBuilder.and(
|
||||
criteriaBuilder.equal(root.get(Product_.MANUFACTURING_PLACE).get(Address_.STATE),
|
||||
STATE.CALIFORNIA),
|
||||
criteriaBuilder.greaterThanOrEqualTo(root.get(Product_.PRICE), PREMIUM_PRICE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.reflectoring.specification.repository;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class Filter {
|
||||
private String field;
|
||||
private QueryOperator operator;
|
||||
private String value;
|
||||
private List<String> values;//Used in case of IN operator
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.reflectoring.specification.repository;
|
||||
|
||||
import io.reflectoring.specification.model.Category;
|
||||
import io.reflectoring.specification.model.Product;
|
||||
import io.reflectoring.specification.model.STATE;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface ProductRepository extends JpaRepository<Product, String>, JpaSpecificationExecutor<Product> {
|
||||
List<Product> findAllByNameLike(String name);
|
||||
|
||||
List<Product> findAllByNameLikeAndPriceLessThanEqual(String name, Double price);
|
||||
|
||||
List<Product> findAllByCategoryInAndPriceLessThanEqual(List<Category> categories, Double price);
|
||||
|
||||
List<Product> findAllByCategoryInAndPriceBetween(List<Category> categories,
|
||||
Double bottom, Double top);
|
||||
|
||||
List<Product> findAllByNameLikeAndCategoryIn(String name, List<Category> categories);
|
||||
|
||||
List<Product> findAllByNameLikeAndCategoryInAndPriceBetween(String name, List<Category> categories,
|
||||
Double bottom, Double top);
|
||||
|
||||
List<Product> findAllByNameLikeAndCategoryInAndPriceBetweenAndManufacturingPlace_State(String name,
|
||||
List<Category> categories,
|
||||
Double bottom, Double top,
|
||||
STATE state);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.reflectoring.specification.repository;
|
||||
|
||||
public enum QueryOperator {
|
||||
GREATER_THAN,
|
||||
LESS_THAN,
|
||||
EQUALS,
|
||||
LIKE,
|
||||
NOT_EQ,
|
||||
IN
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
spring:
|
||||
jpa:
|
||||
show-sql: true
|
||||
generate-ddl: true
|
||||
hibernate:
|
||||
ddl-auto: create-drop
|
||||
45
spring-boot/specification/src/main/resources/data.sql
Normal file
45
spring-boot/specification/src/main/resources/data.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
insert into address (id, city, state, pincode) values
|
||||
('addr_1', 'chicago', 'TEXAS', 'AB9898');
|
||||
insert into address (id, city, state, pincode) values
|
||||
('addr_2', 'hells kitchen', 'CALIFORNIA', 'AB9899');
|
||||
insert into address (id, city, state, pincode) values
|
||||
('addr_3', 'palm city', 'TEXAS', 'AA9800');
|
||||
insert into address (id, city, state, pincode) values
|
||||
('addr_4', ' San Diego', 'CALIFORNIA', 'AA9230');
|
||||
insert into address (id, city, state, pincode) values
|
||||
('addr_5', 'palm city', 'TEXAS', 'AA9560');
|
||||
|
||||
insert into distributor (id, name, address_id) values
|
||||
('dist_1', 'john doe', 'addr_1');
|
||||
insert into distributor (id, name, address_id) values
|
||||
('dist_2', 'Max well', 'addr_2');
|
||||
|
||||
insert into product
|
||||
(id, name, price, manufacturing_date, manufacturing_place_id, weight, height, width, distributor_id, category)
|
||||
values
|
||||
('prod_1', 'one plus 8T', 100, now(), 'addr_3', 2.2, 3.4, 5.4, 'dist_1', 'MOBILE');
|
||||
|
||||
insert into product
|
||||
(id, name, price, manufacturing_date, manufacturing_place_id, weight, height, width, distributor_id, category)
|
||||
values
|
||||
('prod_2', 'Samsung 100 S', 200, now(), 'addr_4', 5.6, 7.9, 4.3, 'dist_2', 'MOBILE');
|
||||
|
||||
insert into product
|
||||
(id, name, price, manufacturing_date, manufacturing_place_id, weight, height, width, distributor_id, category)
|
||||
values
|
||||
('prod_3', 'Armani jacket size 32', 1100, now(), 'addr_4', 1.3, 10.4, 29.5, 'dist_2', 'MEN_FASHION');
|
||||
|
||||
insert into product
|
||||
(id, name, price, manufacturing_date, manufacturing_place_id, weight, height, width, distributor_id, category)
|
||||
values
|
||||
('prod_4', 'Zara purse', 500, now(), 'addr_5', 3.7, 50.6, 70.6, 'dist_1', 'WOMEN_FASHION');
|
||||
|
||||
insert into product
|
||||
(id, name, price, manufacturing_date, manufacturing_place_id, weight, height, width, distributor_id, category)
|
||||
values
|
||||
('prod_5', 'Sony Bravia ', 2000, now(), 'addr_5', 25.5, 48.8, 25.9, 'dist_1', 'TV_APPLIANCES');
|
||||
|
||||
insert into product
|
||||
(id, name, price, manufacturing_date, manufacturing_place_id, weight, height, width, distributor_id, category)
|
||||
values
|
||||
('prod_6', 'zara jacket green color', 1500, now(), 'addr_4', 1.3, 10.4, 29.5, 'dist_2', 'MEN_FASHION');
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.reflectoring.specification;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class SpecificationApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package io.reflectoring.specification.repository;
|
||||
|
||||
import io.reflectoring.specification.model.Category;
|
||||
import io.reflectoring.specification.model.Product;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@SpringBootTest
|
||||
class CustomProductRepositoryTest {
|
||||
|
||||
@Autowired
|
||||
private CustomProductRepository productRepository;
|
||||
|
||||
@Test
|
||||
void getLowRangeProducts() {
|
||||
List<Product> products = productRepository.getLowRangeProducts(List.of(Category.MOBILE, Category.TV_APPLIANCES));
|
||||
assertEquals(2, products.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPremiumProducts() {
|
||||
List<Product> products = productRepository.getPremiumProducts(List.of(Category.MEN_FASHION, Category.WOMEN_FASHION));
|
||||
assertEquals(2, products.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPremiumProducts() {
|
||||
List<Product> products = productRepository.getPremiumProducts("jacket", List.of(Category.MEN_FASHION));
|
||||
assertEquals(2, products.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDynamicSpecification() {
|
||||
Filter nameLike = Filter.builder()
|
||||
.field("name")
|
||||
.operator(QueryOperator.LIKE)
|
||||
.value("jacket")
|
||||
.build();
|
||||
Filter categories = Filter.builder()
|
||||
.field("category")
|
||||
.operator(QueryOperator.IN)
|
||||
.values(List.of(Category.MEN_FASHION.name(), Category.WOMEN_FASHION.name()))
|
||||
.build();
|
||||
List<Filter> filters = new ArrayList<>();
|
||||
filters.add(nameLike);
|
||||
filters.add(categories);
|
||||
List<Product> products = productRepository.getQueryResult(filters);
|
||||
assertEquals(2, products.size());
|
||||
|
||||
Filter lowRange = Filter.builder()
|
||||
.field("price")
|
||||
.operator(QueryOperator.LESS_THAN)
|
||||
.value("1000")
|
||||
.build();
|
||||
categories.setValues(List.of(Category.MOBILE.name(), Category.TV_APPLIANCES.name()));
|
||||
filters = new ArrayList<>();
|
||||
filters.add(lowRange);
|
||||
filters.add(categories);
|
||||
|
||||
products = productRepository.getQueryResult(filters);
|
||||
assertEquals(2, products.size());
|
||||
|
||||
Filter priceEquals = Filter.builder()
|
||||
.field("price")
|
||||
.operator(QueryOperator.EQUALS)
|
||||
.value("1100")
|
||||
.build();
|
||||
filters = new ArrayList<>();
|
||||
filters.add(priceEquals);
|
||||
products = productRepository.getQueryResult(filters);
|
||||
assertEquals(1, products.size());
|
||||
}
|
||||
}
|
||||
23
spring-boot/spring-boot-mocking-modules/build.gradle
Normal file
23
spring-boot/spring-boot-mocking-modules/build.gradle
Normal file
@@ -0,0 +1,23 @@
|
||||
plugins {
|
||||
id 'org.springframework.boot' version '2.4.0'
|
||||
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'io.reflectoring.modules'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
sourceCompatibility = '11'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
BIN
spring-boot/spring-boot-mocking-modules/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
spring-boot/spring-boot-mocking-modules/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
spring-boot/spring-boot-mocking-modules/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
spring-boot/spring-boot-mocking-modules/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Tue Feb 06 12:27:20 CET 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||
172
spring-boot/spring-boot-mocking-modules/gradlew
vendored
Executable file
172
spring-boot/spring-boot-mocking-modules/gradlew
vendored
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
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
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
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
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save ( ) {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
84
spring-boot/spring-boot-mocking-modules/gradlew.bat
vendored
Normal file
84
spring-boot/spring-boot-mocking-modules/gradlew.bat
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
1
spring-boot/spring-boot-mocking-modules/settings.gradle
Normal file
1
spring-boot/spring-boot-mocking-modules/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'mocking-modules'
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.reflectoring.modules;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@ComponentScan()
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DemoApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.reflectoring.modules.github.api;
|
||||
|
||||
public interface GitHubMutations {
|
||||
|
||||
String createRepository(String token, GitHubRepository repository);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.reflectoring.modules.github.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GitHubQueries {
|
||||
|
||||
List<String> getOrganisations(String token);
|
||||
|
||||
List<String> getRepositories(String token, String organisation);
|
||||
|
||||
boolean repositoryExists(String token, String repositoryName, String organisation);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.reflectoring.modules.github.api;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class GitHubRepository {
|
||||
|
||||
private final String name;
|
||||
private final String organization;
|
||||
|
||||
public GitHubRepository(String name, String organization) {
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(organization);
|
||||
this.name = name;
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.reflectoring.modules.github.internal;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
class GitHubModuleConfiguration {
|
||||
|
||||
@Bean
|
||||
GitHubService gitHubService(){
|
||||
return new GitHubService();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.reflectoring.modules.github.internal;
|
||||
|
||||
import io.reflectoring.modules.github.api.GitHubMutations;
|
||||
import io.reflectoring.modules.github.api.GitHubQueries;
|
||||
import io.reflectoring.modules.github.api.GitHubRepository;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class GitHubService implements GitHubMutations, GitHubQueries {
|
||||
|
||||
@Override
|
||||
public String createRepository(String token, GitHubRepository repository) {
|
||||
// call the GitHub API to create a repo
|
||||
return "https://github.com/reflectoring/reflectoring.github.io";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getOrganisations(String token) {
|
||||
// call the GitHub API to get a list of organisations for the user
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRepositories(String token, String organisation) {
|
||||
// call the GitHub API to get a list of repositories for the user
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean repositoryExists(String token, String repositoryName, String organisation) {
|
||||
// call the GitHub API to find out if a given repo exists
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.reflectoring.modules.mail.api;
|
||||
|
||||
public interface EmailNotificationService {
|
||||
|
||||
void sendEmail(String to, String subject, String text);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package io.reflectoring.modules.mail.internal;
|
||||
|
||||
import io.reflectoring.modules.mail.api.EmailNotificationService;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(EmailModuleConfigurationProperties.class)
|
||||
public class EmailModuleConfiguration {
|
||||
|
||||
private final EmailModuleConfigurationProperties configurationProperties;
|
||||
|
||||
public EmailModuleConfiguration(EmailModuleConfigurationProperties configurationProperties) {
|
||||
this.configurationProperties = configurationProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
EmailNotificationService emailNotificationService(MailClient mailClient) {
|
||||
return new EmailNotificationServiceImpl(mailClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
MailClient mailClient() {
|
||||
return new MailClient(configurationProperties.isEnabled());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.reflectoring.modules.mail.internal;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "mail")
|
||||
public class EmailModuleConfigurationProperties {
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.reflectoring.modules.mail.internal;
|
||||
|
||||
import io.reflectoring.modules.mail.api.EmailNotificationService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
class EmailNotificationServiceImpl implements EmailNotificationService {
|
||||
|
||||
private final MailClient mailClient;
|
||||
|
||||
public EmailNotificationServiceImpl(MailClient mailClient) {
|
||||
this.mailClient = mailClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEmail(String to, String subject, String text) {
|
||||
// send an email
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.reflectoring.modules.mail.internal;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* Internal mail server connection. This is not part of the API of the `mail` component.
|
||||
*/
|
||||
class MailClient {
|
||||
|
||||
private final boolean connectToMailServer;
|
||||
|
||||
public MailClient(boolean connectToMailServer) {
|
||||
this.connectToMailServer = connectToMailServer;
|
||||
}
|
||||
|
||||
void sendMail() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* There are many cases where a Spring application connects to external resources during startup, for example when
|
||||
* initializing a connection pool to a database or some other service. This method just simulates a failing connection
|
||||
* during startup. This forces us not to load this bean during integration tests.
|
||||
*/
|
||||
@PostConstruct
|
||||
void connectToMailServer() {
|
||||
if(connectToMailServer) {
|
||||
throw new RuntimeException("Could not connect to mail server!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package io.reflectoring.modules.rest.internal;
|
||||
|
||||
import io.reflectoring.modules.github.api.GitHubMutations;
|
||||
import io.reflectoring.modules.github.api.GitHubQueries;
|
||||
import io.reflectoring.modules.github.api.GitHubRepository;
|
||||
import io.reflectoring.modules.mail.api.EmailNotificationService;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
class RepositoryController {
|
||||
|
||||
private final GitHubMutations gitHubMutations;
|
||||
private final GitHubQueries gitHubQueries;
|
||||
private final EmailNotificationService emailNotificationService;
|
||||
|
||||
public RepositoryController(
|
||||
GitHubMutations gitHubMutations,
|
||||
GitHubQueries gitHubQueries,
|
||||
EmailNotificationService emailNotificationService
|
||||
) {
|
||||
this.gitHubMutations = gitHubMutations;
|
||||
this.gitHubQueries = gitHubQueries;
|
||||
this.emailNotificationService = emailNotificationService;
|
||||
}
|
||||
|
||||
@PostMapping("/github/repository")
|
||||
ResponseEntity<Void> createGitHubRepository(
|
||||
@RequestParam("token") String token,
|
||||
@RequestParam("repositoryName") String repoName,
|
||||
@RequestParam("organizationName") String orgName
|
||||
) {
|
||||
|
||||
if (gitHubQueries.repositoryExists(token, repoName, orgName)) {
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
|
||||
}
|
||||
String repoUrl = gitHubMutations.createRepository(token, new GitHubRepository(repoName, orgName));
|
||||
emailNotificationService.sendEmail("user@mail.com", "Your new repository", "Here's your new repository: " + repoUrl);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package io.reflectoring.modules.github;
|
||||
|
||||
import io.reflectoring.modules.github.internal.GitHubService;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@TestConfiguration
|
||||
public class GitHubModuleMock {
|
||||
|
||||
private final GitHubService gitHubServiceMock = Mockito.mock(GitHubService.class);
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
GitHubService gitHubServiceMock() {
|
||||
return gitHubServiceMock;
|
||||
}
|
||||
|
||||
public void givenCreateRepositoryReturnsUrl(String url) {
|
||||
given(gitHubServiceMock.createRepository(any(), any())).willReturn(url);
|
||||
}
|
||||
|
||||
public void givenRepositoryExists(){
|
||||
given(gitHubServiceMock.repositoryExists(anyString(), anyString(), anyString())).willReturn(true);
|
||||
}
|
||||
|
||||
public void givenRepositoryDoesNotExist(){
|
||||
given(gitHubServiceMock.repositoryExists(anyString(), anyString(), anyString())).willReturn(false);
|
||||
}
|
||||
|
||||
public void assertRepositoryCreated(){
|
||||
verify(gitHubServiceMock).createRepository(any(), any());
|
||||
}
|
||||
|
||||
public void givenDefaultState(String defaultRepositoryUrl){
|
||||
givenRepositoryDoesNotExist();
|
||||
givenCreateRepositoryReturnsUrl(defaultRepositoryUrl);
|
||||
}
|
||||
|
||||
public void assertRepositoryNotCreated(){
|
||||
verify(gitHubServiceMock, never()).createRepository(any(), any());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package io.reflectoring.modules.mail;
|
||||
|
||||
import io.reflectoring.modules.mail.api.EmailNotificationService;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.contains;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@TestConfiguration
|
||||
public class EmailModuleMock {
|
||||
|
||||
private final EmailNotificationService emailNotificationServiceMock = Mockito.mock(EmailNotificationService.class);
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
EmailNotificationService emailNotificationServiceMock() {
|
||||
return emailNotificationServiceMock;
|
||||
}
|
||||
|
||||
public void givenSendMailSucceeds() {
|
||||
// nothing to do, the mock will simply return 0
|
||||
}
|
||||
|
||||
public void givenSendMailThrowsError() {
|
||||
doThrow(new RuntimeException("error when sending mail"))
|
||||
.when(emailNotificationServiceMock).sendEmail(anyString(), anyString(), anyString());
|
||||
}
|
||||
|
||||
public void assertSentMailContains(String repositoryUrl) {
|
||||
verify(emailNotificationServiceMock).sendEmail(anyString(), anyString(), contains(repositoryUrl));
|
||||
}
|
||||
|
||||
public void assertNoMailSent() {
|
||||
verify(emailNotificationServiceMock, never()).sendEmail(anyString(), anyString(), anyString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package io.reflectoring.modules.rest;
|
||||
|
||||
import io.reflectoring.modules.github.GitHubModuleMock;
|
||||
import io.reflectoring.modules.mail.EmailModuleMock;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@WebMvcTest
|
||||
@TestPropertySource(properties = "mail.enabled=false")
|
||||
@Import({
|
||||
GitHubModuleMock.class,
|
||||
EmailModuleMock.class
|
||||
})
|
||||
class RepositoryControllerTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private EmailModuleMock emailModuleMock;
|
||||
|
||||
@Autowired
|
||||
private GitHubModuleMock gitHubModuleMock;
|
||||
|
||||
@Test
|
||||
void givenRepositoryDoesNotExist_thenRepositoryIsCreatedSuccessfully() throws Exception {
|
||||
|
||||
String repositoryUrl = "https://github.com/reflectoring/reflectoring.github.io";
|
||||
|
||||
gitHubModuleMock.givenDefaultState(repositoryUrl);
|
||||
emailModuleMock.givenSendMailSucceeds();
|
||||
|
||||
mockMvc.perform(post("/github/repository")
|
||||
.param("token", "123")
|
||||
.param("repositoryName", "foo")
|
||||
.param("organizationName", "bar"))
|
||||
.andExpect(status().is(200));
|
||||
|
||||
emailModuleMock.assertSentMailContains(repositoryUrl);
|
||||
gitHubModuleMock.assertRepositoryCreated();
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenRepositoryExists_thenReturnsBadRequest() throws Exception {
|
||||
|
||||
String repositoryUrl = "https://github.com/reflectoring/reflectoring.github.io";
|
||||
|
||||
gitHubModuleMock.givenDefaultState(repositoryUrl);
|
||||
gitHubModuleMock.givenRepositoryExists();
|
||||
emailModuleMock.givenSendMailSucceeds();
|
||||
|
||||
mockMvc.perform(post("/github/repository")
|
||||
.param("token", "123")
|
||||
.param("repositoryName", "foo")
|
||||
.param("organizationName", "bar"))
|
||||
.andExpect(status().is(400));
|
||||
|
||||
emailModuleMock.assertNoMailSent();
|
||||
gitHubModuleMock.assertRepositoryNotCreated();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package io.reflectoring.modules.rest;
|
||||
|
||||
import io.reflectoring.modules.github.api.GitHubMutations;
|
||||
import io.reflectoring.modules.github.api.GitHubQueries;
|
||||
import io.reflectoring.modules.mail.api.EmailNotificationService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@WebMvcTest
|
||||
@TestPropertySource(properties = "mail.enabled=false")
|
||||
class RepositoryControllerTestWithoutModuleMocks {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private GitHubMutations gitHubMutations;
|
||||
|
||||
@MockBean
|
||||
private GitHubQueries gitHubQueries;
|
||||
|
||||
@MockBean
|
||||
private EmailNotificationService emailNotificationService;
|
||||
|
||||
@Test
|
||||
void givenRepositoryDoesNotExist_thenRepositoryIsCreatedSuccessfully() throws Exception {
|
||||
|
||||
String repositoryUrl = "https://github.com/reflectoring/reflectoring.github.io";
|
||||
|
||||
given(gitHubQueries.repositoryExists(
|
||||
anyString(),
|
||||
anyString(),
|
||||
anyString())
|
||||
).willReturn(false);
|
||||
|
||||
given(gitHubMutations.createRepository(
|
||||
any(),
|
||||
any())
|
||||
).willReturn(repositoryUrl);
|
||||
|
||||
mockMvc.perform(post("/github/repository")
|
||||
.param("token", "123")
|
||||
.param("repositoryName", "foo")
|
||||
.param("organizationName", "bar"))
|
||||
.andExpect(status().is(200));
|
||||
|
||||
verify(emailNotificationService).sendEmail(
|
||||
anyString(),
|
||||
anyString(),
|
||||
contains(repositoryUrl)
|
||||
);
|
||||
|
||||
verify(gitHubMutations).createRepository(
|
||||
any(),
|
||||
any()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user