diff --git a/algorithms/src/main/java/com/baeldung/algorithms/BinarySearch.java b/algorithms/src/main/java/com/baeldung/algorithms/BinarySearch.java
new file mode 100644
index 0000000000..be4a9e578a
--- /dev/null
+++ b/algorithms/src/main/java/com/baeldung/algorithms/BinarySearch.java
@@ -0,0 +1,26 @@
+public class BinarySearch {
+
+ public int runBinarySearch() {
+ int[] sortedArray = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9 };
+ int key = 6;
+
+ int low = 0;
+ int high = sortedArray.length - 1;
+ int index = Integer.MAX_VALUE;
+
+ while (low <= high) {
+
+ int mid = (low + high) / 2;
+
+ if (sortedArray[mid] < key) {
+ low = mid + 1;
+ } else if (sortedArray[mid] > key) {
+ high = mid - 1;
+ } else if (sortedArray[mid] == key) {
+ index = mid;
+ break;
+ }
+ }
+ return index;
+ }
+}
diff --git a/algorithms/src/test/java/algorithms/BinarySearchTest.java b/algorithms/src/test/java/algorithms/BinarySearchTest.java
new file mode 100644
index 0000000000..d53b074cc4
--- /dev/null
+++ b/algorithms/src/test/java/algorithms/BinarySearchTest.java
@@ -0,0 +1,14 @@
+import org.junit.Assert;
+import org.junit.Test;
+
+
+public class BinarySearchTest {
+
+ @Test
+ public void givenASortedArrayOfIntegers_whenBinarySearchRunForANumber_thenGetIndexOfTheNumber() {
+ BinarySearch binSearch = new BinarySearch();
+ int expectedIndexForSearchKey = 7;
+ Assert.assertEquals(expectedIndexForSearchKey, binSearch.runBinarySearch());
+ }
+
+}
diff --git a/apache-shiro/.gitignore b/apache-shiro/.gitignore
new file mode 100644
index 0000000000..020cda4898
--- /dev/null
+++ b/apache-shiro/.gitignore
@@ -0,0 +1,4 @@
+
+/.idea/
+/target/
+/apache-shiro.iml
\ No newline at end of file
diff --git a/apache-shiro/README.md b/apache-shiro/README.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apache-shiro/pom.xml b/apache-shiro/pom.xml
new file mode 100644
index 0000000000..97ed872a26
--- /dev/null
+++ b/apache-shiro/pom.xml
@@ -0,0 +1,65 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ apache-shiro
+ 1.0-SNAPSHOT
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+
+ 1.4.0
+ 1.2.17
+ 1.7.25
+
+
+
+
+ org.apache.shiro
+ shiro-core
+ ${apache-shiro-core-version}
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${slf4j-version}
+ runtime
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+ runtime
+
+
+ log4j
+ log4j
+ ${log4j-version}
+ runtime
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.6.2
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apache-shiro/src/main/java/com/baeldung/Main.java b/apache-shiro/src/main/java/com/baeldung/Main.java
new file mode 100644
index 0000000000..5e341f251b
--- /dev/null
+++ b/apache-shiro/src/main/java/com/baeldung/Main.java
@@ -0,0 +1,85 @@
+package com.baeldung;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.realm.Realm;
+import org.apache.shiro.realm.text.IniRealm;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.Subject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Main {
+
+ private static final transient Logger log = LoggerFactory.getLogger(Main.class);
+
+ public static void main(String[] args) {
+
+ Realm realm = new MyCustomRealm();
+ SecurityManager securityManager = new DefaultSecurityManager(realm);
+
+ SecurityUtils.setSecurityManager(securityManager);
+ Subject currentUser = SecurityUtils.getSubject();
+
+ if (!currentUser.isAuthenticated()) {
+ UsernamePasswordToken token
+ = new UsernamePasswordToken("user", "password");
+ token.setRememberMe(true);
+ try {
+ currentUser.login(token);
+ } catch (UnknownAccountException uae) {
+ log.error("Username Not Found!", uae);
+ } catch (IncorrectCredentialsException ice) {
+ log.error("Invalid Credentials!", ice);
+ } catch (LockedAccountException lae) {
+ log.error("Your Account is Locked!", lae);
+ } catch (AuthenticationException ae) {
+ log.error("Unexpected Error!", ae);
+ }
+ }
+
+ log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
+
+ if (currentUser.hasRole("admin")) {
+ log.info("Welcome Admin");
+ } else if(currentUser.hasRole("editor")) {
+ log.info("Welcome, Editor!");
+ } else if(currentUser.hasRole("author")) {
+ log.info("Welcome, Author");
+ } else {
+ log.info("Welcome, Guest");
+ }
+
+ if(currentUser.isPermitted("articles:compose")) {
+ log.info("You can compose an article");
+ } else {
+ log.info("You are not permitted to compose an article!");
+ }
+
+ if(currentUser.isPermitted("articles:save")) {
+ log.info("You can save articles");
+ } else {
+ log.info("You can not save articles");
+ }
+
+ if(currentUser.isPermitted("articles:publish")) {
+ log.info("You can publish articles");
+ } else {
+ log.info("You can not publish articles");
+ }
+
+ Session session = currentUser.getSession();
+ session.setAttribute("key", "value");
+ String value = (String) session.getAttribute("key");
+ if (value.equals("value")) {
+ log.info("Retrieved the correct value! [" + value + "]");
+ }
+
+ currentUser.logout();
+
+ System.exit(0);
+ }
+
+}
diff --git a/apache-shiro/src/main/java/com/baeldung/MyCustomRealm.java b/apache-shiro/src/main/java/com/baeldung/MyCustomRealm.java
new file mode 100644
index 0000000000..8d792c76a5
--- /dev/null
+++ b/apache-shiro/src/main/java/com/baeldung/MyCustomRealm.java
@@ -0,0 +1,102 @@
+package com.baeldung;
+
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.jdbc.JdbcRealm;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.*;
+
+public class MyCustomRealm extends JdbcRealm {
+
+ private Map credentials = new HashMap<>();
+ private Map> roles = new HashMap<>();
+ private Map> perm = new HashMap<>();
+
+ {
+ credentials.put("user", "password");
+ credentials.put("user2", "password2");
+ credentials.put("user3", "password3");
+
+ roles.put("user", new HashSet<>(Arrays.asList("admin")));
+ roles.put("user2", new HashSet<>(Arrays.asList("editor")));
+ roles.put("user3", new HashSet<>(Arrays.asList("author")));
+
+ perm.put("admin", new HashSet<>(Arrays.asList("*")));
+ perm.put("editor", new HashSet<>(Arrays.asList("articles:*")));
+ perm.put("author",
+ new HashSet<>(Arrays.asList("articles:compose",
+ "articles:save")));
+
+ }
+
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
+ throws AuthenticationException {
+
+ UsernamePasswordToken uToken = (UsernamePasswordToken) token;
+
+ if(uToken.getUsername() == null
+ || uToken.getUsername().isEmpty()
+ || !credentials.containsKey(uToken.getUsername())
+ ) {
+ throw new UnknownAccountException("username not found!");
+ }
+
+
+ return new SimpleAuthenticationInfo(
+ uToken.getUsername(), credentials.get(uToken.getUsername()),
+ getName());
+ }
+
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+ Set roleNames = new HashSet<>();
+ Set permissions = new HashSet<>();
+
+ principals.forEach(p -> {
+ try {
+ Set roles = getRoleNamesForUser(null, (String) p);
+ roleNames.addAll(roles);
+ permissions.addAll(getPermissions(null, null,roles));
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ });
+
+ SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
+ info.setStringPermissions(permissions);
+ return info;
+ }
+
+ @Override
+ protected Set getRoleNamesForUser(Connection conn, String username) throws SQLException {
+ if(!roles.containsKey(username)) {
+ throw new SQLException("username not found!");
+ }
+
+ return roles.get(username);
+ }
+
+ @Override
+ protected Set getPermissions(Connection conn, String username, Collection roleNames) throws SQLException {
+ for (String role : roleNames) {
+ if (!perm.containsKey(role)) {
+ throw new SQLException("role not found!");
+ }
+ }
+
+ Set finalSet = new HashSet<>();
+ for (String role : roleNames) {
+ finalSet.addAll(perm.get(role));
+ }
+
+ return finalSet;
+ }
+
+}
diff --git a/apache-shiro/src/main/resources/log4j.properties b/apache-shiro/src/main/resources/log4j.properties
new file mode 100644
index 0000000000..897bf08221
--- /dev/null
+++ b/apache-shiro/src/main/resources/log4j.properties
@@ -0,0 +1,12 @@
+log4j.rootLogger=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
+
+log4j.logger.org.apache=WARN
+
+log4j.logger.org.apache.shiro=INFO
+
+log4j.logger.org.apache.shiro.util.ThreadContext=WARN
+log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
\ No newline at end of file
diff --git a/apache-shiro/src/main/resources/shiro.ini b/apache-shiro/src/main/resources/shiro.ini
new file mode 100644
index 0000000000..0bb7567d1e
--- /dev/null
+++ b/apache-shiro/src/main/resources/shiro.ini
@@ -0,0 +1,9 @@
+[users]
+user = password,admin
+user2 = password2,editor
+user3 = password3,author
+
+[roles]
+admin = *
+editor = articles:*
+author = articles:compose,articles:save
\ No newline at end of file
diff --git a/asciidoctor/README.md b/asciidoctor/README.md
index 164200d227..3c602b6abd 100644
--- a/asciidoctor/README.md
+++ b/asciidoctor/README.md
@@ -1,3 +1,4 @@
### Relevant articles
-- [Introduction to Asciidoctor](http://www.baeldung.com/introduction-to-asciidoctor)
\ No newline at end of file
+- [Introduction to Asciidoctor](http://www.baeldung.com/introduction-to-asciidoctor)
+- [Generating a Book with Asciidoctor](http://www.baeldung.com/asciidoctor-book)
diff --git a/core-java-9/src/test/java/com/baeldung/java9/language/Java9ObjectsAPIUnitTest.java b/core-java-9/src/test/java/com/baeldung/java9/language/Java9ObjectsAPIUnitTest.java
index 93abe4e185..93579019a1 100644
--- a/core-java-9/src/test/java/com/baeldung/java9/language/Java9ObjectsAPIUnitTest.java
+++ b/core-java-9/src/test/java/com/baeldung/java9/language/Java9ObjectsAPIUnitTest.java
@@ -10,17 +10,27 @@ import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
public class Java9ObjectsAPIUnitTest {
-
+
+ private List aMethodReturningNullList(){
+ return null;
+ }
+
@Test
public void givenNullObject_whenRequireNonNullElse_thenElse(){
- assertThat(Objects.requireNonNullElse(null, Collections.EMPTY_LIST),
- is(Collections.EMPTY_LIST));
+ List aList = Objects.requireNonNullElse(
+ aMethodReturningNullList(), Collections.EMPTY_LIST);
+ assertThat(aList, is(Collections.EMPTY_LIST));
+ }
+
+ private List aMethodReturningNonNullList(){
+ return List.of("item1", "item2");
}
@Test
public void givenObject_whenRequireNonNullElse_thenObject(){
- assertThat(Objects.requireNonNullElse(List.of("item1", "item2"),
- Collections.EMPTY_LIST), is(List.of("item1", "item2")));
+ List aList = Objects.requireNonNullElse(
+ aMethodReturningNonNullList(), Collections.EMPTY_LIST);
+ assertThat(aList, is(List.of("item1", "item2")));
}
@Test(expected = NullPointerException.class)
@@ -30,8 +40,8 @@ public class Java9ObjectsAPIUnitTest {
@Test
public void givenObject_whenRequireNonNullElseGet_thenObject(){
- assertThat(Objects.requireNonNullElseGet(null, List::of),
- is(List.of()));
+ List aList = Objects.requireNonNullElseGet(null, List::of);
+ assertThat(aList, is(List.of()));
}
@Test
diff --git a/core-java/src/main/java/com/baeldung/concurrent/volatilekeyword/SharedObject.java b/core-java/src/main/java/com/baeldung/concurrent/volatilekeyword/SharedObject.java
new file mode 100644
index 0000000000..063c835481
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/concurrent/volatilekeyword/SharedObject.java
@@ -0,0 +1,13 @@
+package com.baeldung.concurrent.volatilekeyword;
+
+
+public class SharedObject {
+ private volatile int count=0;
+
+ void increamentCount(){
+ count++;
+ }
+ public int getCount(){
+ return count;
+ }
+}
diff --git a/core-java/src/main/java/com/baeldung/java/networking/README.md b/core-java/src/main/java/com/baeldung/networking/README.md
similarity index 100%
rename from core-java/src/main/java/com/baeldung/java/networking/README.md
rename to core-java/src/main/java/com/baeldung/networking/README.md
diff --git a/core-java/src/main/java/com/baeldung/java/networking/cookies/PersistentCookieStore.java b/core-java/src/main/java/com/baeldung/networking/cookies/PersistentCookieStore.java
similarity index 96%
rename from core-java/src/main/java/com/baeldung/java/networking/cookies/PersistentCookieStore.java
rename to core-java/src/main/java/com/baeldung/networking/cookies/PersistentCookieStore.java
index 0d66406ac2..5d30491cfe 100644
--- a/core-java/src/main/java/com/baeldung/java/networking/cookies/PersistentCookieStore.java
+++ b/core-java/src/main/java/com/baeldung/networking/cookies/PersistentCookieStore.java
@@ -1,4 +1,4 @@
-package com.baeldung.java.networking.cookies;
+package com.baeldung.networking.cookies;
import java.net.*;
import java.util.List;
diff --git a/core-java/src/main/java/com/baeldung/java/networking/cookies/ProxyAcceptCookiePolicy.java b/core-java/src/main/java/com/baeldung/networking/cookies/ProxyAcceptCookiePolicy.java
similarity index 93%
rename from core-java/src/main/java/com/baeldung/java/networking/cookies/ProxyAcceptCookiePolicy.java
rename to core-java/src/main/java/com/baeldung/networking/cookies/ProxyAcceptCookiePolicy.java
index 6d6371bfe0..0b5f6d7714 100644
--- a/core-java/src/main/java/com/baeldung/java/networking/cookies/ProxyAcceptCookiePolicy.java
+++ b/core-java/src/main/java/com/baeldung/networking/cookies/ProxyAcceptCookiePolicy.java
@@ -1,4 +1,4 @@
-package com.baeldung.java.networking.cookies;
+package com.baeldung.networking.cookies;
import java.net.*;
diff --git a/core-java/src/main/java/com/baeldung/java/networking/udp/EchoClient.java b/core-java/src/main/java/com/baeldung/networking/udp/EchoClient.java
similarity index 96%
rename from core-java/src/main/java/com/baeldung/java/networking/udp/EchoClient.java
rename to core-java/src/main/java/com/baeldung/networking/udp/EchoClient.java
index 916442533b..35a083de26 100644
--- a/core-java/src/main/java/com/baeldung/java/networking/udp/EchoClient.java
+++ b/core-java/src/main/java/com/baeldung/networking/udp/EchoClient.java
@@ -1,4 +1,4 @@
-package com.baeldung.java.networking.udp;
+package com.baeldung.networking.udp;
import java.io.IOException;
import java.net.DatagramPacket;
diff --git a/core-java/src/main/java/com/baeldung/java/networking/udp/EchoServer.java b/core-java/src/main/java/com/baeldung/networking/udp/EchoServer.java
similarity index 96%
rename from core-java/src/main/java/com/baeldung/java/networking/udp/EchoServer.java
rename to core-java/src/main/java/com/baeldung/networking/udp/EchoServer.java
index 900d330786..34f2971cc4 100644
--- a/core-java/src/main/java/com/baeldung/java/networking/udp/EchoServer.java
+++ b/core-java/src/main/java/com/baeldung/networking/udp/EchoServer.java
@@ -1,4 +1,4 @@
-package com.baeldung.java.networking.udp;
+package com.baeldung.networking.udp;
import java.io.IOException;
import java.net.DatagramPacket;
diff --git a/core-java/src/main/java/com/baeldung/networking/udp/broadcast/BroadcastingClient.java b/core-java/src/main/java/com/baeldung/networking/udp/broadcast/BroadcastingClient.java
new file mode 100644
index 0000000000..09794c2596
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/networking/udp/broadcast/BroadcastingClient.java
@@ -0,0 +1,85 @@
+package com.baeldung.networking.udp.broadcast;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class BroadcastingClient {
+ private DatagramSocket socket;
+ private InetAddress address;
+ private int expectedServerCount;
+ private byte[] buf;
+
+ public BroadcastingClient(int expectedServerCount) throws Exception {
+ this.expectedServerCount = expectedServerCount;
+ this.address = InetAddress.getByName("255.255.255.255");
+ }
+
+ public int discoverServers(String msg) throws IOException {
+ initializeSocketForBroadcasting();
+ copyMessageOnBuffer(msg);
+
+ // When we want to broadcast not just to local network, call listAllBroadcastAddresses() and execute broadcastPacket for each value.
+ broadcastPacket(address);
+
+ return receivePackets();
+ }
+
+ List listAllBroadcastAddresses() throws SocketException {
+ List broadcastList = new ArrayList<>();
+ Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
+ while (interfaces.hasMoreElements()) {
+ NetworkInterface networkInterface = interfaces.nextElement();
+
+ if (networkInterface.isLoopback() || !networkInterface.isUp()) {
+ continue;
+ }
+
+ broadcastList.addAll(networkInterface.getInterfaceAddresses()
+ .stream()
+ .filter(address -> address.getBroadcast() != null)
+ .map(address -> address.getBroadcast())
+ .collect(Collectors.toList()));
+ }
+ return broadcastList;
+ }
+
+ private void initializeSocketForBroadcasting() throws SocketException {
+ socket = new DatagramSocket();
+ socket.setBroadcast(true);
+ }
+
+ private void copyMessageOnBuffer(String msg) {
+ buf = msg.getBytes();
+ }
+
+ private void broadcastPacket(InetAddress address) throws IOException {
+ DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4445);
+ socket.send(packet);
+ }
+
+ private int receivePackets() throws IOException {
+ int serversDiscovered = 0;
+ while (serversDiscovered != expectedServerCount) {
+ receivePacket();
+ serversDiscovered++;
+ }
+ return serversDiscovered;
+ }
+
+ private void receivePacket() throws IOException {
+ DatagramPacket packet = new DatagramPacket(buf, buf.length);
+ socket.receive(packet);
+ }
+
+ public void close() {
+ socket.close();
+ }
+}
diff --git a/core-java/src/main/java/com/baeldung/networking/udp/broadcast/BroadcastingEchoServer.java b/core-java/src/main/java/com/baeldung/networking/udp/broadcast/BroadcastingEchoServer.java
new file mode 100644
index 0000000000..b519f899bb
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/networking/udp/broadcast/BroadcastingEchoServer.java
@@ -0,0 +1,44 @@
+package com.baeldung.networking.udp.broadcast;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+public class BroadcastingEchoServer extends Thread {
+
+ protected DatagramSocket socket = null;
+ protected boolean running;
+ protected byte[] buf = new byte[256];
+
+ public BroadcastingEchoServer() throws IOException {
+ socket = new DatagramSocket(null);
+ socket.setReuseAddress(true);
+ socket.bind(new InetSocketAddress(4445));
+ }
+
+ public void run() {
+ running = true;
+
+ while (running) {
+ try {
+ DatagramPacket packet = new DatagramPacket(buf, buf.length);
+ socket.receive(packet);
+ InetAddress address = packet.getAddress();
+ int port = packet.getPort();
+ packet = new DatagramPacket(buf, buf.length, address, port);
+ String received = new String(packet.getData(), 0, packet.getLength());
+ if (received.equals("end")) {
+ running = false;
+ continue;
+ }
+ socket.send(packet);
+ } catch (IOException e) {
+ e.printStackTrace();
+ running = false;
+ }
+ }
+ socket.close();
+ }
+}
diff --git a/core-java/src/main/java/com/baeldung/networking/udp/multicast/MulticastEchoServer.java b/core-java/src/main/java/com/baeldung/networking/udp/multicast/MulticastEchoServer.java
new file mode 100644
index 0000000000..9d63dd6386
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/networking/udp/multicast/MulticastEchoServer.java
@@ -0,0 +1,41 @@
+package com.baeldung.networking.udp.multicast;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+
+public class MulticastEchoServer extends Thread {
+
+ protected MulticastSocket socket = null;
+ protected byte[] buf = new byte[256];
+ protected InetAddress group = null;
+
+ public MulticastEchoServer() throws IOException {
+ socket = new MulticastSocket(4446);
+ socket.setReuseAddress(true);
+ group = InetAddress.getByName("230.0.0.0");
+ socket.joinGroup(group);
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ DatagramPacket packet = new DatagramPacket(buf, buf.length);
+ socket.receive(packet);
+ InetAddress address = packet.getAddress();
+ int port = packet.getPort();
+ packet = new DatagramPacket(buf, buf.length, address, port);
+ String received = new String(packet.getData(), 0, packet.getLength());
+ if (received.equals("end")) {
+ break;
+ }
+ socket.send(packet);
+ }
+ socket.leaveGroup(group);
+ socket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/core-java/src/main/java/com/baeldung/networking/udp/multicast/MulticastingClient.java b/core-java/src/main/java/com/baeldung/networking/udp/multicast/MulticastingClient.java
new file mode 100644
index 0000000000..e89abc939d
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/networking/udp/multicast/MulticastingClient.java
@@ -0,0 +1,53 @@
+package com.baeldung.networking.udp.multicast;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+
+public class MulticastingClient {
+ private DatagramSocket socket;
+ private InetAddress group;
+ private int expectedServerCount;
+ private byte[] buf;
+
+ public MulticastingClient(int expectedServerCount) throws Exception {
+ this.expectedServerCount = expectedServerCount;
+ this.socket = new DatagramSocket();
+ this.group = InetAddress.getByName("230.0.0.0");
+ }
+
+ public int discoverServers(String msg) throws IOException {
+ copyMessageOnBuffer(msg);
+ multicastPacket();
+
+ return receivePackets();
+ }
+
+ private void copyMessageOnBuffer(String msg) {
+ buf = msg.getBytes();
+ }
+
+ private void multicastPacket() throws IOException {
+ DatagramPacket packet = new DatagramPacket(buf, buf.length, group, 4446);
+ socket.send(packet);
+ }
+
+ private int receivePackets() throws IOException {
+ int serversDiscovered = 0;
+ while (serversDiscovered != expectedServerCount) {
+ receivePacket();
+ serversDiscovered++;
+ }
+ return serversDiscovered;
+ }
+
+ private void receivePacket() throws IOException {
+ DatagramPacket packet = new DatagramPacket(buf, buf.length);
+ socket.receive(packet);
+ }
+
+ public void close() {
+ socket.close();
+ }
+}
diff --git a/core-java/src/test/java/com/baeldung/concurrent/volatilekeyword/SharedObjectManualTest.java b/core-java/src/test/java/com/baeldung/concurrent/volatilekeyword/SharedObjectManualTest.java
new file mode 100644
index 0000000000..8770cb4e90
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/concurrent/volatilekeyword/SharedObjectManualTest.java
@@ -0,0 +1,71 @@
+package com.baeldung.concurrent.volatilekeyword;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+
+public class SharedObjectManualTest {
+
+ private SharedObject sharedObject;
+ private int valueReadByThread2;
+ private int valueReadByThread3;
+
+ @Before
+ public void setUp() {
+ sharedObject = new SharedObject();
+ }
+
+ @Test
+ public void whenOneThreadWrites_thenVolatileReadsFromMainMemory() throws InterruptedException {
+ Thread writer = new Thread(() -> sharedObject.increamentCount());
+ writer.start();
+
+
+ Thread readerOne = new Thread(() -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ valueReadByThread2 = sharedObject.getCount();
+ });
+ readerOne.start();
+
+ Thread readerTwo = new Thread(() -> {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ valueReadByThread3 = sharedObject.getCount();
+ });
+ readerTwo.start();
+
+ assertEquals(1, valueReadByThread2);
+ assertEquals(1, valueReadByThread3);
+
+ }
+
+ @Test
+ public void whenTwoThreadWrites_thenVolatileReadsFromMainMemory() throws InterruptedException {
+ Thread writerOne = new Thread(() -> sharedObject.increamentCount());
+ writerOne.start();
+ Thread.sleep(100);
+
+ Thread writerTwo = new Thread(() -> sharedObject.increamentCount());
+ writerTwo.start();
+ Thread.sleep(100);
+
+ Thread readerOne = new Thread(() -> valueReadByThread2 = sharedObject.getCount());
+ readerOne.start();
+
+ Thread readerTwo = new Thread(() -> valueReadByThread3 = sharedObject.getCount());
+ readerTwo.start();
+
+ assertEquals(2, valueReadByThread2);
+ assertEquals(2, valueReadByThread3);
+
+ }
+}
diff --git a/core-java/src/test/java/com/baeldung/javanetworking/uriurl/URIvsURLUnitTest.java b/core-java/src/test/java/com/baeldung/javanetworking/uriurl/URIvsURLUnitTest.java
new file mode 100644
index 0000000000..ed36951f73
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/javanetworking/uriurl/URIvsURLUnitTest.java
@@ -0,0 +1,78 @@
+package com.baeldung.javanetworking.uriurl;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import org.apache.commons.io.IOUtils;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+public class URIvsURLUnitTest {
+
+ @Test
+ public void whenCreatingURIs_thenSameInfo() throws URISyntaxException {
+ URI firstURI = new URI("somescheme://theuser:thepassword@someauthority:80/some/path?thequery#somefragment");
+ URI secondURI = new URI("somescheme", "theuser:thepassword", "someuthority", 80, "/some/path", "thequery", "somefragment");
+
+ assertEquals(firstURI.getScheme(), secondURI.getScheme());
+ assertEquals(firstURI.getPath(), secondURI.getPath());
+ }
+
+ @Test
+ public void whenCreatingURLs_thenSameInfo() throws MalformedURLException {
+ URL firstURL = new URL("http://theuser:thepassword@somehost:80/path/to/file?thequery#somefragment");
+ URL secondURL = new URL("http", "somehost", 80, "/path/to/file");
+
+ assertEquals(firstURL.getHost(), secondURL.getHost());
+ assertEquals(firstURL.getPath(), secondURL.getPath());
+ }
+
+ @Test
+ public void whenCreatingURI_thenCorrect() {
+ URI uri = URI.create("urn:isbn:1234567890");
+
+ assertNotNull(uri);
+ }
+
+ @Test(expected = MalformedURLException.class)
+ public void whenCreatingURLs_thenException() throws MalformedURLException {
+ URL theURL = new URL("otherprotocol://somehost/path/to/file");
+
+ assertNotNull(theURL);
+ }
+
+ @Test
+ public void givenObjects_whenConverting_thenCorrect() throws MalformedURLException, URISyntaxException {
+ String aURIString = "http://somehost:80/path?thequery";
+ URI uri = new URI(aURIString);
+ URL url = new URL(aURIString);
+
+ URL toURL = uri.toURL();
+ URI toURI = url.toURI();
+
+ assertNotNull(url);
+ assertNotNull(uri);
+ assertEquals(toURL.toString(), toURI.toString());
+ }
+
+ @Test(expected = MalformedURLException.class)
+ public void givenURI_whenConvertingToURL_thenException() throws MalformedURLException, URISyntaxException {
+ URI uri = new URI("somescheme://someauthority/path?thequery");
+
+ URL url = uri.toURL();
+
+ assertNotNull(url);
+ }
+
+ @Test
+ public void givenURL_whenGettingContents_thenCorrect() throws MalformedURLException, IOException {
+ URL url = new URL("http://courses.baeldung.com");
+
+ String contents = IOUtils.toString(url.openStream());
+
+ assertTrue(contents.contains(""));
+ }
+
+}
diff --git a/core-java/src/test/java/com/baeldung/java/networking/udp/UDPIntegrationTest.java b/core-java/src/test/java/com/baeldung/networking/udp/UDPIntegrationTest.java
similarity index 95%
rename from core-java/src/test/java/com/baeldung/java/networking/udp/UDPIntegrationTest.java
rename to core-java/src/test/java/com/baeldung/networking/udp/UDPIntegrationTest.java
index aff851ae4b..968c01d24e 100644
--- a/core-java/src/test/java/com/baeldung/java/networking/udp/UDPIntegrationTest.java
+++ b/core-java/src/test/java/com/baeldung/networking/udp/UDPIntegrationTest.java
@@ -1,4 +1,4 @@
-package com.baeldung.java.networking.udp;
+package com.baeldung.networking.udp;
import org.junit.After;
import org.junit.Before;
diff --git a/core-java/src/test/java/com/baeldung/networking/udp/broadcast/BroadcastIntegrationTest.java b/core-java/src/test/java/com/baeldung/networking/udp/broadcast/BroadcastIntegrationTest.java
new file mode 100644
index 0000000000..c4f1e1f42c
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/networking/udp/broadcast/BroadcastIntegrationTest.java
@@ -0,0 +1,39 @@
+package com.baeldung.networking.udp.broadcast;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+
+public class BroadcastIntegrationTest {
+ private BroadcastingClient client;
+
+ @Test
+ public void whenBroadcasting_thenDiscoverExpectedServers() throws Exception {
+ int expectedServers = 4;
+ initializeForExpectedServers(expectedServers);
+
+ int serversDiscovered = client.discoverServers("hello server");
+ assertEquals(expectedServers, serversDiscovered);
+ }
+
+ private void initializeForExpectedServers(int expectedServers) throws Exception {
+ for (int i = 0; i < expectedServers; i++) {
+ new BroadcastingEchoServer().start();
+ }
+
+ client = new BroadcastingClient(expectedServers);
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ stopEchoServer();
+ client.close();
+ }
+
+ private void stopEchoServer() throws IOException {
+ client.discoverServers("end");
+ }
+}
diff --git a/core-java/src/test/java/com/baeldung/networking/udp/multicast/MulticastIntegrationTest.java b/core-java/src/test/java/com/baeldung/networking/udp/multicast/MulticastIntegrationTest.java
new file mode 100644
index 0000000000..404f6c4e85
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/networking/udp/multicast/MulticastIntegrationTest.java
@@ -0,0 +1,39 @@
+package com.baeldung.networking.udp.multicast;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+
+public class MulticastIntegrationTest {
+ private MulticastingClient client;
+
+ @Test
+ public void whenBroadcasting_thenDiscoverExpectedServers() throws Exception {
+ int expectedServers = 4;
+ initializeForExpectedServers(expectedServers);
+
+ int serversDiscovered = client.discoverServers("hello server");
+ assertEquals(expectedServers, serversDiscovered);
+ }
+
+ private void initializeForExpectedServers(int expectedServers) throws Exception {
+ for (int i = 0; i < expectedServers; i++) {
+ new MulticastEchoServer().start();
+ }
+
+ client = new MulticastingClient(expectedServers);
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ stopEchoServer();
+ client.close();
+ }
+
+ private void stopEchoServer() throws IOException {
+ client.discoverServers("end");
+ }
+}
diff --git a/easy-rules/pom.xml b/easy-rules/pom.xml
new file mode 100644
index 0000000000..b74b16f34c
--- /dev/null
+++ b/easy-rules/pom.xml
@@ -0,0 +1,15 @@
+
+ 4.0.0
+ com.baeldung.easyrules
+ easy-rules
+ 1.0.0-SNAPSHOT
+
+
+
+ org.jeasy
+ easy-rules-core
+ 3.0.0
+
+
+
\ No newline at end of file
diff --git a/easy-rules/src/main/java/com/baeldung/easyrules/HelloWorldRule.java b/easy-rules/src/main/java/com/baeldung/easyrules/HelloWorldRule.java
new file mode 100644
index 0000000000..5448eabf2a
--- /dev/null
+++ b/easy-rules/src/main/java/com/baeldung/easyrules/HelloWorldRule.java
@@ -0,0 +1,20 @@
+package com.baeldung.easyrules;
+
+import org.jeasy.rules.annotation.Action;
+import org.jeasy.rules.annotation.Condition;
+import org.jeasy.rules.annotation.Rule;
+
+@Rule(name = "Hello World rule", description = "Always say hello world")
+public class HelloWorldRule {
+
+ @Condition
+ public boolean when() {
+ return true;
+ }
+
+ @Action
+ public void then() throws Exception {
+ System.out.println("hello world");
+ }
+
+}
diff --git a/easy-rules/src/main/java/com/baeldung/easyrules/Launcher.java b/easy-rules/src/main/java/com/baeldung/easyrules/Launcher.java
new file mode 100644
index 0000000000..427e3eace0
--- /dev/null
+++ b/easy-rules/src/main/java/com/baeldung/easyrules/Launcher.java
@@ -0,0 +1,21 @@
+package com.baeldung.easyrules;
+
+import org.jeasy.rules.api.Facts;
+import org.jeasy.rules.api.Rules;
+import org.jeasy.rules.api.RulesEngine;
+import org.jeasy.rules.core.DefaultRulesEngine;
+
+public class Launcher {
+ public static void main(String... args) {
+ // create facts
+ Facts facts = new Facts();
+
+ // create rules
+ Rules rules = new Rules();
+ rules.register(new HelloWorldRule());
+
+ // create a rules engine and fire rules on known facts
+ RulesEngine rulesEngine = new DefaultRulesEngine();
+ rulesEngine.fire(rules, facts);
+ }
+}
diff --git a/ejb/ejb-client/src/main/resources/jboss-ejb-client.properties b/ejb/ejb-client/src/main/resources/jboss-ejb-client.properties
index a01a675e44..67533b7825 100755
--- a/ejb/ejb-client/src/main/resources/jboss-ejb-client.properties
+++ b/ejb/ejb-client/src/main/resources/jboss-ejb-client.properties
@@ -1,8 +1,8 @@
+endpoint.name=client-endpoint
+remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=127.0.0.1
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
-remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false
-remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS=${host.auth:JBOSS-LOCAL-USER}
-remote.connection.default.username=testUser
-remote.connection.default.password=admin1234!
+remote.connection.default.username=myusername
+remote.connection.default.password=mypassword
\ No newline at end of file
diff --git a/ejb/ejbclient/src/main/java/com/baeldung/ejbclient/application/TextApplication.java b/ejb/ejbclient/src/main/java/com/baeldung/ejbclient/application/TextApplication.java
new file mode 100644
index 0000000000..b65c21100d
--- /dev/null
+++ b/ejb/ejbclient/src/main/java/com/baeldung/ejbclient/application/TextApplication.java
@@ -0,0 +1,42 @@
+package com.baeldung.ejbclient.application;
+
+import com.baeldung.ejbmodule.TextProcessorBean;
+import com.baeldung.ejbmodule.TextProcessorRemote;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.util.Properties;
+
+public class TextApplication {
+
+ public static void main(String[] args) throws NamingException {
+ TextProcessorRemote textProcessor = EJBFactory.createTextProcessorBeanFromJNDI("ejb:");
+ System.out.print(textProcessor.processText("sample text"));
+ }
+
+ private static class EJBFactory {
+
+ private static TextProcessorRemote createTextProcessorBeanFromJNDI(String namespace) throws NamingException {
+ return lookupTextProcessorBean(namespace);
+ }
+
+ private static TextProcessorRemote lookupTextProcessorBean(String namespace) throws NamingException {
+ Context ctx = createInitialContext();
+ final String appName = "";
+ final String moduleName = "EJBModule";
+ final String distinctName = "";
+ final String beanName = TextProcessorBean.class.getSimpleName();
+ final String viewClassName = TextProcessorRemote.class.getName();
+ return (TextProcessorRemote) ctx.lookup(namespace + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);
+ }
+
+ private static Context createInitialContext() throws NamingException {
+ Properties jndiProperties = new Properties();
+ jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
+ jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
+ jndiProperties.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
+ jndiProperties.put("jboss.naming.client.ejb.context", true);
+ return new InitialContext(jndiProperties);
+ }
+ }
+}
diff --git a/ejb/ejbclient/src/main/resources/jboss-ejb-client.properties b/ejb/ejbclient/src/main/resources/jboss-ejb-client.properties
new file mode 100644
index 0000000000..67533b7825
--- /dev/null
+++ b/ejb/ejbclient/src/main/resources/jboss-ejb-client.properties
@@ -0,0 +1,8 @@
+endpoint.name=client-endpoint
+remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
+remote.connections=default
+remote.connection.default.host=127.0.0.1
+remote.connection.default.port=8080
+remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
+remote.connection.default.username=myusername
+remote.connection.default.password=mypassword
\ No newline at end of file
diff --git a/ejb/ejbclient/src/test/java/com/baeldung/ejbclient/application/TextApplicationTest.java b/ejb/ejbclient/src/test/java/com/baeldung/ejbclient/application/TextApplicationTest.java
new file mode 100644
index 0000000000..947c72d0b0
--- /dev/null
+++ b/ejb/ejbclient/src/test/java/com/baeldung/ejbclient/application/TextApplicationTest.java
@@ -0,0 +1,31 @@
+package com.baeldung.ejbclient.application;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import javax.naming.NamingException;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import static org.junit.Assert.*;
+
+public class TextApplicationTest {
+
+ private static ByteArrayOutputStream outContent;
+
+ @BeforeClass
+ public static void setUpPrintStreamInstance() {
+ outContent = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(outContent));
+ }
+
+ @AfterClass
+ public static void tearDownByteArrayOutputStream() {
+ outContent = null;
+ }
+
+ @Test
+ public void givenInputString_whenCompareTtoStringPrintedToConsole_thenSuccessful() throws NamingException {
+ TextApplication.main(new String[]{});
+ assertEquals("SAMPLE TEXT", outContent.toString());
+ }
+}
\ No newline at end of file
diff --git a/ejb/ejbmodule/src/main/java/com/baeldung/ejbmodule/TextProcessorBean.java b/ejb/ejbmodule/src/main/java/com/baeldung/ejbmodule/TextProcessorBean.java
new file mode 100644
index 0000000000..dc0db5fc53
--- /dev/null
+++ b/ejb/ejbmodule/src/main/java/com/baeldung/ejbmodule/TextProcessorBean.java
@@ -0,0 +1,10 @@
+package com.baeldung.ejbmodule;
+
+import javax.ejb.Stateless;
+
+@Stateless
+public class TextProcessorBean implements TextProcessorRemote {
+ public String processText(String text) {
+ return text.toUpperCase();
+ }
+}
diff --git a/ejb/ejbmodule/src/main/java/com/baeldung/ejbmodule/TextProcessorRemote.java b/ejb/ejbmodule/src/main/java/com/baeldung/ejbmodule/TextProcessorRemote.java
new file mode 100644
index 0000000000..680d8f4e10
--- /dev/null
+++ b/ejb/ejbmodule/src/main/java/com/baeldung/ejbmodule/TextProcessorRemote.java
@@ -0,0 +1,9 @@
+package com.baeldung.ejbmodule;
+
+import javax.ejb.Remote;
+
+@Remote
+public interface TextProcessorRemote {
+
+ String processText(String text);
+}
\ No newline at end of file
diff --git a/ejb/ejbmodule/src/test/java/com/baeldung/ejbmodule/TextProcessorBeanTest.java b/ejb/ejbmodule/src/test/java/com/baeldung/ejbmodule/TextProcessorBeanTest.java
new file mode 100644
index 0000000000..d8693420d4
--- /dev/null
+++ b/ejb/ejbmodule/src/test/java/com/baeldung/ejbmodule/TextProcessorBeanTest.java
@@ -0,0 +1,12 @@
+package com.baeldung.ejbmodule;
+
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+public class TextProcessorBeanTest {
+ @Test
+ public void givenInputString_whenComparedToStringParsedByBean_thenSuccessful() {
+ TextProcessorBean textProcessor = new TextProcessorBean();
+ assertEquals("TEST", textProcessor.processText("test"));
+ }
+}
\ No newline at end of file
diff --git a/jackson/src/test/java/com/baeldung/jackson/test/JacksonDeserializationUnitTest.java b/jackson/src/test/java/com/baeldung/jackson/test/JacksonDeserializationUnitTest.java
index 45d957b90b..035ff8ca9c 100644
--- a/jackson/src/test/java/com/baeldung/jackson/test/JacksonDeserializationUnitTest.java
+++ b/jackson/src/test/java/com/baeldung/jackson/test/JacksonDeserializationUnitTest.java
@@ -1,19 +1,23 @@
package com.baeldung.jackson.test;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import java.io.IOException;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import org.junit.Test;
import com.baeldung.jackson.deserialization.ItemDeserializer;
import com.baeldung.jackson.dtos.Item;
import com.baeldung.jackson.dtos.ItemWithSerializer;
import com.baeldung.jackson.dtos.MyDto;
import com.baeldung.jackson.dtos.ignore.MyDtoIgnoreUnknown;
-import org.junit.Test;
-
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
@@ -21,6 +25,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import com.fasterxml.jackson.databind.module.SimpleModule;
@@ -165,4 +170,35 @@ public class JacksonDeserializationUnitTest {
assertThat(readValue, notNullValue());
}
+ @Test
+ public void whenDeserialisingZonedDateTimeWithDefaults_thenTimeZoneIsNotPreserved() throws IOException {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.findAndRegisterModules();
+ objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ // construct a new instance of ZonedDateTime
+ ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Europe/Berlin"));
+ String converted = objectMapper.writeValueAsString(now);
+ // restore an instance of ZonedDateTime from String
+ ZonedDateTime restored = objectMapper.readValue(converted, ZonedDateTime.class);
+ System.out.println("serialized: " + now);
+ System.out.println("restored: " + restored);
+ assertThat(now, is(not(restored)));
+ }
+
+ @Test
+ public void whenDeserialisingZonedDateTimeWithFeaturesDisabled_thenTimeZoneIsPreserved() throws IOException {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.findAndRegisterModules();
+ objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
+ // construct a new instance of ZonedDateTime
+ ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Europe/Berlin"));
+ String converted = objectMapper.writeValueAsString(now);
+ // restore an instance of ZonedDateTime from String
+ ZonedDateTime restored = objectMapper.readValue(converted, ZonedDateTime.class);
+ System.out.println("serialized: " + now);
+ System.out.println("restored: " + restored);
+ assertThat(now, is(restored));
+ }
+
}
diff --git a/kotlin/README.md b/kotlin/README.md
index 6b3fb93dcc..91933e94dc 100644
--- a/kotlin/README.md
+++ b/kotlin/README.md
@@ -7,3 +7,10 @@
- [Difference Between “==” and “===” in Kotlin](http://www.baeldung.com/kotlin-equality-operators)
- [Generics in Kotlin](http://www.baeldung.com/kotlin-generics)
- [Introduction to Kotlin Coroutines](http://www.baeldung.com/kotlin-coroutines)
+- [Destructuring Declarations in Kotlin](http://www.baeldung.com/kotlin-destructuring-declarations)
+- [Kotlin with Mockito](http://www.baeldung.com/kotlin-mockito)
+- [Lazy Initialization in Kotlin](http://www.baeldung.com/kotlin-lazy-initialization)
+- [Overview of Kotlin Collections API](http://www.baeldung.com/kotlin-collections-api)
+- [Converting a List to Map in Kotlin](http://www.baeldung.com/kotlin-list-to-map)
+- [Data Classes in Kotlin](http://www.baeldung.com/kotlin-data-classes)
+
diff --git a/libraries/README.md b/libraries/README.md
index 88075af390..ed6d214c7a 100644
--- a/libraries/README.md
+++ b/libraries/README.md
@@ -23,6 +23,7 @@
- [Serenity BDD with Spring and JBehave](http://www.baeldung.com/serenity-spring-jbehave)
- [Locality-Sensitive Hashing in Java Using Java-LSH](http://www.baeldung.com/locality-sensitive-hashing)
- [Apache Commons Collections OrderedMap](http://www.baeldung.com/apache-commons-ordered-map)
+- [Introduction to Apache Commons Text](http://www.baeldung.com/java-apache-commons-text)
- [A Guide to Apache Commons DbUtils](http://www.baeldung.com/apache-commons-dbutils)
- [Introduction to Awaitility](http://www.baeldung.com/awaitlity-testing)
- [Guide to the HyperLogLog Algorithm](http://www.baeldung.com/java-hyperloglog)
diff --git a/libraries/pom.xml b/libraries/pom.xml
index 490302ca29..ddfd75da82 100644
--- a/libraries/pom.xml
+++ b/libraries/pom.xml
@@ -186,11 +186,11 @@
rome
${rome.version}
-
- io.specto
- hoverfly-java
- 0.8.0
-
+
+ io.specto
+ hoverfly-java
+ 0.8.0
+
org.apache.httpcomponents
httpclient
@@ -212,6 +212,11 @@
commons-chain
${commons-chain.version}
+
+ org.apache.commons
+ commons-csv
+ ${commons-csv.version}
+
commons-dbutils
commons-dbutils
@@ -380,7 +385,7 @@
one.util
streamex
- 0.6.5
+ ${streamex.version}
org.jooq
@@ -467,11 +472,16 @@
noexception
1.1.0
-
+
org.eclipse.collections
eclipse-collections
${eclipse-collections.version}
+
+ io.vavr
+ vavr
+ ${vavr.version}
+
0.7.0
@@ -480,6 +490,7 @@
1.1
1.9.3
1.2
+ 1.4
1.9.2
1.2
3.21.0-GA
@@ -513,6 +524,8 @@
1.7.1
2.1.2
1.0
- 8.2.0
+ 8.2.0
+ 0.6.5
+ 0.9.0
diff --git a/libraries/src/main/java/com/baeldung/distinct/DistinctWithJavaFunction.java b/libraries/src/main/java/com/baeldung/distinct/DistinctWithJavaFunction.java
new file mode 100644
index 0000000000..0d08c94b47
--- /dev/null
+++ b/libraries/src/main/java/com/baeldung/distinct/DistinctWithJavaFunction.java
@@ -0,0 +1,15 @@
+package com.baeldung.distinct;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public class DistinctWithJavaFunction {
+
+ public static Predicate distinctByKey(Function super T, ?> keyExtractor) {
+ Map
+
+
+ mysql
+ mysql-connector-java
+ ${mysql-connector-java.version}
+
com.h2database
@@ -167,7 +173,7 @@
- 4.3.5.RELEASE
+ 4.3.10.RELEASE
1.10.6.RELEASE
@@ -177,7 +183,8 @@
5.2.10.Final
- 8.5.15
+ 8.0.7-dmr
+ 9.0.0.M26
1.1
2.3.4
1.4.195
diff --git a/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/model/Employee.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/model/Employee.java
new file mode 100644
index 0000000000..f1ad30b090
--- /dev/null
+++ b/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/model/Employee.java
@@ -0,0 +1,86 @@
+package com.baeldung.hibernate.manytomany.model;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinTable;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "Employee")
+public class Employee implements Serializable {
+ @Id
+ @Column(name = "employee_id")
+ @GeneratedValue
+ private Long employeeId;
+
+ @Column(name = "first_name")
+ private String firstName;
+
+ @Column(name = "last_name")
+ private String lastName;
+
+ @ManyToMany(cascade = { CascadeType.ALL })
+ @JoinTable(
+ name = "Employee_Project",
+ joinColumns = { @JoinColumn(name = "employee_id") },
+ inverseJoinColumns = { @JoinColumn(name = "project_id") }
+ )
+ Set projects = new HashSet();
+
+
+ public Employee() {
+ super();
+ }
+
+ public Employee(String firstName, String lastName) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+
+ public Employee(String firstName, String lastName, Set projects) {
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.projects = projects;
+ }
+
+
+ public Long getEmployeeId() {
+ return employeeId;
+ }
+
+ public void setEmployeeId(Long employeeId) {
+ this.employeeId = employeeId;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public Set getProjects() {
+ return projects;
+ }
+
+ public void setProjects(Set projects) {
+ this.projects = projects;
+ }
+}
diff --git a/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/model/Project.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/model/Project.java
new file mode 100644
index 0000000000..d6c049f33e
--- /dev/null
+++ b/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/model/Project.java
@@ -0,0 +1,61 @@
+package com.baeldung.hibernate.manytomany.model;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "Project")
+public class Project implements Serializable {
+
+ @Id
+ @Column(name = "project_id")
+ @GeneratedValue
+ private Long projectId;
+
+ @Column(name = "title")
+ private String title;
+
+ @ManyToMany(mappedBy = "projects")
+ private Set employees = new HashSet();
+
+ public Project() {
+ super();
+ }
+
+ public Project(String title) {
+ this.title = title;
+ }
+
+ public Long getProjectId() {
+ return projectId;
+ }
+
+ public void setProjectId(Long projectId) {
+ this.projectId = projectId;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public Set getEmployees() {
+ return employees;
+ }
+
+ public void setEmployees(Set employees) {
+ this.employees = employees;
+ }
+
+
+}
diff --git a/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/util/HibernateUtil.java b/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/util/HibernateUtil.java
new file mode 100644
index 0000000000..5f489dd027
--- /dev/null
+++ b/spring-hibernate5/src/main/java/com/baeldung/hibernate/manytomany/util/HibernateUtil.java
@@ -0,0 +1,41 @@
+package com.baeldung.hibernate.manytomany.util;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.service.ServiceRegistry;
+import com.baeldung.hibernate.manytomany.model.Employee;
+import com.baeldung.hibernate.manytomany.model.Project;
+
+public class HibernateUtil {
+ private static SessionFactory sessionFactory;
+
+ private static SessionFactory buildSessionFactory() {
+ try {
+ // Create the SessionFactory from hibernate-annotation.cfg.xml
+ Configuration configuration = new Configuration();
+ configuration.addAnnotatedClass(Employee.class);
+ configuration.addAnnotatedClass(Project.class);
+ configuration.configure("manytomany.cfg.xml");
+ System.out.println("Hibernate Annotation Configuration loaded");
+
+ ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties())
+ .build();
+ System.out.println("Hibernate Annotation serviceRegistry created");
+
+ SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
+
+ return sessionFactory;
+ } catch (Throwable ex) {
+ System.err.println("Initial SessionFactory creation failed." + ex);
+ ex.printStackTrace();
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ public static SessionFactory getSessionFactory() {
+ if (sessionFactory == null)
+ sessionFactory = buildSessionFactory();
+ return sessionFactory;
+ }
+}
diff --git a/spring-hibernate5/src/main/java/com/baeldung/manytomany/spring/PersistenceConfig.java b/spring-hibernate5/src/main/java/com/baeldung/manytomany/spring/PersistenceConfig.java
new file mode 100644
index 0000000000..6f359054b6
--- /dev/null
+++ b/spring-hibernate5/src/main/java/com/baeldung/manytomany/spring/PersistenceConfig.java
@@ -0,0 +1,70 @@
+package com.baeldung.manytomany.spring;
+
+import java.util.Properties;
+import javax.sql.DataSource;
+import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
+import org.springframework.orm.hibernate4.HibernateTransactionManager;
+import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+
+
+@Configuration
+@EnableTransactionManagement
+@PropertySource({ "classpath:persistence-mysql.properties" })
+@ComponentScan({ "com.baeldung.hibernate.manytomany" })
+public class PersistenceConfig {
+
+ @Autowired
+ private Environment env;
+
+ @Bean
+ public LocalSessionFactoryBean sessionFactory() {
+ final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
+ sessionFactory.setDataSource(restDataSource());
+ sessionFactory.setPackagesToScan(new String[] { "com.baeldung.hibernate.manytomany" });
+ sessionFactory.setHibernateProperties(hibernateProperties());
+
+ return sessionFactory;
+ }
+
+ @Bean
+ public DataSource restDataSource() {
+ final BasicDataSource dataSource = new BasicDataSource();
+ dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
+ dataSource.setUrl(env.getProperty("jdbc.url"));
+ dataSource.setUsername(env.getProperty("jdbc.user"));
+ dataSource.setPassword(env.getProperty("jdbc.pass"));
+
+ return dataSource;
+ }
+
+ @Bean
+ public PlatformTransactionManager hibernateTransactionManager() {
+ final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
+ transactionManager.setSessionFactory(sessionFactory().getObject());
+ return transactionManager;
+ }
+
+ @Bean
+ public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
+ return new PersistenceExceptionTranslationPostProcessor();
+ }
+
+ private final Properties hibernateProperties() {
+ final Properties hibernateProperties = new Properties();
+ //hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
+ hibernateProperties.setProperty("hibernate.show_sql", "true");
+
+ return hibernateProperties;
+ }
+}
diff --git a/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/IEmployeeDao.java b/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/IEmployeeDao.java
new file mode 100644
index 0000000000..d619807b64
--- /dev/null
+++ b/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/IEmployeeDao.java
@@ -0,0 +1,8 @@
+package com.baeldung.persistence.manytomany.dao;
+
+import com.baeldung.hibernate.manytomany.model.Employee;
+import com.baeldung.persistence.dao.common.IOperations;
+
+public interface IEmployeeDao extends IOperations{
+
+}
diff --git a/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/IProjectDao.java b/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/IProjectDao.java
new file mode 100644
index 0000000000..4a55714f8d
--- /dev/null
+++ b/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/IProjectDao.java
@@ -0,0 +1,8 @@
+package com.baeldung.persistence.manytomany.dao;
+
+import com.baeldung.hibernate.manytomany.model.Project;
+import com.baeldung.persistence.dao.common.IOperations;
+
+public interface IProjectDao extends IOperations{
+
+}
diff --git a/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/impl/EmployeeDao.java b/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/impl/EmployeeDao.java
new file mode 100644
index 0000000000..b062c00ff9
--- /dev/null
+++ b/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/impl/EmployeeDao.java
@@ -0,0 +1,16 @@
+package com.baeldung.persistence.manytomany.dao.impl;
+
+import org.springframework.stereotype.Repository;
+import com.baeldung.hibernate.manytomany.model.Employee;
+import com.baeldung.persistence.dao.common.AbstractHibernateDao;
+import com.baeldung.persistence.manytomany.dao.IEmployeeDao;
+
+@Repository
+public class EmployeeDao extends AbstractHibernateDao implements IEmployeeDao {
+
+ public EmployeeDao() {
+ super();
+
+ setClazz(Employee.class);
+ }
+}
diff --git a/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/impl/ProjectDao.java b/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/impl/ProjectDao.java
new file mode 100644
index 0000000000..772026fbc1
--- /dev/null
+++ b/spring-hibernate5/src/main/java/com/baeldung/persistence/manytomany/dao/impl/ProjectDao.java
@@ -0,0 +1,17 @@
+package com.baeldung.persistence.manytomany.dao.impl;
+
+import org.springframework.stereotype.Repository;
+import com.baeldung.hibernate.manytomany.model.Project;
+import com.baeldung.persistence.dao.common.AbstractHibernateDao;
+import com.baeldung.persistence.manytomany.dao.IProjectDao;
+
+
+@Repository
+public class ProjectDao extends AbstractHibernateDao implements IProjectDao {
+
+ public ProjectDao() {
+ super();
+
+ setClazz(Project.class);
+ }
+}
diff --git a/spring-hibernate5/src/main/resources/manytomany.cfg.xml b/spring-hibernate5/src/main/resources/manytomany.cfg.xml
new file mode 100644
index 0000000000..8a10fc1580
--- /dev/null
+++ b/spring-hibernate5/src/main/resources/manytomany.cfg.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+ com.mysql.jdbc.Driver
+
+
+ buddhinisam123
+
+
+ jdbc:mysql://localhost:3306/spring_hibernate_many_to_many
+
+
+ root
+
+
+ org.hibernate.dialect.MySQLDialect
+
+
+ thread
+
+ true
+
+
diff --git a/spring-hibernate5/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationJavaConfigMainIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationJavaConfigMainIntegrationTest.java
new file mode 100644
index 0000000000..61d821e85e
--- /dev/null
+++ b/spring-hibernate5/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationJavaConfigMainIntegrationTest.java
@@ -0,0 +1,53 @@
+package com.baeldung.hibernate.manytomany;
+
+
+import java.util.HashSet;
+import java.util.Set;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+import com.baeldung.hibernate.manytomany.model.Employee;
+import com.baeldung.hibernate.manytomany.model.Project;
+import com.baeldung.manytomany.spring.PersistenceConfig;
+
+
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class)
+public class HibernateManyToManyAnnotationJavaConfigMainIntegrationTest {
+
+ @Autowired
+ private SessionFactory sessionFactory;
+
+ private Session session;
+
+
+ @Before
+ public final void before() {
+ session = sessionFactory.openSession();
+ session.beginTransaction();
+ }
+
+ @After
+ public final void after() {
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ @Test
+ public final void whenEntitiesAreCreated_thenNoExceptions() {
+ Set projects = new HashSet();
+ projects.add(new Project("IT Project"));
+ projects.add(new Project("Networking Project"));
+ session.persist(new Employee("Peter", "Oven", projects));
+ session.persist(new Employee("Allan", "Norman", projects));
+ }
+
+}
diff --git a/spring-hibernate5/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationXMLConfigMainIntegrationTest.java b/spring-hibernate5/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationXMLConfigMainIntegrationTest.java
new file mode 100644
index 0000000000..5308134fac
--- /dev/null
+++ b/spring-hibernate5/src/test/java/com/baeldung/hibernate/manytomany/HibernateManyToManyAnnotationXMLConfigMainIntegrationTest.java
@@ -0,0 +1,84 @@
+package com.baeldung.hibernate.manytomany;
+
+import static org.junit.Assert.assertNotNull;
+import static junit.framework.TestCase.assertEquals;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import com.baeldung.hibernate.manytomany.util.HibernateUtil;
+import com.baeldung.hibernate.manytomany.model.Employee;
+import com.baeldung.hibernate.manytomany.model.Project;
+
+
+public class HibernateManyToManyAnnotationXMLConfigMainIntegrationTest {
+ private static SessionFactory sessionFactory;
+
+ private Session session;
+
+
+ @BeforeClass
+ public static void beforeTests() {
+ sessionFactory = HibernateUtil.getSessionFactory();
+ }
+
+ @Before
+ public void setUp() {
+ session = sessionFactory.openSession();
+ session.beginTransaction();
+ }
+
+
+ @Test
+ public void givenSession_checkIfDatabaseIsPopulated() {
+ Employee employee1 = new Employee("Peter", "Oven");
+ Set projects = new HashSet();
+ projects = employee1.getProjects();
+ int noProjects = projects.size();
+ assertEquals(0,noProjects);
+ Project project1 = new Project("IT Project");
+ assertNotNull(project1);
+ projects.add(project1);
+ Project project2 = new Project("Networking Project");
+ assertNotNull(project2);
+ projects.add(project2);
+ employee1.setProjects(projects);
+ assertNotNull(employee1);
+ Employee employee2 = new Employee("Allan", "Norman");
+ employee2.setProjects(projects);
+ assertNotNull(employee2);
+
+ session.persist(employee1);
+ session.persist(employee2);
+ session.getTransaction().commit();
+ session.close();
+
+ session = sessionFactory.openSession();
+ session.beginTransaction();
+ @SuppressWarnings("unchecked")
+ List projectList = session.createQuery("FROM Project").list();
+ assertNotNull(projectList);
+ @SuppressWarnings("unchecked")
+ List employeeList = session.createQuery("FROM Employee").list();
+ assertNotNull(employeeList);
+ }
+
+
+ @After
+ public void tearDown() {
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ @AfterClass
+ public static void afterTests() {
+ sessionFactory.close();
+ }
+
+}
diff --git a/spring-ldap/pom.xml b/spring-ldap/pom.xml
index 16d4879f10..05baf8c66d 100644
--- a/spring-ldap/pom.xml
+++ b/spring-ldap/pom.xml
@@ -1,6 +1,6 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.baeldung
@@ -97,6 +97,18 @@
test
+
+
+
+ org.springframework.data
+ spring-data-ldap
+ 1.0.6.RELEASE
+
+
+ org.springframework.data
+ spring-data-jpa
+ 1.11.6.RELEASE
+
diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/data/repository/User.java b/spring-ldap/src/main/java/com/baeldung/ldap/data/repository/User.java
new file mode 100644
index 0000000000..726fa53b02
--- /dev/null
+++ b/spring-ldap/src/main/java/com/baeldung/ldap/data/repository/User.java
@@ -0,0 +1,55 @@
+package com.baeldung.ldap.data.repository;
+
+import javax.naming.Name;
+
+import org.springframework.ldap.odm.annotations.Attribute;
+import org.springframework.ldap.odm.annotations.Entry;
+import org.springframework.ldap.odm.annotations.Id;
+
+@Entry(base = "ou=users", objectClasses = { "person", "inetOrgPerson", "top" })
+public class User {
+
+ @Id
+ private Name id;
+
+ private @Attribute(name = "cn") String username;
+ private @Attribute(name = "sn") String password;
+
+ public User() {
+ }
+
+ public User(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ public Name getId() {
+ return id;
+ }
+
+ public void setId(Name id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @Override
+ public String toString() {
+ return username;
+ }
+
+}
diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/data/repository/UserRepository.java b/spring-ldap/src/main/java/com/baeldung/ldap/data/repository/UserRepository.java
new file mode 100644
index 0000000000..12dc0f7f14
--- /dev/null
+++ b/spring-ldap/src/main/java/com/baeldung/ldap/data/repository/UserRepository.java
@@ -0,0 +1,17 @@
+package com.baeldung.ldap.data.repository;
+
+import java.util.List;
+
+import org.springframework.data.ldap.repository.LdapRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserRepository extends LdapRepository {
+
+ User findByUsername(String username);
+
+ User findByUsernameAndPassword(String username, String password);
+
+ List findByUsernameLikeIgnoreCase(String username);
+
+}
diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/data/service/LdapClient.java b/spring-ldap/src/main/java/com/baeldung/ldap/data/service/LdapClient.java
new file mode 100644
index 0000000000..1b04edb35b
--- /dev/null
+++ b/spring-ldap/src/main/java/com/baeldung/ldap/data/service/LdapClient.java
@@ -0,0 +1,87 @@
+package com.baeldung.ldap.data.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.ldap.core.AttributesMapper;
+import org.springframework.ldap.core.ContextSource;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DirContextOperations;
+import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.support.LdapNameBuilder;
+
+import javax.naming.Name;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import java.util.List;
+
+public class LdapClient {
+
+ @Autowired
+ private Environment env;
+
+ @Autowired
+ private ContextSource contextSource;
+
+ @Autowired
+ private LdapTemplate ldapTemplate;
+
+ public void authenticate(final String username, final String password) {
+ contextSource.getContext("cn=" + username + ",ou=users," + env.getRequiredProperty("ldap.partitionSuffix"), password);
+ }
+
+ public List search(final String username) {
+ return ldapTemplate.search(
+ "ou=users",
+ "cn=" + username,
+ (AttributesMapper) attrs -> (String) attrs
+ .get("cn")
+ .get());
+ }
+
+ public void create(final String username, final String password) {
+ Name dn = LdapNameBuilder
+ .newInstance()
+ .add("ou", "users")
+ .add("cn", username)
+ .build();
+ DirContextAdapter context = new DirContextAdapter(dn);
+
+ context.setAttributeValues("objectclass", new String[]{"top", "person", "organizationalPerson", "inetOrgPerson"});
+ context.setAttributeValue("cn", username);
+ context.setAttributeValue("sn", username);
+ context.setAttributeValue("userPassword", digestSHA(password));
+
+ ldapTemplate.bind(context);
+ }
+
+ public void modify(final String username, final String password) {
+ Name dn = LdapNameBuilder
+ .newInstance()
+ .add("ou", "users")
+ .add("cn", username)
+ .build();
+ DirContextOperations context = ldapTemplate.lookupContext(dn);
+
+ context.setAttributeValues("objectclass", new String[]{"top", "person", "organizationalPerson", "inetOrgPerson"});
+ context.setAttributeValue("cn", username);
+ context.setAttributeValue("sn", username);
+ context.setAttributeValue("userPassword", digestSHA(password));
+
+ ldapTemplate.modifyAttributes(context);
+ }
+
+ private String digestSHA(final String password) {
+ String base64;
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA");
+ digest.update(password.getBytes());
+ base64 = Base64
+ .getEncoder()
+ .encodeToString(digest.digest());
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ return "{SHA}" + base64;
+ }
+}
diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/data/service/UserService.java b/spring-ldap/src/main/java/com/baeldung/ldap/data/service/UserService.java
new file mode 100644
index 0000000000..54954e3c9d
--- /dev/null
+++ b/spring-ldap/src/main/java/com/baeldung/ldap/data/service/UserService.java
@@ -0,0 +1,63 @@
+package com.baeldung.ldap.data.service;
+
+import com.baeldung.ldap.data.repository.User;
+import com.baeldung.ldap.data.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.ldap.support.LdapUtils;
+import org.springframework.stereotype.Service;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class UserService {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ public Boolean authenticate(final String username, final String password) {
+ User user = userRepository.findByUsernameAndPassword(username, password);
+ return user != null;
+ }
+
+ public List search(final String username) {
+ List userList = userRepository.findByUsernameLikeIgnoreCase(username);
+ if (userList == null) {
+ return Collections.emptyList();
+ }
+
+ return userList.stream()
+ .map(User::getUsername)
+ .collect(Collectors.toList());
+ }
+
+ public void create(final String username, final String password) {
+ User newUser = new User(username,digestSHA(password));
+ newUser.setId(LdapUtils.emptyLdapName());
+ userRepository.save(newUser);
+
+ }
+
+ public void modify(final String username, final String password) {
+ User user = userRepository.findByUsername(username);
+ user.setPassword(password);
+ userRepository.save(user);
+ }
+
+ private String digestSHA(final String password) {
+ String base64;
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA");
+ digest.update(password.getBytes());
+ base64 = Base64.getEncoder()
+ .encodeToString(digest.digest());
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ return "{SHA}" + base64;
+ }
+}
diff --git a/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java b/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java
index 8572e5d1be..fb3000b2bd 100644
--- a/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java
+++ b/spring-ldap/src/main/java/com/baeldung/ldap/javaconfig/AppConfig.java
@@ -1,5 +1,6 @@
package com.baeldung.ldap.javaconfig;
+import com.baeldung.ldap.client.LdapClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@@ -7,15 +8,15 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
+import org.springframework.data.ldap.repository.config.EnableLdapRepositories;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
-import com.baeldung.ldap.client.LdapClient;
-
@Configuration
@PropertySource("classpath:application.properties")
-@ComponentScan(basePackages = { "com.baeldung.ldap.*" })
+@ComponentScan(basePackages = {"com.baeldung.ldap.*"})
@Profile("default")
+@EnableLdapRepositories(basePackages = "com.baeldung.ldap.**")
public class AppConfig {
@Autowired
diff --git a/spring-ldap/src/main/resources/logback.xml b/spring-ldap/src/main/resources/logback.xml
index ec0dc2469a..32b78577ee 100644
--- a/spring-ldap/src/main/resources/logback.xml
+++ b/spring-ldap/src/main/resources/logback.xml
@@ -7,13 +7,13 @@
-
-
+
+
-
+
-
+
\ No newline at end of file
diff --git a/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java b/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java
index b65588dc38..f5b74d64c6 100644
--- a/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java
+++ b/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapClientLiveTest.java
@@ -1,7 +1,6 @@
package com.baeldung.ldap.client;
-import java.util.List;
-
+import com.baeldung.ldap.javaconfig.TestConfig;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
@@ -13,11 +12,11 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
-import com.baeldung.ldap.javaconfig.TestConfig;
+import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("testlive")
-@ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class)
+@ContextConfiguration(classes = {TestConfig.class}, loader = AnnotationConfigContextLoader.class)
public class LdapClientLiveTest {
private static final String USER2 = "TEST02";
diff --git a/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapDataRepositoryTest.java b/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapDataRepositoryTest.java
new file mode 100644
index 0000000000..9f38af9263
--- /dev/null
+++ b/spring-ldap/src/test/java/com/baeldung/ldap/client/LdapDataRepositoryTest.java
@@ -0,0 +1,67 @@
+package com.baeldung.ldap.client;
+
+import com.baeldung.ldap.data.service.UserService;
+import com.baeldung.ldap.javaconfig.TestConfig;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ActiveProfiles("testlive")
+@ContextConfiguration(classes = {TestConfig.class}, loader = AnnotationConfigContextLoader.class)
+public class LdapDataRepositoryTest {
+
+ private static final String USER2 = "TEST02";
+ private static final String USER3 = "TEST03";
+ private static final String USER4 = "TEST04";
+
+ private static final String USER2_PWD = "TEST02";
+ private static final String USER3_PWD = "TEST03";
+ private static final String USER4_PWD = "TEST04";
+
+ private static final String SEARCH_STRING = "TEST*";
+
+ @Autowired
+ private UserService userService;
+
+ @Test
+ public void givenLdapClient_whenCorrectCredentials_thenSuccessfulLogin() {
+ Boolean isValid = userService.authenticate(USER3, USER3_PWD);
+ assertEquals(true, isValid);
+ }
+
+ @Test
+ public void givenLdapClient_whenIncorrectCredentials_thenFailedLogin() {
+ Boolean isValid = userService.authenticate(USER3, USER2_PWD);
+ assertEquals(false, isValid);
+ }
+
+ @Test
+ public void givenLdapClient_whenCorrectSearchFilter_thenEntriesReturned() {
+ List userList = userService.search(SEARCH_STRING);
+ assertThat(userList, Matchers.containsInAnyOrder(USER2, USER3));
+ }
+
+ @Test
+ public void givenLdapClientNotExists_whenDataProvided_thenNewUserCreated() {
+ userService.create(USER4, USER4_PWD);
+ userService.authenticate(USER4, USER4_PWD);
+ }
+
+ @Test
+ public void givenLdapClientExists_whenDataProvided_thenExistingUserModified() {
+ userService.modify(USER2, USER3_PWD);
+ userService.authenticate(USER2, USER3_PWD);
+ }
+
+}
diff --git a/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java b/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java
index e2968e977c..c6293982da 100644
--- a/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java
+++ b/spring-ldap/src/test/java/com/baeldung/ldap/javaconfig/TestConfig.java
@@ -1,5 +1,6 @@
package com.baeldung.ldap.javaconfig;
+import com.baeldung.ldap.client.LdapClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@@ -8,15 +9,15 @@ import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
+import org.springframework.data.ldap.repository.config.EnableLdapRepositories;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.test.TestContextSourceFactoryBean;
-import com.baeldung.ldap.client.LdapClient;
-
@Configuration
@PropertySource("classpath:test_application.properties")
-@ComponentScan(basePackages = { "com.baeldung.ldap.*" })
+@ComponentScan(basePackages = {"com.baeldung.ldap.*"})
+@EnableLdapRepositories(basePackages = "com.baeldung.ldap.**")
@Profile("testlive")
public class TestConfig {
@Autowired
diff --git a/spring-mvc-kotlin/pom.xml b/spring-mvc-kotlin/pom.xml
new file mode 100644
index 0000000000..087f02fc68
--- /dev/null
+++ b/spring-mvc-kotlin/pom.xml
@@ -0,0 +1,79 @@
+
+
+ 4.0.0
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+
+
+ spring-mvc-kotlin
+ 0.1-SNAPSHOT
+
+ spring-mvc-kotlin
+
+ war
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jre8
+ 1.1.4
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ 1.1.4
+
+
+
+ org.springframework
+ spring-web
+ 4.3.10.RELEASE
+
+
+ org.springframework
+ spring-webmvc
+ 4.3.10.RELEASE
+
+
+ javax.servlet
+ jstl
+ 1.2
+
+
+
+
+ ${project.basedir}/src/main/kotlin
+ ${project.basedir}/src/test/kotlin
+
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ 1.1.4
+
+
+
+ compile
+ compile
+
+ compile
+
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/mvc/ApplicationWebConfig.kt b/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/mvc/ApplicationWebConfig.kt
new file mode 100644
index 0000000000..4907e46efb
--- /dev/null
+++ b/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/mvc/ApplicationWebConfig.kt
@@ -0,0 +1,37 @@
+package com.baeldung.kotlin.mvc
+
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.web.servlet.ViewResolver
+import org.springframework.web.servlet.config.annotation.EnableWebMvc
+import org.springframework.web.servlet.config.annotation.ViewControllerRegistry
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
+import org.springframework.web.servlet.view.InternalResourceViewResolver
+import org.springframework.web.servlet.view.JstlView
+
+
+
+
+
+@EnableWebMvc
+@Configuration
+open class ApplicationWebConfig: WebMvcConfigurerAdapter() {
+
+ override fun addViewControllers(registry: ViewControllerRegistry?) {
+ super.addViewControllers(registry)
+
+ registry!!.addViewController("/welcome.html")
+ }
+
+ @Bean
+ open fun viewResolver(): ViewResolver {
+ val bean = InternalResourceViewResolver()
+
+ bean.setViewClass(JstlView::class.java)
+ bean.setPrefix("/WEB-INF/view/")
+ bean.setSuffix(".jsp")
+
+ return bean
+ }
+
+}
\ No newline at end of file
diff --git a/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/mvc/ApplicationWebInitializer.kt b/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/mvc/ApplicationWebInitializer.kt
new file mode 100644
index 0000000000..a4d1614271
--- /dev/null
+++ b/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/mvc/ApplicationWebInitializer.kt
@@ -0,0 +1,19 @@
+package com.baeldung.kotlin.mvc
+
+import com.baeldung.kotlin.mvc.ApplicationWebConfig
+import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer
+
+class ApplicationWebInitializer: AbstractAnnotationConfigDispatcherServletInitializer() {
+
+ override fun getRootConfigClasses(): Array>? {
+ return null
+ }
+
+ override fun getServletMappings(): Array {
+ return arrayOf("/")
+ }
+
+ override fun getServletConfigClasses(): Array> {
+ return arrayOf(ApplicationWebConfig::class.java)
+ }
+}
\ No newline at end of file
diff --git a/spring-mvc-kotlin/src/main/webapp/WEB-INF/spring-web-config.xml b/spring-mvc-kotlin/src/main/webapp/WEB-INF/spring-web-config.xml
new file mode 100644
index 0000000000..ffe83a66fa
--- /dev/null
+++ b/spring-mvc-kotlin/src/main/webapp/WEB-INF/spring-web-config.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-mvc-kotlin/src/main/webapp/WEB-INF/view/welcome.jsp b/spring-mvc-kotlin/src/main/webapp/WEB-INF/view/welcome.jsp
new file mode 100644
index 0000000000..bdb6716889
--- /dev/null
+++ b/spring-mvc-kotlin/src/main/webapp/WEB-INF/view/welcome.jsp
@@ -0,0 +1,7 @@
+
+ Welcome
+
+
+ This is the body of the welcome view 2
+
+
\ No newline at end of file
diff --git a/spring-mvc-kotlin/src/main/webapp/WEB-INF/web.xml b/spring-mvc-kotlin/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000000..cbee6a1b11
--- /dev/null
+++ b/spring-mvc-kotlin/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,24 @@
+
+
+ Spring Kotlin MVC Application
+
+
+ spring-web-mvc
+ org.springframework.web.servlet.DispatcherServlet
+ 1
+
+ contextConfigLocation
+ /WEB-INF/spring-web-config.xml
+
+
+
+
+ spring-web-mvc
+ /
+
+
+
\ No newline at end of file
diff --git a/spring-rest/README.md b/spring-rest/README.md
index 66c893e45f..2cea315188 100644
--- a/spring-rest/README.md
+++ b/spring-rest/README.md
@@ -15,3 +15,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
- [A Custom Media Type for a Spring REST API](http://www.baeldung.com/spring-rest-custom-media-type)
- [HTTP PUT vs HTTP PATCH in a REST API](http://www.baeldung.com/http-put-patch-difference-spring)
- [Exploring the Spring Boot TestRestTemplate](http://www.baeldung.com/spring-boot-testresttemplate)
+- [Spring – Log Incoming Requests](http://www.baeldung.com/spring-http-logging)
diff --git a/testing/README.md b/testing/README.md
index 6338a52f3d..a691737e4f 100644
--- a/testing/README.md
+++ b/testing/README.md
@@ -12,3 +12,4 @@
- [Testing with Google Truth](http://www.baeldung.com/google-truth)
- [Testing with JGoTesting](http://www.baeldung.com/jgotesting)
- [Introduction to JUnitParams](http://www.baeldung.com/junit-params)
+- [Cucumber Java 8 Support](http://www.baeldung.com/cucumber-java-8-support)
diff --git a/undertow/pom.xml b/undertow/pom.xml
new file mode 100644
index 0000000000..a0f2dc53ee
--- /dev/null
+++ b/undertow/pom.xml
@@ -0,0 +1,58 @@
+
+ 4.0.0
+ com.baeldung.undertow
+ undertow
+ jar
+ 1.0-SNAPSHOT
+ undertow
+ http://maven.apache.org
+
+
+ 1.8
+ 1.8
+
+
+
+
+ io.undertow
+ undertow-core
+ 1.4.18.Final
+
+
+ io.undertow
+ undertow-servlet
+ 1.4.18.Final
+
+
+
+
+ ${project.artifactId}
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ com.baeldung.undertow.SimpleServer
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/undertow/src/main/java/com/baeldung/undertow/SimpleServer.java b/undertow/src/main/java/com/baeldung/undertow/SimpleServer.java
new file mode 100644
index 0000000000..7f869746be
--- /dev/null
+++ b/undertow/src/main/java/com/baeldung/undertow/SimpleServer.java
@@ -0,0 +1,16 @@
+package com.baeldung.undertow;
+
+import io.undertow.Undertow;
+import io.undertow.util.Headers;
+
+public class SimpleServer {
+
+ public static void main(String[] args) {
+ Undertow server = Undertow.builder().addHttpListener(8080, "localhost").setHandler(exchange -> {
+ exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
+ exchange.getResponseSender().send("Hello Baeldung");
+ }).build();
+ server.start();
+ }
+
+}
diff --git a/undertow/src/main/java/com/baeldung/undertow/ftp/FileServer.java b/undertow/src/main/java/com/baeldung/undertow/ftp/FileServer.java
new file mode 100644
index 0000000000..90cad9ebbd
--- /dev/null
+++ b/undertow/src/main/java/com/baeldung/undertow/ftp/FileServer.java
@@ -0,0 +1,20 @@
+package com.baeldung.undertow.ftp;
+
+import java.nio.file.Paths;
+
+import io.undertow.Undertow;
+import io.undertow.server.handlers.resource.PathResourceManager;
+
+import static io.undertow.Handlers.resource;
+
+public class FileServer {
+
+ public static void main(String[] args) {
+ Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
+ .setHandler(resource(new PathResourceManager(Paths.get(System.getProperty("user.home")), 100))
+ .setDirectoryListingEnabled(true))
+ .build();
+ server.start();
+ }
+
+}
diff --git a/undertow/src/main/java/com/baeldung/undertow/secure/CustomIdentityManager.java b/undertow/src/main/java/com/baeldung/undertow/secure/CustomIdentityManager.java
new file mode 100644
index 0000000000..e0984f65a5
--- /dev/null
+++ b/undertow/src/main/java/com/baeldung/undertow/secure/CustomIdentityManager.java
@@ -0,0 +1,77 @@
+package com.baeldung.undertow.secure;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import io.undertow.security.idm.Account;
+import io.undertow.security.idm.Credential;
+import io.undertow.security.idm.PasswordCredential;
+
+public class CustomIdentityManager implements io.undertow.security.idm.IdentityManager {
+
+ private final Map users;
+
+ CustomIdentityManager(final Map users) {
+ this.users = users;
+ }
+
+ @Override
+ public Account verify(Account account) {
+ return account;
+ }
+
+ @Override
+ public Account verify(Credential credential) {
+ return null;
+ }
+
+ @Override
+ public Account verify(String id, Credential credential) {
+ Account account = getAccount(id);
+ if (account != null && verifyCredential(account, credential)) {
+ return account;
+ }
+ return null;
+ }
+
+ private boolean verifyCredential(Account account, Credential credential) {
+ if (credential instanceof PasswordCredential) {
+ char[] password = ((PasswordCredential) credential).getPassword();
+ char[] expectedPassword = users.get(account.getPrincipal().getName());
+
+ return Arrays.equals(password, expectedPassword);
+ }
+ return false;
+ }
+
+ private Account getAccount(final String id) {
+ if (users.containsKey(id)) {
+ return new Account() {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Principal principal = new Principal() {
+ @Override
+ public String getName() {
+ return id;
+ }
+ };
+
+ @Override
+ public Principal getPrincipal() {
+ return principal;
+ }
+
+ @Override
+ public Set getRoles() {
+ return Collections.emptySet();
+ }
+ };
+ }
+ return null;
+ }
+
+}
diff --git a/undertow/src/main/java/com/baeldung/undertow/secure/SecureServer.java b/undertow/src/main/java/com/baeldung/undertow/secure/SecureServer.java
new file mode 100644
index 0000000000..6f520944db
--- /dev/null
+++ b/undertow/src/main/java/com/baeldung/undertow/secure/SecureServer.java
@@ -0,0 +1,52 @@
+package com.baeldung.undertow.secure;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import io.undertow.Undertow;
+import io.undertow.io.IoCallback;
+import io.undertow.security.api.AuthenticationMechanism;
+import io.undertow.security.api.AuthenticationMode;
+import io.undertow.security.api.SecurityContext;
+import io.undertow.security.handlers.AuthenticationCallHandler;
+import io.undertow.security.handlers.AuthenticationConstraintHandler;
+import io.undertow.security.handlers.AuthenticationMechanismsHandler;
+import io.undertow.security.handlers.SecurityInitialHandler;
+import io.undertow.security.idm.IdentityManager;
+import io.undertow.security.impl.BasicAuthenticationMechanism;
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+
+public class SecureServer {
+
+ public static void main(String[] args) {
+ final Map users = new HashMap<>(2);
+ users.put("root", "password".toCharArray());
+ users.put("admin", "password".toCharArray());
+
+ final IdentityManager idm = new CustomIdentityManager(users);
+
+ Undertow server = Undertow.builder().addHttpListener(8080, "localhost").setHandler(addSecurity((exchange) -> {
+ final SecurityContext context = exchange.getSecurityContext();
+ exchange.getResponseSender().send("Hello " + context.getAuthenticatedAccount().getPrincipal().getName(),
+ IoCallback.END_EXCHANGE);
+ }, idm)).build();
+
+ server.start();
+
+ }
+
+ private static HttpHandler addSecurity(final HttpHandler toWrap, final IdentityManager identityManager) {
+ HttpHandler handler = toWrap;
+ handler = new AuthenticationCallHandler(handler);
+ handler = new AuthenticationConstraintHandler(handler);
+ final List mechanisms = Collections
+ . singletonList(new BasicAuthenticationMechanism("Baeldung_Realm"));
+ handler = new AuthenticationMechanismsHandler(handler, mechanisms);
+ handler = new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, identityManager, handler);
+ return handler;
+ }
+
+}
diff --git a/undertow/src/main/java/com/baeldung/undertow/socket/SocketServer.java b/undertow/src/main/java/com/baeldung/undertow/socket/SocketServer.java
new file mode 100644
index 0000000000..9e0e065c3a
--- /dev/null
+++ b/undertow/src/main/java/com/baeldung/undertow/socket/SocketServer.java
@@ -0,0 +1,36 @@
+package com.baeldung.undertow.socket;
+
+import io.undertow.Undertow;
+import io.undertow.server.handlers.resource.ClassPathResourceManager;
+import io.undertow.websockets.core.AbstractReceiveListener;
+import io.undertow.websockets.core.BufferedTextMessage;
+import io.undertow.websockets.core.WebSocketChannel;
+import io.undertow.websockets.core.WebSockets;
+
+import static io.undertow.Handlers.path;
+import static io.undertow.Handlers.resource;
+import static io.undertow.Handlers.websocket;
+
+public class SocketServer {
+
+ public static void main(String[] args) {
+ Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
+ .setHandler(path().addPrefixPath("/baeldungApp", websocket((exchange, channel) -> {
+ channel.getReceiveSetter().set(new AbstractReceiveListener() {
+ @Override
+ protected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) {
+ final String messageData = message.getData();
+ for (WebSocketChannel session : channel.getPeerConnections()) {
+ WebSockets.sendText(messageData, session, null);
+ }
+ }
+ });
+ channel.resumeReceives();
+ })).addPrefixPath("/", resource(new ClassPathResourceManager(SocketServer.class.getClassLoader(),
+ SocketServer.class.getPackage())).addWelcomeFiles("index.html")))
+ .build();
+
+ server.start();
+ }
+
+}
diff --git a/vavr/README.md b/vavr/README.md
index c4155c2680..d7816f3f9f 100644
--- a/vavr/README.md
+++ b/vavr/README.md
@@ -5,3 +5,4 @@
- [Property Testing Example With Vavr](http://www.baeldung.com/javaslang-property-testing)
- [Exceptions in Lambda Expression Using Vavr](http://www.baeldung.com/exceptions-using-vavr)
- [Vavr (ex-Javaslang) Support in Spring Data](http://www.baeldung.com/spring-vavr)
+