diff --git a/README.md b/README.md
index d94a786bc2..271aea0767 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,14 @@
The "REST with Spring" Classes
==============================
+
After 5 months of work, here's the Master Class of REST With Spring:
**[>> THE REST WITH SPRING MASTER CLASS](http://www.baeldung.com/rest-with-spring-course?utm_source=github&utm_medium=social&utm_content=tutorials&utm_campaign=rws#master-class)**
+And here's the Master Class of Learn Spring Security:
+**[>> LEARN SPRING SECURITY MASTER CLASS](http://www.baeldung.com/learn-spring-security-course?utm_source=github&utm_medium=social&utm_content=tutorials&utm_campaign=lss#master-class)**
+
+
Spring Tutorials
================
diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java
new file mode 100644
index 0000000000..9b850c4153
--- /dev/null
+++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java
@@ -0,0 +1,33 @@
+package com.baeldung.concurrent.waitandnotify;
+
+public class Data {
+ private String packet;
+
+ // True if receiver should wait
+ // False if sender should wait
+ private boolean transfer = true;
+
+ public synchronized String receive() {
+ while (transfer) {
+ try {
+ wait();
+ } catch (InterruptedException e) {}
+ }
+ transfer = true;
+
+ notifyAll();
+ return packet;
+ }
+
+ public synchronized void send(String packet) {
+ while (!transfer) {
+ try {
+ wait();
+ } catch (InterruptedException e) {}
+ }
+ transfer = false;
+
+ this.packet = packet;
+ notifyAll();
+ }
+}
\ No newline at end of file
diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/NetworkDriver.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/NetworkDriver.java
new file mode 100644
index 0000000000..d4fd1574c6
--- /dev/null
+++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/NetworkDriver.java
@@ -0,0 +1,12 @@
+package com.baeldung.concurrent.waitandnotify;
+
+public class NetworkDriver {
+ public static void main(String[] args) {
+ Data data = new Data();
+ Thread sender = new Thread(new Sender(data));
+ Thread receiver = new Thread(new Receiver(data));
+
+ sender.start();
+ receiver.start();
+ }
+}
\ No newline at end of file
diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java
new file mode 100644
index 0000000000..63f48b8031
--- /dev/null
+++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java
@@ -0,0 +1,25 @@
+package com.baeldung.concurrent.waitandnotify;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+public class Receiver implements Runnable {
+ private Data load;
+
+ public Receiver(Data load) {
+ this.load = load;
+ }
+
+ public void run() {
+ for(String receivedMessage = load.receive();
+ !"End".equals(receivedMessage) ;
+ receivedMessage = load.receive()) {
+
+ System.out.println(receivedMessage);
+
+ //Thread.sleep() to mimic heavy server-side processing
+ try {
+ Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 5000));
+ } catch (InterruptedException e) {}
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java
new file mode 100644
index 0000000000..b7d782c3f5
--- /dev/null
+++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java
@@ -0,0 +1,30 @@
+package com.baeldung.concurrent.waitandnotify;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+public class Sender implements Runnable {
+ private Data data;
+
+ public Sender(Data data) {
+ this.data = data;
+ }
+
+ public void run() {
+ String packets[] = {
+ "First packet",
+ "Second packet",
+ "Third packet",
+ "Fourth packet",
+ "End"
+ };
+
+ for (String packet : packets) {
+ data.send(packet);
+
+ //Thread.sleep() to mimic heavy server-side processing
+ try {
+ Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 5000));
+ } catch (InterruptedException e) {}
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-java-concurrency/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java b/core-java-concurrency/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java
new file mode 100644
index 0000000000..49f4313e9d
--- /dev/null
+++ b/core-java-concurrency/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java
@@ -0,0 +1,65 @@
+package com.baeldung.concurrent.waitandnotify;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NetworkIntegrationTest {
+
+ private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+ private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
+ private String expected;
+
+ @Before
+ public void setUpStreams() {
+ System.setOut(new PrintStream(outContent));
+ System.setErr(new PrintStream(errContent));
+ }
+
+ @Before
+ public void setUpExpectedOutput() {
+ StringWriter expectedStringWriter = new StringWriter();
+
+ PrintWriter printWriter = new PrintWriter(expectedStringWriter);
+ printWriter.println("First packet");
+ printWriter.println("Second packet");
+ printWriter.println("Third packet");
+ printWriter.println("Fourth packet");
+ printWriter.close();
+
+ expected = expectedStringWriter.toString();
+ }
+
+ @After
+ public void cleanUpStreams() {
+ System.setOut(null);
+ System.setErr(null);
+ }
+
+ @Test
+ public void givenSenderAndReceiver_whenSendingPackets_thenNetworkSynchronized() {
+ Data data = new Data();
+ Thread sender = new Thread(new Sender(data));
+ Thread receiver = new Thread(new Receiver(data));
+
+ sender.start();
+ receiver.start();
+
+ //wait for sender and receiver to finish before we test against expected
+ try {
+ sender.join();
+ receiver.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ assertEquals(expected, outContent.toString());
+ }
+}
diff --git a/core-java/src/main/java/com/baeldung/nestedclass/Enclosing.java b/core-java/src/main/java/com/baeldung/nestedclass/Enclosing.java
deleted file mode 100644
index a9911538b0..0000000000
--- a/core-java/src/main/java/com/baeldung/nestedclass/Enclosing.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.baeldung.nestedclass;
-
-public class Enclosing {
-
- public static class Nested {
-
- public void test() {
- System.out.println("Calling test...");
- }
- }
-}
diff --git a/core-java/src/main/java/com/baeldung/nestedclass/Outer.java b/core-java/src/main/java/com/baeldung/nestedclass/Outer.java
deleted file mode 100644
index ebd6d27293..0000000000
--- a/core-java/src/main/java/com/baeldung/nestedclass/Outer.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.baeldung.nestedclass;
-
-public class Outer {
-
- public class Inner {
-
- public void test() {
- System.out.println("Calling test...");
- }
- }
-}
diff --git a/core-java/src/main/java/com/baeldung/nestedclass/SimpleAbstractClass.java b/core-java/src/main/java/com/baeldung/nestedclass/SimpleAbstractClass.java
deleted file mode 100644
index 586e2d12b4..0000000000
--- a/core-java/src/main/java/com/baeldung/nestedclass/SimpleAbstractClass.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.baeldung.nestedclass;
-
-abstract class SimpleAbstractClass {
- abstract void run();
-}
\ No newline at end of file
diff --git a/core-java/src/main/java/com/baeldung/polymorphism/FileManager.java b/core-java/src/main/java/com/baeldung/polymorphism/FileManager.java
new file mode 100644
index 0000000000..7f2665ff2d
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/polymorphism/FileManager.java
@@ -0,0 +1,38 @@
+package com.baeldung.polymorphism;
+
+import java.awt.image.BufferedImage;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FileManager {
+
+ final static Logger logger = LoggerFactory.getLogger(FileManager.class);
+
+ public static void main(String[] args) {
+ GenericFile file1 = new TextFile("SampleTextFile", "This is a sample text content", "v1.0.0");
+ logger.info("File Info: \n" + file1.getFileInfo() + "\n");
+ ImageFile imageFile = new ImageFile("SampleImageFile", 200, 100, new BufferedImage(100, 200, BufferedImage.TYPE_INT_RGB).toString()
+ .getBytes(), "v1.0.0");
+ logger.info("File Info: \n" + imageFile.getFileInfo());
+ }
+
+ public static ImageFile createImageFile(String name, int height, int width, byte[] content, String version) {
+ ImageFile imageFile = new ImageFile(name, height, width, content, version);
+ logger.info("File 2 Info: \n" + imageFile.getFileInfo());
+ return imageFile;
+ }
+
+ public static GenericFile createTextFile(String name, String content, String version) {
+ GenericFile file1 = new TextFile(name, content, version);
+ logger.info("File 1 Info: \n" + file1.getFileInfo() + "\n");
+ return file1;
+ }
+
+ public static TextFile createTextFile2(String name, String content, String version) {
+ TextFile file1 = new TextFile(name, content, version);
+ logger.info("File 1 Info: \n" + file1.getFileInfo() + "\n");
+ return file1;
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/polymorphism/GenericFile.java b/core-java/src/main/java/com/baeldung/polymorphism/GenericFile.java
new file mode 100644
index 0000000000..4075083c49
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/polymorphism/GenericFile.java
@@ -0,0 +1,63 @@
+package com.baeldung.polymorphism;
+
+import java.util.Date;
+
+public class GenericFile {
+ private String name;
+ private String extension;
+ private Date dateCreated;
+ private String version;
+ private byte[] content;
+
+ public GenericFile() {
+ this.setDateCreated(new Date());
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getExtension() {
+ return extension;
+ }
+
+ public void setExtension(String extension) {
+ this.extension = extension;
+ }
+
+ public Date getDateCreated() {
+ return dateCreated;
+ }
+
+ public void setDateCreated(Date dateCreated) {
+ this.dateCreated = dateCreated;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public byte[] getContent() {
+ return content;
+ }
+
+ public void setContent(byte[] content) {
+ this.content = content;
+ }
+
+ public String getFileInfo() {
+ return "File Name: " + this.getName() + "\n" + "Extension: " + this.getExtension() + "\n" + "Date Created: " + this.getDateCreated() + "\n" + "Version: " + this.getVersion() + "\n";
+ }
+
+ public Object read() {
+ return content;
+ }
+}
diff --git a/core-java/src/main/java/com/baeldung/polymorphism/ImageFile.java b/core-java/src/main/java/com/baeldung/polymorphism/ImageFile.java
new file mode 100644
index 0000000000..ac72a40993
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/polymorphism/ImageFile.java
@@ -0,0 +1,41 @@
+package com.baeldung.polymorphism;
+
+public class ImageFile extends GenericFile {
+ private int height;
+ private int width;
+
+ public ImageFile(String name, int height, int width, byte[] content, String version) {
+ this.setHeight(height);
+ this.setWidth(width);
+ this.setContent(content);
+ this.setName(name);
+ this.setVersion(version);
+ this.setExtension(".jpg");
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public String getFileInfo() {
+ return super.getFileInfo() + "Height: " + this.getHeight() + "\n" + "Width: " + this.getWidth();
+ }
+
+ public String read() {
+ return this.getContent()
+ .toString();
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/polymorphism/TextFile.java b/core-java/src/main/java/com/baeldung/polymorphism/TextFile.java
new file mode 100644
index 0000000000..8280b4ee95
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/polymorphism/TextFile.java
@@ -0,0 +1,44 @@
+package com.baeldung.polymorphism;
+
+public class TextFile extends GenericFile {
+ private int wordCount;
+
+ public TextFile(String name, String content, String version) {
+ String[] words = content.split(" ");
+ this.setWordCount(words.length > 0 ? words.length : 1);
+ this.setContent(content.getBytes());
+ this.setName(name);
+ this.setVersion(version);
+ this.setExtension(".txt");
+ }
+
+ public int getWordCount() {
+ return wordCount;
+ }
+
+ public void setWordCount(int wordCount) {
+ this.wordCount = wordCount;
+ }
+
+ public String getFileInfo() {
+ return super.getFileInfo() + "Word Count: " + wordCount;
+ }
+
+ public String read() {
+ return this.getContent()
+ .toString();
+ }
+
+ public String read(int limit) {
+ return this.getContent()
+ .toString()
+ .substring(0, limit);
+ }
+
+ public String read(int start, int stop) {
+ return this.getContent()
+ .toString()
+ .substring(start, stop);
+ }
+
+}
diff --git a/core-java/src/test/java/com/baeldung/nestedclass/AnonymousInnerTest.java b/core-java/src/test/java/com/baeldung/nestedclass/AnonymousInner.java
similarity index 71%
rename from core-java/src/test/java/com/baeldung/nestedclass/AnonymousInnerTest.java
rename to core-java/src/test/java/com/baeldung/nestedclass/AnonymousInner.java
index 394c0bb57a..9fa8ee9cd5 100644
--- a/core-java/src/test/java/com/baeldung/nestedclass/AnonymousInnerTest.java
+++ b/core-java/src/test/java/com/baeldung/nestedclass/AnonymousInner.java
@@ -2,10 +2,14 @@ package com.baeldung.nestedclass;
import org.junit.Test;
-public class AnonymousInnerTest {
+abstract class SimpleAbstractClass {
+ abstract void run();
+}
+
+public class AnonymousInner {
@Test
- public void whenRunAnonymousClass_thenCorrect() {
+ public void run() {
SimpleAbstractClass simpleAbstractClass = new SimpleAbstractClass() {
void run() {
System.out.println("Running Anonymous Class...");
diff --git a/core-java/src/test/java/com/baeldung/nestedclass/Enclosing.java b/core-java/src/test/java/com/baeldung/nestedclass/Enclosing.java
new file mode 100644
index 0000000000..3db33cde9b
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/nestedclass/Enclosing.java
@@ -0,0 +1,21 @@
+package com.baeldung.nestedclass;
+
+import org.junit.Test;
+
+public class Enclosing {
+
+ private static int x = 1;
+
+ public static class StaticNested {
+
+ private void run() {
+ System.out.println("x = " + x);
+ }
+ }
+
+ @Test
+ public void test() {
+ Enclosing.StaticNested nested = new Enclosing.StaticNested();
+ nested.run();
+ }
+}
diff --git a/core-java/src/test/java/com/baeldung/nestedclass/InnerClassTest.java b/core-java/src/test/java/com/baeldung/nestedclass/InnerClassTest.java
deleted file mode 100644
index e9cb119ac2..0000000000
--- a/core-java/src/test/java/com/baeldung/nestedclass/InnerClassTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.baeldung.nestedclass;
-
-import org.junit.Test;
-
-public class InnerClassTest {
-
- @Test
- public void givenInnerClassWhenInstantiating_thenCorrect() {
- Outer outer = new Outer();
- Outer.Inner inner = outer.new Inner();
- inner.test();
- }
-}
diff --git a/core-java/src/test/java/com/baeldung/nestedclass/LocalClassTest.java b/core-java/src/test/java/com/baeldung/nestedclass/LocalClassTest.java
deleted file mode 100644
index dad19161ad..0000000000
--- a/core-java/src/test/java/com/baeldung/nestedclass/LocalClassTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.baeldung.nestedclass;
-
-import org.junit.Test;
-
-public class LocalClassTest {
-
- @Test
- public void whenTestingLocalClass_thenCorrect() {
- NewEnclosing newEnclosing = new NewEnclosing();
- newEnclosing.run();
- }
-}
diff --git a/core-java/src/test/java/com/baeldung/nestedclass/NestedClassTest.java b/core-java/src/test/java/com/baeldung/nestedclass/NestedClassTest.java
deleted file mode 100644
index 16c883689a..0000000000
--- a/core-java/src/test/java/com/baeldung/nestedclass/NestedClassTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.baeldung.nestedclass;
-
-import org.junit.Test;
-
-public class NestedClassTest {
-
- @Test
- public void whenInstantiatingStaticNestedClass_thenCorrect() {
- Enclosing.Nested nested = new Enclosing.Nested();
- nested.test();
- }
-}
diff --git a/core-java/src/main/java/com/baeldung/nestedclass/NewEnclosing.java b/core-java/src/test/java/com/baeldung/nestedclass/NewEnclosing.java
similarity index 59%
rename from core-java/src/main/java/com/baeldung/nestedclass/NewEnclosing.java
rename to core-java/src/test/java/com/baeldung/nestedclass/NewEnclosing.java
index c7e04e8600..deeb72de0c 100644
--- a/core-java/src/main/java/com/baeldung/nestedclass/NewEnclosing.java
+++ b/core-java/src/test/java/com/baeldung/nestedclass/NewEnclosing.java
@@ -1,10 +1,11 @@
package com.baeldung.nestedclass;
+import org.junit.Test;
+
public class NewEnclosing {
- void run() {
+ private void run() {
class Local {
-
void run() {
System.out.println("Welcome to Baeldung!");
}
@@ -12,4 +13,10 @@ public class NewEnclosing {
Local local = new Local();
local.run();
}
+
+ @Test
+ public void test() {
+ NewEnclosing newEnclosing = new NewEnclosing();
+ newEnclosing.run();
+ }
}
\ No newline at end of file
diff --git a/core-java/src/test/java/com/baeldung/nestedclass/NewOuter.java b/core-java/src/test/java/com/baeldung/nestedclass/NewOuter.java
new file mode 100644
index 0000000000..a3a723b30e
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/nestedclass/NewOuter.java
@@ -0,0 +1,30 @@
+package com.baeldung.nestedclass;
+
+import org.junit.Test;
+
+public class NewOuter {
+
+ int a = 1;
+ static int b = 2;
+
+ public class InnerClass {
+ int a = 3;
+ static final int b = 4;
+
+ public void run() {
+ System.out.println("a = " + a);
+ System.out.println("b = " + b);
+ System.out.println("NewOuterTest.this.a = " + NewOuter.this.a);
+ System.out.println("NewOuterTest.b = " + NewOuter.b);
+ System.out.println("NewOuterTest.this.b = " + NewOuter.this.b);
+ }
+ }
+
+ @Test
+ public void test() {
+ NewOuter outer = new NewOuter();
+ NewOuter.InnerClass inner = outer.new InnerClass();
+ inner.run();
+
+ }
+}
\ No newline at end of file
diff --git a/core-java/src/test/java/com/baeldung/nestedclass/NewOuterTest.java b/core-java/src/test/java/com/baeldung/nestedclass/NewOuterTest.java
deleted file mode 100644
index e883687d33..0000000000
--- a/core-java/src/test/java/com/baeldung/nestedclass/NewOuterTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.baeldung.nestedclass;
-
-import static org.junit.Assert.assertEquals;
-import org.junit.Test;
-
-public class NewOuterTest {
-
- int a = 1;
- static int b = 2;
-
- public class InnerClass {
- int a = 3;
- static final int b = 4;
-
- @Test
- public void whenShadowing_thenCorrect() {
- assertEquals(3, a);
- assertEquals(4, b);
- assertEquals(1, NewOuterTest.this.a);
- assertEquals(2, NewOuterTest.b);
- assertEquals(2, NewOuterTest.this.b);
- }
- }
-
- @Test
- public void shadowingTest() {
- NewOuterTest outer = new NewOuterTest();
- NewOuterTest.InnerClass inner = outer.new InnerClass();
- inner.whenShadowing_thenCorrect();
-
- }
-}
\ No newline at end of file
diff --git a/core-java/src/test/java/com/baeldung/nestedclass/Outer.java b/core-java/src/test/java/com/baeldung/nestedclass/Outer.java
new file mode 100644
index 0000000000..d5e46670c9
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/nestedclass/Outer.java
@@ -0,0 +1,20 @@
+package com.baeldung.nestedclass;
+
+import org.junit.Test;
+
+public class Outer {
+
+ public class Inner {
+
+ public void run() {
+ System.out.println("Calling test...");
+ }
+ }
+
+ @Test
+ public void test() {
+ Outer outer = new Outer();
+ Outer.Inner inner = outer.new Inner();
+ inner.run();
+ }
+}
diff --git a/core-java/src/test/java/com/baeldung/polymorphism/PolymorphismUnitTest.java b/core-java/src/test/java/com/baeldung/polymorphism/PolymorphismUnitTest.java
new file mode 100644
index 0000000000..8fb606c2fc
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/polymorphism/PolymorphismUnitTest.java
@@ -0,0 +1,34 @@
+package com.baeldung.polymorphism;
+
+import static org.junit.Assert.*;
+
+import java.awt.image.BufferedImage;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class PolymorphismUnitTest {
+
+ @Test
+ public void givenImageFile_whenFileCreated_shouldSucceed() {
+ ImageFile imageFile = FileManager.createImageFile("SampleImageFile", 200, 100, new BufferedImage(100, 200, BufferedImage.TYPE_INT_RGB).toString()
+ .getBytes(), "v1.0.0");
+ assertEquals(200, imageFile.getHeight());
+ }
+
+ // Downcasting then Upcasting
+ @Test
+ public void givenTextFile_whenTextFileCreatedAndAssignedToGenericFileAndCastBackToTextFileOnGetWordCount_shouldSucceed() {
+ GenericFile textFile = FileManager.createTextFile("SampleTextFile", "This is a sample text content", "v1.0.0");
+ TextFile textFile2 = (TextFile) textFile;
+ assertEquals(6, textFile2.getWordCount());
+ }
+
+ // Downcasting
+ @Test(expected = ClassCastException.class)
+ public void givenGenericFile_whenCastToTextFileAndInvokeGetWordCount_shouldFail() {
+ GenericFile genericFile = new GenericFile();
+ TextFile textFile = (TextFile) genericFile;
+ System.out.println(textFile.getWordCount());
+ }
+}
diff --git a/guava-modules/guava-18/pom.xml b/guava-modules/guava-18/pom.xml
index a9aba47f12..f8dbf5657e 100644
--- a/guava-modules/guava-18/pom.xml
+++ b/guava-modules/guava-18/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/guava-modules/guava-19/pom.xml b/guava-modules/guava-19/pom.xml
index 2345212eba..4a23bf7aec 100644
--- a/guava-modules/guava-19/pom.xml
+++ b/guava-modules/guava-19/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/guava-modules/guava-21/pom.xml b/guava-modules/guava-21/pom.xml
index 94bb66e76a..f5432fb7df 100644
--- a/guava-modules/guava-21/pom.xml
+++ b/guava-modules/guava-21/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/logging-modules/log-mdc/pom.xml b/logging-modules/log-mdc/pom.xml
index 918e052a15..5551585372 100644
--- a/logging-modules/log-mdc/pom.xml
+++ b/logging-modules/log-mdc/pom.xml
@@ -12,7 +12,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/logging-modules/log4j/pom.xml b/logging-modules/log4j/pom.xml
index a3bfb0a33a..6a3fbde393 100644
--- a/logging-modules/log4j/pom.xml
+++ b/logging-modules/log4j/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/logging-modules/log4j2/pom.xml b/logging-modules/log4j2/pom.xml
index 58bc4b74e7..48608fbc80 100644
--- a/logging-modules/log4j2/pom.xml
+++ b/logging-modules/log4j2/pom.xml
@@ -9,7 +9,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/java-cassandra/pom.xml b/persistence-modules/java-cassandra/pom.xml
index faaabb9e2e..81e072c3a7 100644
--- a/persistence-modules/java-cassandra/pom.xml
+++ b/persistence-modules/java-cassandra/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/java-mongodb/pom.xml b/persistence-modules/java-mongodb/pom.xml
index aab48921a6..9784b2c5a8 100644
--- a/persistence-modules/java-mongodb/pom.xml
+++ b/persistence-modules/java-mongodb/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/liquibase/pom.xml b/persistence-modules/liquibase/pom.xml
index 020c2516a2..a574ba497c 100644
--- a/persistence-modules/liquibase/pom.xml
+++ b/persistence-modules/liquibase/pom.xml
@@ -6,7 +6,7 @@
parent-modules
com.baeldung
1.0.0-SNAPSHOT
- ../
+ ../../
4.0.0
diff --git a/persistence-modules/querydsl/pom.xml b/persistence-modules/querydsl/pom.xml
index 27f383e0c6..c2943875f1 100644
--- a/persistence-modules/querydsl/pom.xml
+++ b/persistence-modules/querydsl/pom.xml
@@ -15,7 +15,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/redis/pom.xml b/persistence-modules/redis/pom.xml
index ef081a2c69..4321b491eb 100644
--- a/persistence-modules/redis/pom.xml
+++ b/persistence-modules/redis/pom.xml
@@ -15,7 +15,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/solr/pom.xml b/persistence-modules/solr/pom.xml
index 2fd0bdd721..966bd8755b 100644
--- a/persistence-modules/solr/pom.xml
+++ b/persistence-modules/solr/pom.xml
@@ -12,7 +12,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/spring-data-cassandra/pom.xml b/persistence-modules/spring-data-cassandra/pom.xml
index 607d7b90ba..1358210a45 100644
--- a/persistence-modules/spring-data-cassandra/pom.xml
+++ b/persistence-modules/spring-data-cassandra/pom.xml
@@ -13,7 +13,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/spring-data-gemfire/pom.xml b/persistence-modules/spring-data-gemfire/pom.xml
index 9108865b4c..3f7fcd03e5 100644
--- a/persistence-modules/spring-data-gemfire/pom.xml
+++ b/persistence-modules/spring-data-gemfire/pom.xml
@@ -12,7 +12,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/spring-data-neo4j/pom.xml b/persistence-modules/spring-data-neo4j/pom.xml
index 0055850ec3..bdd51e9659 100644
--- a/persistence-modules/spring-data-neo4j/pom.xml
+++ b/persistence-modules/spring-data-neo4j/pom.xml
@@ -10,7 +10,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/spring-data-redis/pom.xml b/persistence-modules/spring-data-redis/pom.xml
index b184d7e369..6cb49f11cf 100644
--- a/persistence-modules/spring-data-redis/pom.xml
+++ b/persistence-modules/spring-data-redis/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/spring-data-solr/pom.xml b/persistence-modules/spring-data-solr/pom.xml
index 0759c1dbc0..e24d8314ba 100644
--- a/persistence-modules/spring-data-solr/pom.xml
+++ b/persistence-modules/spring-data-solr/pom.xml
@@ -12,7 +12,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/spring-hibernate-3/pom.xml b/persistence-modules/spring-hibernate-3/pom.xml
index 8eee819572..f1873a84d3 100644
--- a/persistence-modules/spring-hibernate-3/pom.xml
+++ b/persistence-modules/spring-hibernate-3/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/persistence-modules/spring-hibernate-5/pom.xml b/persistence-modules/spring-hibernate-5/pom.xml
index f1f3d10347..57eb1aeffb 100644
--- a/persistence-modules/spring-hibernate-5/pom.xml
+++ b/persistence-modules/spring-hibernate-5/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/pom.xml b/pom.xml
index 9b1f50f05e..cac0cc5845 100644
--- a/pom.xml
+++ b/pom.xml
@@ -141,6 +141,7 @@
spark-java
spring-5-mvc
+ spring-acl
spring-activiti
spring-akka
spring-amqp
diff --git a/spring-acl/pom.xml b/spring-acl/pom.xml
new file mode 100644
index 0000000000..3bcc0cf596
--- /dev/null
+++ b/spring-acl/pom.xml
@@ -0,0 +1,66 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-acl
+ 0.0.1-SNAPSHOT
+ war
+
+ spring-acl
+ Spring ACL
+
+
+ parent-boot-5
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-5
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ com.h2database
+ h2
+
+
+
+ org.springframework
+ spring-test
+ test
+
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+
+ org.springframework.security
+ spring-security-acl
+
+
+ org.springframework.security
+ spring-security-config
+
+
+ org.springframework
+ spring-context-support
+
+
+ net.sf.ehcache
+ ehcache-core
+ 2.6.11
+ jar
+
+
+
+
+
diff --git a/spring-acl/src/main/java/org/baeldung/acl/config/ACLContext.java b/spring-acl/src/main/java/org/baeldung/acl/config/ACLContext.java
new file mode 100644
index 0000000000..63a4ea58ef
--- /dev/null
+++ b/spring-acl/src/main/java/org/baeldung/acl/config/ACLContext.java
@@ -0,0 +1,80 @@
+package org.baeldung.acl.config;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.cache.ehcache.EhCacheFactoryBean;
+import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
+import org.springframework.security.acls.AclPermissionCacheOptimizer;
+import org.springframework.security.acls.AclPermissionEvaluator;
+import org.springframework.security.acls.domain.AclAuthorizationStrategy;
+import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
+import org.springframework.security.acls.domain.ConsoleAuditLogger;
+import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
+import org.springframework.security.acls.domain.EhCacheBasedAclCache;
+import org.springframework.security.acls.jdbc.BasicLookupStrategy;
+import org.springframework.security.acls.jdbc.JdbcMutableAclService;
+import org.springframework.security.acls.jdbc.LookupStrategy;
+import org.springframework.security.acls.model.PermissionGrantingStrategy;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+@Configuration
+@EnableAutoConfiguration
+public class ACLContext {
+
+ @Autowired
+ DataSource dataSource;
+
+ @Bean
+ public EhCacheBasedAclCache aclCache() {
+ return new EhCacheBasedAclCache(aclEhCacheFactoryBean().getObject(), permissionGrantingStrategy(), aclAuthorizationStrategy());
+ }
+
+ @Bean
+ public EhCacheFactoryBean aclEhCacheFactoryBean() {
+ EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
+ ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
+ ehCacheFactoryBean.setCacheName("aclCache");
+ return ehCacheFactoryBean;
+ }
+
+ @Bean
+ public EhCacheManagerFactoryBean aclCacheManager() {
+ return new EhCacheManagerFactoryBean();
+ }
+
+ @Bean
+ public PermissionGrantingStrategy permissionGrantingStrategy() {
+ return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
+ }
+
+ @Bean
+ public AclAuthorizationStrategy aclAuthorizationStrategy() {
+ return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMIN"));
+ }
+
+ @Bean
+ public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
+ DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
+ AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());
+ expressionHandler.setPermissionEvaluator(permissionEvaluator);
+ expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
+ return expressionHandler;
+ }
+
+ @Bean
+ public LookupStrategy lookupStrategy() {
+ return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
+ }
+
+ @Bean
+ public JdbcMutableAclService aclService() {
+ return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
+ }
+
+}
\ No newline at end of file
diff --git a/spring-acl/src/main/java/org/baeldung/acl/config/AclMethodSecurityConfiguration.java b/spring-acl/src/main/java/org/baeldung/acl/config/AclMethodSecurityConfiguration.java
new file mode 100644
index 0000000000..110c4a6d24
--- /dev/null
+++ b/spring-acl/src/main/java/org/baeldung/acl/config/AclMethodSecurityConfiguration.java
@@ -0,0 +1,21 @@
+package org.baeldung.acl.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
+
+@Configuration
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
+public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
+
+ @Autowired
+ MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
+
+ @Override
+ protected MethodSecurityExpressionHandler createExpressionHandler() {
+ return defaultMethodSecurityExpressionHandler;
+ }
+
+}
diff --git a/spring-acl/src/main/java/org/baeldung/acl/config/JPAPersistenceConfig.java b/spring-acl/src/main/java/org/baeldung/acl/config/JPAPersistenceConfig.java
new file mode 100644
index 0000000000..9b87efa92c
--- /dev/null
+++ b/spring-acl/src/main/java/org/baeldung/acl/config/JPAPersistenceConfig.java
@@ -0,0 +1,16 @@
+package org.baeldung.acl.config;
+
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@EnableTransactionManagement
+@EnableJpaRepositories(basePackages = "org.baeldung.acl.persistence.dao")
+@PropertySource("classpath:org.baeldung.acl.datasource.properties")
+@EntityScan(basePackages={ "org.baeldung.acl.persistence.entity" })
+public class JPAPersistenceConfig {
+
+}
diff --git a/spring-acl/src/main/java/org/baeldung/acl/persistence/dao/NoticeMessageRepository.java b/spring-acl/src/main/java/org/baeldung/acl/persistence/dao/NoticeMessageRepository.java
new file mode 100644
index 0000000000..8662c88d6c
--- /dev/null
+++ b/spring-acl/src/main/java/org/baeldung/acl/persistence/dao/NoticeMessageRepository.java
@@ -0,0 +1,24 @@
+package org.baeldung.acl.persistence.dao;
+
+import java.util.List;
+
+import org.baeldung.acl.persistence.entity.NoticeMessage;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.security.access.prepost.PostAuthorize;
+import org.springframework.security.access.prepost.PostFilter;
+import org.springframework.security.access.prepost.PreAuthorize;
+
+public interface NoticeMessageRepository extends JpaRepository{
+
+ @PostFilter("hasPermission(filterObject, 'READ')")
+ List findAll();
+
+ @PostAuthorize("hasPermission(returnObject, 'READ')")
+ NoticeMessage findById(Integer id);
+
+ @SuppressWarnings("unchecked")
+ @PreAuthorize("hasPermission(#noticeMessage, 'WRITE')")
+ NoticeMessage save(@Param("noticeMessage")NoticeMessage noticeMessage);
+
+}
diff --git a/spring-acl/src/main/java/org/baeldung/acl/persistence/entity/NoticeMessage.java b/spring-acl/src/main/java/org/baeldung/acl/persistence/entity/NoticeMessage.java
new file mode 100644
index 0000000000..23f01a8edb
--- /dev/null
+++ b/spring-acl/src/main/java/org/baeldung/acl/persistence/entity/NoticeMessage.java
@@ -0,0 +1,29 @@
+package org.baeldung.acl.persistence.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="system_message")
+public class NoticeMessage {
+
+ @Id
+ @Column
+ private Integer id;
+ @Column
+ private String content;
+ public Integer getId() {
+ return id;
+ }
+ public void setId(Integer id) {
+ this.id = id;
+ }
+ public String getContent() {
+ return content;
+ }
+ public void setContent(String content) {
+ this.content = content;
+ }
+}
\ No newline at end of file
diff --git a/spring-acl/src/main/resources/acl-data.sql b/spring-acl/src/main/resources/acl-data.sql
new file mode 100644
index 0000000000..6c01eaacc2
--- /dev/null
+++ b/spring-acl/src/main/resources/acl-data.sql
@@ -0,0 +1,28 @@
+INSERT INTO system_message(id,content) VALUES (1,'First Level Message');
+INSERT INTO system_message(id,content) VALUES (2,'Second Level Message');
+INSERT INTO system_message(id,content) VALUES (3,'Third Level Message');
+
+INSERT INTO acl_class (id, class) VALUES
+(1, 'org.baeldung.acl.persistence.entity.NoticeMessage');
+
+INSERT INTO acl_sid (id, principal, sid) VALUES
+(1, 1, 'manager'),
+(2, 1, 'hr'),
+(3, 1, 'admin'),
+(4, 0, 'ROLE_EDITOR');
+
+INSERT INTO acl_object_identity (id, object_id_class, object_id_identity, parent_object, owner_sid, entries_inheriting) VALUES
+(1, 1, 1, NULL, 3, 0),
+(2, 1, 2, NULL, 3, 0),
+(3, 1, 3, NULL, 3, 0)
+;
+
+INSERT INTO acl_entry (id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) VALUES
+(1, 1, 1, 1, 1, 1, 1, 1),
+(2, 1, 2, 1, 2, 1, 1, 1),
+(3, 1, 3, 4, 1, 1, 1, 1),
+(4, 2, 1, 2, 1, 1, 1, 1),
+(5, 2, 2, 4, 1, 1, 1, 1),
+(6, 3, 1, 4, 1, 1, 1, 1),
+(7, 3, 2, 4, 2, 1, 1, 1)
+;
\ No newline at end of file
diff --git a/spring-acl/src/main/resources/acl-schema.sql b/spring-acl/src/main/resources/acl-schema.sql
new file mode 100644
index 0000000000..58e9394b2b
--- /dev/null
+++ b/spring-acl/src/main/resources/acl-schema.sql
@@ -0,0 +1,58 @@
+create table system_message (id integer not null, content varchar(255), primary key (id));
+
+CREATE TABLE IF NOT EXISTS acl_sid (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ principal tinyint(1) NOT NULL,
+ sid varchar(100) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_uk_1 (sid,principal)
+);
+
+CREATE TABLE IF NOT EXISTS acl_class (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ class varchar(255) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_uk_2 (class)
+);
+
+CREATE TABLE IF NOT EXISTS acl_entry (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ acl_object_identity bigint(20) NOT NULL,
+ ace_order int(11) NOT NULL,
+ sid bigint(20) NOT NULL,
+ mask int(11) NOT NULL,
+ granting tinyint(1) NOT NULL,
+ audit_success tinyint(1) NOT NULL,
+ audit_failure tinyint(1) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_uk_4 (acl_object_identity,ace_order)
+);
+
+CREATE TABLE IF NOT EXISTS acl_object_identity (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ object_id_class bigint(20) NOT NULL,
+ object_id_identity bigint(20) NOT NULL,
+ parent_object bigint(20) DEFAULT NULL,
+ owner_sid bigint(20) DEFAULT NULL,
+ entries_inheriting tinyint(1) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_uk_3 (object_id_class,object_id_identity)
+);
+
+ALTER TABLE acl_entry
+ADD FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id);
+
+ALTER TABLE acl_entry
+ADD FOREIGN KEY (sid) REFERENCES acl_sid(id);
+
+--
+-- Constraints for table acl_object_identity
+--
+ALTER TABLE acl_object_identity
+ADD FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id);
+
+ALTER TABLE acl_object_identity
+ADD FOREIGN KEY (object_id_class) REFERENCES acl_class (id);
+
+ALTER TABLE acl_object_identity
+ADD FOREIGN KEY (owner_sid) REFERENCES acl_sid (id);
\ No newline at end of file
diff --git a/spring-acl/src/main/resources/org.baeldung.acl.datasource.properties b/spring-acl/src/main/resources/org.baeldung.acl.datasource.properties
new file mode 100644
index 0000000000..739dd3f07c
--- /dev/null
+++ b/spring-acl/src/main/resources/org.baeldung.acl.datasource.properties
@@ -0,0 +1,12 @@
+spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
+spring.datasource.username=sa
+spring.datasource.password=
+spring.datasource.driverClassName=org.h2.Driver
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
+
+spring.h2.console.path=/myconsole
+spring.h2.console.enabled=true
+spring.datasource.initialize=true
+spring.datasource.schema=classpath:acl-schema.sql
+spring.datasource.data=classpath:acl-data.sql
\ No newline at end of file
diff --git a/spring-acl/src/test/java/org/baeldung/acl/SpringAclTest.java b/spring-acl/src/test/java/org/baeldung/acl/SpringAclTest.java
new file mode 100644
index 0000000000..fd9069d9bc
--- /dev/null
+++ b/spring-acl/src/test/java/org/baeldung/acl/SpringAclTest.java
@@ -0,0 +1,119 @@
+package org.baeldung.acl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+
+import org.baeldung.acl.persistence.dao.NoticeMessageRepository;
+import org.baeldung.acl.persistence.entity.NoticeMessage;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
+import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
+import org.springframework.test.context.web.ServletTestExecutionListener;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
+ DependencyInjectionTestExecutionListener.class,
+ DirtiesContextTestExecutionListener.class,
+ TransactionalTestExecutionListener.class,
+ WithSecurityContextTestExecutionListener.class})
+public class SpringAclTest extends AbstractJUnit4SpringContextTests{
+
+ private static Integer FIRST_MESSAGE_ID = 1;
+ private static Integer SECOND_MESSAGE_ID = 2;
+ private static Integer THIRD_MESSAGE_ID = 3;
+ private static String EDITTED_CONTENT = "EDITED";
+
+ @Configuration
+ @ComponentScan("org.baeldung.acl.*")
+ public static class SpringConfig {
+
+ }
+
+ @Autowired
+ NoticeMessageRepository repo;
+
+ @Test
+ @WithMockUser(username="manager")
+ public void givenUsernameManager_whenFindAllMessage_thenReturnFirstMessage(){
+ List details = repo.findAll();
+ assertNotNull(details);
+ assertEquals(1,details.size());
+ assertEquals(FIRST_MESSAGE_ID,details.get(0).getId());
+ }
+
+ @Test
+ @WithMockUser(username="manager")
+ public void givenUsernameManager_whenFindFirstMessageByIdAndUpdateFirstMessageContent_thenOK(){
+ NoticeMessage firstMessage = repo.findById(FIRST_MESSAGE_ID);
+ assertNotNull(firstMessage);
+ assertEquals(FIRST_MESSAGE_ID,firstMessage.getId());
+
+ firstMessage.setContent(EDITTED_CONTENT);
+ repo.save(firstMessage);
+
+ NoticeMessage editedFirstMessage = repo.findById(FIRST_MESSAGE_ID);
+ assertNotNull(editedFirstMessage);
+ assertEquals(FIRST_MESSAGE_ID,editedFirstMessage.getId());
+ assertEquals(EDITTED_CONTENT,editedFirstMessage.getContent());
+ }
+
+ @Test
+ @WithMockUser(username="hr")
+ public void givenUsernameHr_whenFindMessageById2_thenOK(){
+ NoticeMessage secondMessage = repo.findById(SECOND_MESSAGE_ID);
+ assertNotNull(secondMessage);
+ assertEquals(SECOND_MESSAGE_ID,secondMessage.getId());
+ }
+
+ @Test(expected=AccessDeniedException.class)
+ @WithMockUser(username="hr")
+ public void givenUsernameHr_whenUpdateMessageWithId2_thenFail(){
+ NoticeMessage secondMessage = new NoticeMessage();
+ secondMessage.setId(SECOND_MESSAGE_ID);
+ secondMessage.setContent(EDITTED_CONTENT);
+ repo.save(secondMessage);
+ }
+
+ @Test
+ @WithMockUser(roles={"EDITOR"})
+ public void givenRoleEditor_whenFindAllMessage_thenReturnThreeMessage(){
+ List details = repo.findAll();
+ assertNotNull(details);
+ assertEquals(3,details.size());
+ }
+
+ @Test
+ @WithMockUser(roles={"EDITOR"})
+ public void givenRoleEditor_whenUpdateThirdMessage_thenOK(){
+ NoticeMessage thirdMessage = new NoticeMessage();
+ thirdMessage.setId(THIRD_MESSAGE_ID);
+ thirdMessage.setContent(EDITTED_CONTENT);
+ repo.save(thirdMessage);
+ }
+
+ @Test(expected=AccessDeniedException.class)
+ @WithMockUser(roles={"EDITOR"})
+ public void givenRoleEditor_whenFindFirstMessageByIdAndUpdateFirstMessageContent_thenFail(){
+ NoticeMessage firstMessage = repo.findById(FIRST_MESSAGE_ID);
+ assertNotNull(firstMessage);
+ assertEquals(FIRST_MESSAGE_ID,firstMessage.getId());
+ firstMessage.setContent(EDITTED_CONTENT);
+ repo.save(firstMessage);
+ }
+}
+
\ No newline at end of file
diff --git a/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java b/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java
index b3c98c3e71..8a40744bdc 100644
--- a/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java
+++ b/spring-security-mvc-boot/src/main/java/org/baeldung/Application.java
@@ -5,12 +5,13 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.FilterType;
@Configuration
@EnableAutoConfiguration
-@ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.voter.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multipleauthproviders.*"),
- @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multiplelogin.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multipleentrypoints.*") })
+@ComponentScan({ "org.baeldung.config", "org.baeldung.persistence", "org.baeldung.security", "org.baeldung.web" })
+// @ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.voter.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multipleauthproviders.*"),
+// @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multiplelogin.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.multipleentrypoints.*"),
+// @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.rolesauthorities.*"), @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.baeldung.acl.*") })
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
diff --git a/testing-modules/groovy-spock/pom.xml b/testing-modules/groovy-spock/pom.xml
index f4e61e6786..3d67657224 100644
--- a/testing-modules/groovy-spock/pom.xml
+++ b/testing-modules/groovy-spock/pom.xml
@@ -17,7 +17,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/testing-modules/junit-5/pom.xml b/testing-modules/junit-5/pom.xml
index 2be8937d04..684a9253d5 100644
--- a/testing-modules/junit-5/pom.xml
+++ b/testing-modules/junit-5/pom.xml
@@ -14,7 +14,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/testing-modules/mockito-2/pom.xml b/testing-modules/mockito-2/pom.xml
index 0291ac4ec1..2d119ae8af 100644
--- a/testing-modules/mockito-2/pom.xml
+++ b/testing-modules/mockito-2/pom.xml
@@ -12,7 +12,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/testing-modules/mockito/pom.xml b/testing-modules/mockito/pom.xml
index aa3dd9b20a..0e83c46926 100644
--- a/testing-modules/mockito/pom.xml
+++ b/testing-modules/mockito/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/testing-modules/mocks/pom.xml b/testing-modules/mocks/pom.xml
index 959c1851d6..6473f07c13 100644
--- a/testing-modules/mocks/pom.xml
+++ b/testing-modules/mocks/pom.xml
@@ -6,7 +6,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
mocks
diff --git a/testing-modules/rest-assured/pom.xml b/testing-modules/rest-assured/pom.xml
index 0c0826c5c3..1006e9a373 100644
--- a/testing-modules/rest-assured/pom.xml
+++ b/testing-modules/rest-assured/pom.xml
@@ -10,7 +10,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/testing-modules/rest-testing/pom.xml b/testing-modules/rest-testing/pom.xml
index 4b838720da..ea63ee0e58 100644
--- a/testing-modules/rest-testing/pom.xml
+++ b/testing-modules/rest-testing/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/testing-modules/selenium-junit-testng/pom.xml b/testing-modules/selenium-junit-testng/pom.xml
index 14169e5749..418dd495a4 100644
--- a/testing-modules/selenium-junit-testng/pom.xml
+++ b/testing-modules/selenium-junit-testng/pom.xml
@@ -9,7 +9,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/testing-modules/testing/pom.xml b/testing-modules/testing/pom.xml
index 3ad503558f..7aff0a93e0 100644
--- a/testing-modules/testing/pom.xml
+++ b/testing-modules/testing/pom.xml
@@ -10,7 +10,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../
diff --git a/testing-modules/testng/pom.xml b/testing-modules/testng/pom.xml
index f7a50954fc..7aed1837e5 100644
--- a/testing-modules/testng/pom.xml
+++ b/testing-modules/testng/pom.xml
@@ -11,7 +11,7 @@
com.baeldung
parent-modules
1.0.0-SNAPSHOT
- ../
+ ../../