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/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/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/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);