diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4f56dc1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+.DS_Store
+
+.idea
+*.iml
+
+.gradle
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Cache of project
+.gradletasknamecache
+
+build
+out
+bin
+.settings
+.classpath
+.project
\ No newline at end of file
diff --git a/Chapter_04/aop-aspectj/build.gradle b/Chapter_04/aop-aspectj/build.gradle
new file mode 100644
index 0000000..4441039
--- /dev/null
+++ b/Chapter_04/aop-aspectj/build.gradle
@@ -0,0 +1,20 @@
+plugins {
+ id 'java'
+ id "aspectj.gradle" version "0.1.6"
+ id 'application'
+}
+
+group 'com.whezh'
+version '1.0-SNAPSHOT'
+
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile "org.springframework:spring-context:${springVersion}"
+}
+
+mainClassName = 'concert.Main'
diff --git a/Chapter_04/aop-aspectj/gradle.properties b/Chapter_04/aop-aspectj/gradle.properties
new file mode 100644
index 0000000..d51100e
--- /dev/null
+++ b/Chapter_04/aop-aspectj/gradle.properties
@@ -0,0 +1,3 @@
+springVersion=4.0.7.RELEASE
+systemRulesVersion=1.5.0
+aspectjVersion=1.8.5
\ No newline at end of file
diff --git a/Chapter_04/aop-aspectj/gradle/wrapper/gradle-wrapper.jar b/Chapter_04/aop-aspectj/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..1948b90
Binary files /dev/null and b/Chapter_04/aop-aspectj/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Chapter_04/aop-aspectj/gradle/wrapper/gradle-wrapper.properties b/Chapter_04/aop-aspectj/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..d2c45a4
--- /dev/null
+++ b/Chapter_04/aop-aspectj/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/Chapter_04/aop-aspectj/gradlew b/Chapter_04/aop-aspectj/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/Chapter_04/aop-aspectj/gradlew
@@ -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" "$@"
diff --git a/Chapter_04/aop-aspectj/gradlew.bat b/Chapter_04/aop-aspectj/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/Chapter_04/aop-aspectj/gradlew.bat
@@ -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
diff --git a/Chapter_04/aop-aspectj/settings.gradle b/Chapter_04/aop-aspectj/settings.gradle
new file mode 100644
index 0000000..683c3ed
--- /dev/null
+++ b/Chapter_04/aop-aspectj/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'aop'
+
diff --git a/Chapter_04/aop-aspectj/src/main/java/concert/CriticAspect.aj b/Chapter_04/aop-aspectj/src/main/java/concert/CriticAspect.aj
new file mode 100644
index 0000000..c51ce23
--- /dev/null
+++ b/Chapter_04/aop-aspectj/src/main/java/concert/CriticAspect.aj
@@ -0,0 +1,30 @@
+package concert;
+
+public aspect CriticAspect {
+ private CriticismEngine criticismEngine;
+
+ pointcut performance():execution(* concert.Performance.perform(..));
+
+ pointcut construct():execution(concert.CriticismEngineImpl.new());
+
+ after():performance(){
+ System.out.println(criticismEngine.getCriticism());
+ }
+
+ after():construct(){
+ System.out.println("After Performance constructor");
+ }
+
+
+ before():construct(){
+ System.out.println("Before Performance constructor");
+ }
+
+ public CriticismEngine getCriticismEngine() {
+ return this.criticismEngine;
+ }
+
+ public void setCriticismEngine(CriticismEngine criticismEngine) {
+ this.criticismEngine = criticismEngine;
+ }
+}
diff --git a/Chapter_04/aop-aspectj/src/main/java/concert/CriticismEngine.java b/Chapter_04/aop-aspectj/src/main/java/concert/CriticismEngine.java
new file mode 100644
index 0000000..00ddc68
--- /dev/null
+++ b/Chapter_04/aop-aspectj/src/main/java/concert/CriticismEngine.java
@@ -0,0 +1,5 @@
+package concert;
+
+public interface CriticismEngine {
+ String getCriticism();
+}
diff --git a/Chapter_04/aop-aspectj/src/main/java/concert/CriticismEngineImpl.java b/Chapter_04/aop-aspectj/src/main/java/concert/CriticismEngineImpl.java
new file mode 100644
index 0000000..39ee348
--- /dev/null
+++ b/Chapter_04/aop-aspectj/src/main/java/concert/CriticismEngineImpl.java
@@ -0,0 +1,18 @@
+package concert;
+
+public class CriticismEngineImpl implements CriticismEngine {
+ private String[] criticismPool;
+
+ public CriticismEngineImpl() {
+ }
+
+ @Override
+ public String getCriticism() {
+ int i = (int) (Math.random() * criticismPool.length);
+ return criticismPool[i];
+ }
+
+ public void setCriticismPool(String[] criticismPool) {
+ this.criticismPool = criticismPool;
+ }
+}
diff --git a/Chapter_04/aop-aspectj/src/main/java/concert/Main.java b/Chapter_04/aop-aspectj/src/main/java/concert/Main.java
new file mode 100644
index 0000000..4368b78
--- /dev/null
+++ b/Chapter_04/aop-aspectj/src/main/java/concert/Main.java
@@ -0,0 +1,13 @@
+package concert;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class Main {
+ public static void main(String[] args) {
+ ClassPathXmlApplicationContext context =
+ new ClassPathXmlApplicationContext("concert.xml");
+ Performance performance = context.getBean(Performance.class);
+ performance.perform();
+ context.close();
+ }
+}
diff --git a/Chapter_04/aop-aspectj/src/main/java/concert/Music.java b/Chapter_04/aop-aspectj/src/main/java/concert/Music.java
new file mode 100644
index 0000000..c1450bd
--- /dev/null
+++ b/Chapter_04/aop-aspectj/src/main/java/concert/Music.java
@@ -0,0 +1,11 @@
+package concert;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class Music implements Performance {
+ @Override
+ public void perform() {
+ System.out.println("Piano Solo");
+ }
+}
diff --git a/Chapter_04/aop-aspectj/src/main/java/concert/Performance.java b/Chapter_04/aop-aspectj/src/main/java/concert/Performance.java
new file mode 100644
index 0000000..19896c1
--- /dev/null
+++ b/Chapter_04/aop-aspectj/src/main/java/concert/Performance.java
@@ -0,0 +1,5 @@
+package concert;
+
+public interface Performance {
+ void perform();
+}
diff --git a/Chapter_04/aop-aspectj/src/main/resources/concert.xml b/Chapter_04/aop-aspectj/src/main/resources/concert.xml
new file mode 100644
index 0000000..ce98b19
--- /dev/null
+++ b/Chapter_04/aop-aspectj/src/main/resources/concert.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ Worst performance ever!
+ I laughed, I cried, then I realized I was at the wrong show.
+ A must see show!
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Chapter_04/aop-xml/build.gradle b/Chapter_04/aop-xml/build.gradle
new file mode 100644
index 0000000..02a6131
--- /dev/null
+++ b/Chapter_04/aop-xml/build.gradle
@@ -0,0 +1,20 @@
+plugins {
+ id 'java'
+}
+
+group 'com.whezh'
+version '1.0-SNAPSHOT'
+
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile "org.springframework:spring-context:${springVersion}"
+ compile("org.aspectj:aspectjweaver:${aspectjVersion}")
+
+ testCompile("org.springframework:spring-test:${springVersion}")
+ testCompile "com.github.stefanbirkner:system-rules:${systemRulesVersion}"
+}
diff --git a/Chapter_04/aop-xml/gradle.properties b/Chapter_04/aop-xml/gradle.properties
new file mode 100644
index 0000000..d9d7004
--- /dev/null
+++ b/Chapter_04/aop-xml/gradle.properties
@@ -0,0 +1,3 @@
+springVersion=4.0.7.RELEASE
+systemRulesVersion=1.5.0
+aspectjVersion=1.7.2
\ No newline at end of file
diff --git a/Chapter_04/aop-xml/gradle/wrapper/gradle-wrapper.jar b/Chapter_04/aop-xml/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..1948b90
Binary files /dev/null and b/Chapter_04/aop-xml/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Chapter_04/aop-xml/gradle/wrapper/gradle-wrapper.properties b/Chapter_04/aop-xml/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..d2c45a4
--- /dev/null
+++ b/Chapter_04/aop-xml/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/Chapter_04/aop-xml/gradlew b/Chapter_04/aop-xml/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/Chapter_04/aop-xml/gradlew
@@ -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" "$@"
diff --git a/Chapter_04/aop-xml/gradlew.bat b/Chapter_04/aop-xml/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/Chapter_04/aop-xml/gradlew.bat
@@ -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
diff --git a/Chapter_04/aop-xml/settings.gradle b/Chapter_04/aop-xml/settings.gradle
new file mode 100644
index 0000000..683c3ed
--- /dev/null
+++ b/Chapter_04/aop-xml/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'aop'
+
diff --git a/Chapter_04/aop-xml/src/main/java/concert/Audience.java b/Chapter_04/aop-xml/src/main/java/concert/Audience.java
new file mode 100644
index 0000000..3e3053e
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/java/concert/Audience.java
@@ -0,0 +1,32 @@
+package concert;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+
+public class Audience {
+ public void silenceCellPhone() {
+ System.out.println("Silencing cell phones");
+ }
+
+ public void takeSeats() {
+ System.out.println("Taking seats");
+ }
+
+ public void applause() {
+ System.out.println("CLAP CLAP CLAP!!!");
+ }
+
+ public void demandRefund() {
+ System.out.println("Demanding a refund");
+ }
+
+ public void watchPerformance(ProceedingJoinPoint jp) {
+ try {
+ System.out.println("Silencing cell phones");
+ System.out.println("Taking seats");
+ jp.proceed();
+ System.out.println("CLAP CLAP CLAP!!!");
+ } catch (Throwable e) {
+ System.out.println("Demanding a refund");
+ }
+ }
+}
diff --git a/Chapter_04/aop-xml/src/main/java/concert/DefaultEncoreable.java b/Chapter_04/aop-xml/src/main/java/concert/DefaultEncoreable.java
new file mode 100644
index 0000000..d06729e
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/java/concert/DefaultEncoreable.java
@@ -0,0 +1,8 @@
+package concert;
+
+public class DefaultEncoreable implements Encoreable {
+ @Override
+ public void performEncore() {
+ System.out.println("Default encoreable");
+ }
+}
diff --git a/Chapter_04/aop-xml/src/main/java/concert/Encoreable.java b/Chapter_04/aop-xml/src/main/java/concert/Encoreable.java
new file mode 100644
index 0000000..822ad00
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/java/concert/Encoreable.java
@@ -0,0 +1,5 @@
+package concert;
+
+public interface Encoreable {
+ void performEncore();
+}
diff --git a/Chapter_04/aop-xml/src/main/java/concert/Music.java b/Chapter_04/aop-xml/src/main/java/concert/Music.java
new file mode 100644
index 0000000..719cf2c
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/java/concert/Music.java
@@ -0,0 +1,8 @@
+package concert;
+
+public class Music implements Performance {
+ @Override
+ public void perform() {
+ System.out.println("Piano Solo");
+ }
+}
diff --git a/Chapter_04/aop-xml/src/main/java/concert/Performance.java b/Chapter_04/aop-xml/src/main/java/concert/Performance.java
new file mode 100644
index 0000000..19896c1
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/java/concert/Performance.java
@@ -0,0 +1,5 @@
+package concert;
+
+public interface Performance {
+ void perform();
+}
diff --git a/Chapter_04/aop-xml/src/main/java/params/BlankDisc.java b/Chapter_04/aop-xml/src/main/java/params/BlankDisc.java
new file mode 100644
index 0000000..8cf45f9
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/java/params/BlankDisc.java
@@ -0,0 +1,33 @@
+package params;
+
+import java.util.List;
+
+public class BlankDisc implements CompactDisc {
+
+ private String title;
+ private String artist;
+ private List tracks;
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setArtist(String artist) {
+ this.artist = artist;
+ }
+
+ public void setTracks(List tracks) {
+ this.tracks = tracks;
+ }
+
+ public void play() {
+ System.out.println("Playing " + title + " by " + artist);
+ for (int i = 0; i < tracks.size(); i++) {
+ playTrack(i);
+ }
+ }
+
+ public void playTrack(int track) {
+ System.out.println("-Track: " + tracks.get(track));
+ }
+}
diff --git a/Chapter_04/aop-xml/src/main/java/params/CompactDisc.java b/Chapter_04/aop-xml/src/main/java/params/CompactDisc.java
new file mode 100644
index 0000000..8bfab5f
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/java/params/CompactDisc.java
@@ -0,0 +1,7 @@
+package params;
+
+public interface CompactDisc {
+ void play();
+
+ void playTrack(int track);
+}
diff --git a/Chapter_04/aop-xml/src/main/java/params/TrackCounter.java b/Chapter_04/aop-xml/src/main/java/params/TrackCounter.java
new file mode 100644
index 0000000..8b8628b
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/java/params/TrackCounter.java
@@ -0,0 +1,18 @@
+package params;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TrackCounter {
+
+ private Map trackCounts = new HashMap<>();
+
+ public void countTrack(int trackNumber) {
+ int currentCount = getPlayCount(trackNumber);
+ trackCounts.put(trackNumber, currentCount + 1);
+ }
+
+ public int getPlayCount(int trackNumber) {
+ return trackCounts.getOrDefault(trackNumber, 0);
+ }
+}
diff --git a/Chapter_04/aop-xml/src/main/resources/concert.xml b/Chapter_04/aop-xml/src/main/resources/concert.xml
new file mode 100644
index 0000000..51364c6
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/resources/concert.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Chapter_04/aop-xml/src/main/resources/params.xml b/Chapter_04/aop-xml/src/main/resources/params.xml
new file mode 100644
index 0000000..9777a71
--- /dev/null
+++ b/Chapter_04/aop-xml/src/main/resources/params.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ Sgt. Pepper's Lonely Hearts Club Band
+ With a Little Help from My Friends
+ Lucy in the Sky with Diamonds
+ Getting Better
+ Fixing a Hole
+ She's Leaving Home
+ Being for the Benefit of Mr. Kite!
+ Within You Without You
+ When I'm Sixty-Four
+ Lovely Rita
+ Good Morning Good Morning
+ Sgt. Pepper's Lonely Hearts Club Band (Reprise)
+ A Day in the Life
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Chapter_04/aop-xml/src/test/java/concert/ConcertTest.java b/Chapter_04/aop-xml/src/test/java/concert/ConcertTest.java
new file mode 100644
index 0000000..d777da1
--- /dev/null
+++ b/Chapter_04/aop-xml/src/test/java/concert/ConcertTest.java
@@ -0,0 +1,30 @@
+package concert;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("classpath:concert.xml")
+public class ConcertTest {
+ @Rule
+ public final StandardOutputStreamLog log = new StandardOutputStreamLog();
+
+ @Autowired
+ private Performance performance;
+
+ @Test
+ public void testPerformance() {
+ performance.perform();
+ assertEquals("Silencing cell phones\n" +
+ "Taking seats\n" +
+ "Piano Solo\n" +
+ "CLAP CLAP CLAP!!!\n", log.getLog());
+ }
+}
diff --git a/Chapter_04/aop-xml/src/test/java/concert/EncoreableTest.java b/Chapter_04/aop-xml/src/test/java/concert/EncoreableTest.java
new file mode 100644
index 0000000..2b67902
--- /dev/null
+++ b/Chapter_04/aop-xml/src/test/java/concert/EncoreableTest.java
@@ -0,0 +1,27 @@
+package concert;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("classpath:concert.xml")
+public class EncoreableTest {
+ @Rule
+ public final StandardOutputStreamLog log = new StandardOutputStreamLog();
+
+ @Autowired
+ private Encoreable performance;
+
+ @Test
+ public void testPerformance() {
+ performance.performEncore();
+ assertEquals("Default encoreable\n", log.getLog());
+ }
+}
diff --git a/Chapter_04/aop-xml/src/test/java/params/TrackCountTest.java b/Chapter_04/aop-xml/src/test/java/params/TrackCountTest.java
new file mode 100644
index 0000000..55fa56a
--- /dev/null
+++ b/Chapter_04/aop-xml/src/test/java/params/TrackCountTest.java
@@ -0,0 +1,40 @@
+package params;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("classpath:params.xml")
+public class TrackCountTest {
+ @Autowired
+ private CompactDisc cd;
+
+ @Autowired
+ private TrackCounter counter;
+
+ @Test
+ public void testTrackCounter() {
+ cd.playTrack(1);
+ cd.playTrack(2);
+ cd.playTrack(3);
+ cd.playTrack(3);
+ cd.playTrack(3);
+ cd.playTrack(3);
+ cd.playTrack(6);
+ cd.playTrack(7);
+ cd.playTrack(7);
+
+ assertEquals(1, counter.getPlayCount(1));
+ assertEquals(1, counter.getPlayCount(2));
+ assertEquals(4, counter.getPlayCount(3));
+ assertEquals(0, counter.getPlayCount(4));
+ assertEquals(0, counter.getPlayCount(5));
+ assertEquals(1, counter.getPlayCount(6));
+ assertEquals(2, counter.getPlayCount(7));
+ }
+}
diff --git a/Chapter_04/aop/build.gradle b/Chapter_04/aop/build.gradle
new file mode 100644
index 0000000..02a6131
--- /dev/null
+++ b/Chapter_04/aop/build.gradle
@@ -0,0 +1,20 @@
+plugins {
+ id 'java'
+}
+
+group 'com.whezh'
+version '1.0-SNAPSHOT'
+
+sourceCompatibility = 1.8
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile "org.springframework:spring-context:${springVersion}"
+ compile("org.aspectj:aspectjweaver:${aspectjVersion}")
+
+ testCompile("org.springframework:spring-test:${springVersion}")
+ testCompile "com.github.stefanbirkner:system-rules:${systemRulesVersion}"
+}
diff --git a/Chapter_04/aop/gradle.properties b/Chapter_04/aop/gradle.properties
new file mode 100644
index 0000000..d9d7004
--- /dev/null
+++ b/Chapter_04/aop/gradle.properties
@@ -0,0 +1,3 @@
+springVersion=4.0.7.RELEASE
+systemRulesVersion=1.5.0
+aspectjVersion=1.7.2
\ No newline at end of file
diff --git a/Chapter_04/aop/gradle/wrapper/gradle-wrapper.jar b/Chapter_04/aop/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..1948b90
Binary files /dev/null and b/Chapter_04/aop/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Chapter_04/aop/gradle/wrapper/gradle-wrapper.properties b/Chapter_04/aop/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..d2c45a4
--- /dev/null
+++ b/Chapter_04/aop/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/Chapter_04/aop/gradlew b/Chapter_04/aop/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/Chapter_04/aop/gradlew
@@ -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" "$@"
diff --git a/Chapter_04/aop/gradlew.bat b/Chapter_04/aop/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/Chapter_04/aop/gradlew.bat
@@ -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
diff --git a/Chapter_04/aop/settings.gradle b/Chapter_04/aop/settings.gradle
new file mode 100644
index 0000000..683c3ed
--- /dev/null
+++ b/Chapter_04/aop/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'aop'
+
diff --git a/Chapter_04/aop/src/main/java/concert/Audience.java b/Chapter_04/aop/src/main/java/concert/Audience.java
new file mode 100644
index 0000000..4e43a4c
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/concert/Audience.java
@@ -0,0 +1,45 @@
+package concert;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+
+@Aspect
+public class Audience {
+ @Pointcut("execution(* concert.Performance.perform(..))")
+ public void performance() {
+ }
+
+ @Around("performance()")
+ public void watchPerformance(ProceedingJoinPoint jp) {
+ try {
+ System.out.println("Silencing cell phones");
+ System.out.println("Taking seats");
+ jp.proceed();
+ System.out.println("CLAP CLAP CLAP!!!");
+ } catch (Throwable e) {
+ System.out.println("Demanding a refund");
+ }
+ }
+
+// @Before("performance()")
+// public void silenceCellPhone() {
+// System.out.println("Silencing cell phones");
+// }
+//
+// @Before("performance()")
+// public void takeSeats() {
+// System.out.println("Taking seats");
+// }
+//
+// @Before("performance()")
+// public void applause() {
+// System.out.println("CLAP CLAP CLAP!!!");
+// }
+//
+// @Before("performance()")
+// public void demandRefund() {
+// System.out.println("Demanding a refund");
+// }
+}
diff --git a/Chapter_04/aop/src/main/java/concert/ConcertConfig.java b/Chapter_04/aop/src/main/java/concert/ConcertConfig.java
new file mode 100644
index 0000000..e2220f6
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/concert/ConcertConfig.java
@@ -0,0 +1,22 @@
+package concert;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+@Configuration
+@EnableAspectJAutoProxy
+@ComponentScan
+public class ConcertConfig {
+
+ @Bean
+ public Audience audience() {
+ return new Audience();
+ }
+
+ @Bean
+ public EncoreableIntroducer encoreableIntroducer() {
+ return new EncoreableIntroducer();
+ }
+}
diff --git a/Chapter_04/aop/src/main/java/concert/DefaultEncoreable.java b/Chapter_04/aop/src/main/java/concert/DefaultEncoreable.java
new file mode 100644
index 0000000..d06729e
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/concert/DefaultEncoreable.java
@@ -0,0 +1,8 @@
+package concert;
+
+public class DefaultEncoreable implements Encoreable {
+ @Override
+ public void performEncore() {
+ System.out.println("Default encoreable");
+ }
+}
diff --git a/Chapter_04/aop/src/main/java/concert/Encoreable.java b/Chapter_04/aop/src/main/java/concert/Encoreable.java
new file mode 100644
index 0000000..822ad00
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/concert/Encoreable.java
@@ -0,0 +1,5 @@
+package concert;
+
+public interface Encoreable {
+ void performEncore();
+}
diff --git a/Chapter_04/aop/src/main/java/concert/EncoreableIntroducer.java b/Chapter_04/aop/src/main/java/concert/EncoreableIntroducer.java
new file mode 100644
index 0000000..d850a90
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/concert/EncoreableIntroducer.java
@@ -0,0 +1,11 @@
+package concert;
+
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.DeclareParents;
+
+@Aspect
+public class EncoreableIntroducer {
+
+ @DeclareParents(value = "concert.Performance+", defaultImpl = DefaultEncoreable.class)
+ public static Encoreable encoreable;
+}
diff --git a/Chapter_04/aop/src/main/java/concert/Music.java b/Chapter_04/aop/src/main/java/concert/Music.java
new file mode 100644
index 0000000..c1450bd
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/concert/Music.java
@@ -0,0 +1,11 @@
+package concert;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class Music implements Performance {
+ @Override
+ public void perform() {
+ System.out.println("Piano Solo");
+ }
+}
diff --git a/Chapter_04/aop/src/main/java/concert/Performance.java b/Chapter_04/aop/src/main/java/concert/Performance.java
new file mode 100644
index 0000000..7654ce3
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/concert/Performance.java
@@ -0,0 +1,5 @@
+package concert;
+
+public interface Performance {
+ void perform();
+}
\ No newline at end of file
diff --git a/Chapter_04/aop/src/main/java/params/BlankDisc.java b/Chapter_04/aop/src/main/java/params/BlankDisc.java
new file mode 100644
index 0000000..8cf45f9
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/params/BlankDisc.java
@@ -0,0 +1,33 @@
+package params;
+
+import java.util.List;
+
+public class BlankDisc implements CompactDisc {
+
+ private String title;
+ private String artist;
+ private List tracks;
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setArtist(String artist) {
+ this.artist = artist;
+ }
+
+ public void setTracks(List tracks) {
+ this.tracks = tracks;
+ }
+
+ public void play() {
+ System.out.println("Playing " + title + " by " + artist);
+ for (int i = 0; i < tracks.size(); i++) {
+ playTrack(i);
+ }
+ }
+
+ public void playTrack(int track) {
+ System.out.println("-Track: " + tracks.get(track));
+ }
+}
diff --git a/Chapter_04/aop/src/main/java/params/CompactDisc.java b/Chapter_04/aop/src/main/java/params/CompactDisc.java
new file mode 100644
index 0000000..21bc2c3
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/params/CompactDisc.java
@@ -0,0 +1,7 @@
+package params;
+
+public interface CompactDisc {
+ void play();
+
+ void playTrack(int track);
+}
\ No newline at end of file
diff --git a/Chapter_04/aop/src/main/java/params/TrackCounter.java b/Chapter_04/aop/src/main/java/params/TrackCounter.java
new file mode 100644
index 0000000..78b36bf
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/params/TrackCounter.java
@@ -0,0 +1,28 @@
+package params;
+
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Aspect
+public class TrackCounter {
+
+ private Map trackCounts = new HashMap<>();
+
+ @Pointcut("execution(* params.CompactDisc.playTrack(int)) && args(trackNumber)")
+ public void trackPlayed(int trackNumber) {
+ }
+
+ @Before("trackPlayed(trackNumber)")
+ public void countTrack(int trackNumber) {
+ int currentCount = getPlayCount(trackNumber);
+ trackCounts.put(trackNumber, currentCount + 1);
+ }
+
+ public int getPlayCount(int trackNumber) {
+ return trackCounts.containsKey(trackNumber) ? trackCounts.get(trackNumber) : 0;
+ }
+}
diff --git a/Chapter_04/aop/src/main/java/params/TrackCounterConfig.java b/Chapter_04/aop/src/main/java/params/TrackCounterConfig.java
new file mode 100644
index 0000000..3bffef1
--- /dev/null
+++ b/Chapter_04/aop/src/main/java/params/TrackCounterConfig.java
@@ -0,0 +1,42 @@
+package params;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+@EnableAspectJAutoProxy
+public class TrackCounterConfig {
+
+ @Bean
+ public CompactDisc blankDisc() {
+ BlankDisc cd = new BlankDisc();
+ cd.setTitle("Sgt. Pepper's Lonely Hearts Club Band");
+ cd.setArtist("The Beatles");
+
+ List tracks = new ArrayList<>();
+ tracks.add("Sgt. Pepper's Lonely Hearts Club Band");
+ tracks.add("With a Little Help from My Friends");
+ tracks.add("Lucy in the Sky with Diamonds");
+ tracks.add("Getting Better");
+ tracks.add("Fixing a Hole");
+ tracks.add("She's Leaving Home");
+ tracks.add("Within You Without You");
+ tracks.add("When I'm Sixty-Four");
+ tracks.add("Lovely Rita");
+ tracks.add("Good Morning Good Morning");
+ tracks.add("A Day in the Life");
+
+ cd.setTracks(tracks);
+
+ return cd;
+ }
+
+ @Bean
+ public TrackCounter trackCounter() {
+ return new TrackCounter();
+ }
+}
diff --git a/Chapter_04/aop/src/test/java/concert/ConcertTest.java b/Chapter_04/aop/src/test/java/concert/ConcertTest.java
new file mode 100644
index 0000000..5bac278
--- /dev/null
+++ b/Chapter_04/aop/src/test/java/concert/ConcertTest.java
@@ -0,0 +1,30 @@
+package concert;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = ConcertConfig.class)
+public class ConcertTest {
+ @Rule
+ public final StandardOutputStreamLog log = new StandardOutputStreamLog();
+
+ @Autowired
+ private Performance performance;
+
+ @Test
+ public void testPerformance() {
+ performance.perform();
+ assertEquals("Silencing cell phones\n" +
+ "Taking seats\n" +
+ "Piano Solo\n" +
+ "CLAP CLAP CLAP!!!\n", log.getLog());
+ }
+}
diff --git a/Chapter_04/aop/src/test/java/concert/EncoreableTest.java b/Chapter_04/aop/src/test/java/concert/EncoreableTest.java
new file mode 100644
index 0000000..ec7513c
--- /dev/null
+++ b/Chapter_04/aop/src/test/java/concert/EncoreableTest.java
@@ -0,0 +1,27 @@
+package concert;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = ConcertConfig.class)
+public class EncoreableTest {
+ @Rule
+ public final StandardOutputStreamLog log = new StandardOutputStreamLog();
+
+ @Autowired
+ private Encoreable performance;
+
+ @Test
+ public void testPerformance() {
+ performance.performEncore();
+ assertEquals("Default encoreable\n", log.getLog());
+ }
+}
diff --git a/Chapter_04/aop/src/test/java/params/TrackCountTest.java b/Chapter_04/aop/src/test/java/params/TrackCountTest.java
new file mode 100644
index 0000000..b677b2a
--- /dev/null
+++ b/Chapter_04/aop/src/test/java/params/TrackCountTest.java
@@ -0,0 +1,40 @@
+package params;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = TrackCounterConfig.class)
+public class TrackCountTest {
+ @Autowired
+ private CompactDisc cd;
+
+ @Autowired
+ private TrackCounter counter;
+
+ @Test
+ public void testTrackCounter() {
+ cd.playTrack(1);
+ cd.playTrack(2);
+ cd.playTrack(3);
+ cd.playTrack(3);
+ cd.playTrack(3);
+ cd.playTrack(3);
+ cd.playTrack(6);
+ cd.playTrack(7);
+ cd.playTrack(7);
+
+ assertEquals(1, counter.getPlayCount(1));
+ assertEquals(1, counter.getPlayCount(2));
+ assertEquals(4, counter.getPlayCount(3));
+ assertEquals(0, counter.getPlayCount(4));
+ assertEquals(0, counter.getPlayCount(5));
+ assertEquals(1, counter.getPlayCount(6));
+ assertEquals(2, counter.getPlayCount(7));
+ }
+}