diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java new file mode 100644 index 0000000000..e42475c17e --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/EquirectangularApproximation.java @@ -0,0 +1,19 @@ +package com.baeldung.algorithms.latlondistance; + +public class EquirectangularApproximation { + + private static final int EARTH_RADIUS = 6371; // Approx Earth radius in KM + + public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) { + double lat1Rad = Math.toRadians(lat1); + double lat2Rad = Math.toRadians(lat2); + double lon1Rad = Math.toRadians(lon1); + double lon2Rad = Math.toRadians(lon2); + + double x = (lon2Rad - lon1Rad) * Math.cos((lat1Rad + lat2Rad) / 2); + double y = (lat2Rad - lat1Rad); + double distance = Math.sqrt(x * x + y * y) * EARTH_RADIUS; + + return distance; + } +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java new file mode 100644 index 0000000000..69074ec559 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/HaversineDistance.java @@ -0,0 +1,24 @@ +package com.baeldung.algorithms.latlondistance; + +public class HaversineDistance { + private static final int EARTH_RADIUS = 6371; // Approx Earth radius in KM + + public static double calculateDistance(double startLat, double startLong, + double endLat, double endLong) { + + double dLat = Math.toRadians((endLat - startLat)); + double dLong = Math.toRadians((endLong - startLong)); + + startLat = Math.toRadians(startLat); + endLat = Math.toRadians(endLat); + + double a = haversine(dLat) + Math.cos(startLat) * Math.cos(endLat) * haversine(dLong); + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + return EARTH_RADIUS * c; + } + + public static double haversine(double val) { + return Math.pow(Math.sin(val / 2), 2); + } +} diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java new file mode 100644 index 0000000000..7d0b0b907f --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/main/java/com/baeldung/algorithms/latlondistance/VincentyDistance.java @@ -0,0 +1,53 @@ +package com.baeldung.algorithms.latlondistance; + +public class VincentyDistance { + + // Constants for WGS84 ellipsoid model of Earth + private static final double SEMI_MAJOR_AXIS_MT = 6378137; + private static final double SEMI_MINOR_AXIS_MT = 6356752.314245; + private static final double FLATTENING = 1 / 298.257223563; + private static final double ERROR_TOLERANCE = 1e-12; + + public static double calculateDistance(double latitude1, double longitude1, double latitude2, double longitude2) { + double U1 = Math.atan((1 - FLATTENING) * Math.tan(Math.toRadians(latitude1))); + double U2 = Math.atan((1 - FLATTENING) * Math.tan(Math.toRadians(latitude2))); + + double sinU1 = Math.sin(U1); + double cosU1 = Math.cos(U1); + double sinU2 = Math.sin(U2); + double cosU2 = Math.cos(U2); + + double longitudeDifference = Math.toRadians(longitude2 - longitude1); + double previousLongitudeDifference; + + double sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM; + + do { + sinSigma = Math.sqrt(Math.pow(cosU2 * Math.sin(longitudeDifference), 2) + + Math.pow(cosU1 * sinU2 - sinU1 * cosU2 * Math.cos(longitudeDifference), 2)); + cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * Math.cos(longitudeDifference); + sigma = Math.atan2(sinSigma, cosSigma); + sinAlpha = cosU1 * cosU2 * Math.sin(longitudeDifference) / sinSigma; + cosSqAlpha = 1 - Math.pow(sinAlpha, 2); + cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; + if (Double.isNaN(cos2SigmaM)) { + cos2SigmaM = 0; + } + previousLongitudeDifference = longitudeDifference; + double C = FLATTENING / 16 * cosSqAlpha * (4 + FLATTENING * (4 - 3 * cosSqAlpha)); + longitudeDifference = Math.toRadians(longitude2 - longitude1) + (1 - C) * FLATTENING * sinAlpha * + (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * Math.pow(cos2SigmaM, 2)))); + } while (Math.abs(longitudeDifference - previousLongitudeDifference) > ERROR_TOLERANCE); + + double uSq = cosSqAlpha * (Math.pow(SEMI_MAJOR_AXIS_MT, 2) - Math.pow(SEMI_MINOR_AXIS_MT, 2)) / Math.pow(SEMI_MINOR_AXIS_MT, 2); + + double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); + double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); + + double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * Math.pow(cos2SigmaM, 2)) - + B / 6 * cos2SigmaM * (-3 + 4 * Math.pow(sinSigma, 2)) * (-3 + 4 * Math.pow(cos2SigmaM, 2)))); + + double distanceMt = SEMI_MINOR_AXIS_MT * A * (sigma - deltaSigma); + return distanceMt / 1000; + } +} \ No newline at end of file diff --git a/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java new file mode 100644 index 0000000000..9e72f86287 --- /dev/null +++ b/algorithms-modules/algorithms-miscellaneous-7/src/test/java/com/baeldung/algorithms/latlondistance/GeoDistanceUnitTest.java @@ -0,0 +1,26 @@ +package com.baeldung.algorithms.latlondistance; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GeoDistanceUnitTest { + @Test + public void testCalculateDistance() { + double lat1 = 40.714268; // New York + double lon1 = -74.005974; + double lat2 = 34.0522; // Los Angeles + double lon2 = -118.2437; + + double equirectangularDistance = EquirectangularApproximation.calculateDistance(lat1, lon1, lat2, lon2); + double haversineDistance = HaversineDistance.calculateDistance(lat1, lon1, lat2, lon2); + double vincentyDistance = VincentyDistance.calculateDistance(lat1, lon1, lat2, lon2); + + double expectedDistance = 3944; + assertTrue(Math.abs(equirectangularDistance - expectedDistance) < 100); + assertTrue(Math.abs(haversineDistance - expectedDistance) < 10); + assertTrue(Math.abs(vincentyDistance - expectedDistance) < 0.5); + + } + +} \ No newline at end of file diff --git a/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java b/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java index c58763b1c0..818d0c3cd9 100644 --- a/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java +++ b/apache-httpclient-2/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java @@ -1,36 +1,43 @@ package com.baeldung.tlsversion; -import javax.net.ssl.SSLSocket; - -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.ssl.SSLContexts; -import org.apache.http.util.EntityUtils; - import java.io.IOException; +import javax.net.ssl.SSLSocket; + +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.TlsConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.ssl.TLS; +import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.util.Timeout; + public class ClientTlsVersionExamples { - public static CloseableHttpClient setViaSocketFactory() { - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( - SSLContexts.createDefault(), - new String[] { "TLSv1.2", "TLSv1.3" }, - null, - SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() + .setDefaultTlsConfig(TlsConfig.custom() + .setHandshakeTimeout(Timeout.ofSeconds(30)) + .setSupportedProtocols(TLS.V_1_2, TLS.V_1_3) + .build()) + .build(); - return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + return HttpClients.custom() + .setConnectionManager(cm) + .build(); } public static CloseableHttpClient setTlsVersionPerConnection() { SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) { - @Override protected void prepareSocket(SSLSocket socket) { - String hostname = socket.getInetAddress().getHostName(); + String hostname = socket.getInetAddress() + .getHostName(); if (hostname.endsWith("internal.system.com")) { socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }); } else { @@ -39,7 +46,14 @@ public class ClientTlsVersionExamples { } }; - return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + HttpClientConnectionManager connManager = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslsf) + .build(); + + return HttpClients.custom() + .setConnectionManager(connManager) + .build(); + } // To configure the TLS versions for the client, set the https.protocols system property during runtime. @@ -47,15 +61,11 @@ public class ClientTlsVersionExamples { public static CloseableHttpClient setViaSystemProperties() { return HttpClients.createSystem(); // Alternatively: - // return HttpClients.custom().useSystemProperties().build(); + //return HttpClients.custom().useSystemProperties().build(); } public static void main(String[] args) throws IOException { - // Alternatively: - // CloseableHttpClient httpClient = setTlsVersionPerConnection(); - // CloseableHttpClient httpClient = setViaSystemProperties(); - try (CloseableHttpClient httpClient = setViaSocketFactory(); - CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { + try (CloseableHttpClient httpClient = setViaSocketFactory(); CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { HttpEntity entity = response.getEntity(); EntityUtils.consume(entity); diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java index 57a8f0a806..9d5294aa7e 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/HttpClientConnectionManagementLiveTest.java @@ -1,69 +1,71 @@ package com.baeldung.httpclient.conn; -import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Iterator; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import org.apache.http.HeaderElement; -import org.apache.http.HeaderElementIterator; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.config.SocketConfig; -import org.apache.http.conn.ConnectionKeepAliveStrategy; -import org.apache.http.conn.ConnectionPoolTimeoutException; -import org.apache.http.conn.ConnectionRequest; -import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.message.BasicHeaderElementIterator; -import org.apache.http.protocol.HTTP; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpCoreContext; -import org.apache.http.protocol.HttpRequestExecutor; -import org.apache.http.util.EntityUtils; -import org.junit.Ignore; +import org.apache.hc.client5.http.ConnectionKeepAliveStrategy; +import org.apache.hc.client5.http.HttpRoute; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.io.ConnectionEndpoint; +import org.apache.hc.client5.http.io.LeaseRequest; +import org.apache.hc.core5.http.HeaderElement; +import org.apache.hc.core5.http.HeaderElements; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.message.MessageSupport; +import org.apache.hc.core5.http.message.StatusLine; +import org.apache.hc.core5.http.protocol.BasicHttpContext; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.pool.PoolStats; +import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; +import org.junit.Assert; import org.junit.Test; public class HttpClientConnectionManagementLiveTest { // Example 2.1. Getting a Connection Request for a Low Level Connection (HttpClientConnection) @Test - public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ConnectionPoolTimeoutException, InterruptedException, ExecutionException { - try (BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager()) { - HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); - final ConnectionRequest connRequest = connManager.requestConnection(route, null); - assertNotNull(connRequest.get(1000, TimeUnit.SECONDS)); - } + public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ExecutionException, InterruptedException, TimeoutException { + BasicHttpClientConnectionManager connMgr = new BasicHttpClientConnectionManager(); + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); + final LeaseRequest connRequest = connMgr.lease("some-id", route, null); + assertNotNull(connRequest.get(Timeout.ZERO_MILLISECONDS)); + connMgr.close(); } // Example 3.1. Setting the PoolingHttpClientConnectionManager on a HttpClient @Test - public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws ClientProtocolException, IOException { + public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws IOException { PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(poolingConnManager) .build(); client.execute(new HttpGet("https://www.baeldung.com")); - assertTrue(poolingConnManager.getTotalStats() .getLeased() == 1); + client.close(); + poolingConnManager.close(); } // Example 3.2. Using Two HttpClients to Connect to One Target Host Each @Test - public final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException { + public final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException, IOException { HttpGet get1 = new HttpGet("https://www.baeldung.com"); HttpGet get2 = new HttpGet("https://www.google.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); @@ -81,38 +83,52 @@ public class HttpClientConnectionManagementLiveTest { thread1.join(); thread2.join(); - assertTrue(connManager.getTotalStats() + Assert.assertTrue(connManager.getTotalStats() .getLeased() == 0); + client1.close(); + client2.close(); + connManager.close(); } // Example 4.1. Increasing the Number of Connections that Can be Open and Managed Beyond the default Limits @Test - public final void whenIncreasingConnectionPool_thenNoEceptions() { - try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { - connManager.setMaxTotal(5); - connManager.setDefaultMaxPerRoute(4); - HttpHost host = new HttpHost("www.baeldung.com", 80); - connManager.setMaxPerRoute(new HttpRoute(host), 5); - } + public final void whenIncreasingConnectionPool_thenNoExceptions() { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(4); + HttpHost host = new HttpHost("www.baeldung.com", 80); + connManager.setMaxPerRoute(new HttpRoute(host), 5); + connManager.close(); } // Example 4.2. Using Threads to Execute Connections @Test - public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteReuqest() throws InterruptedException { + public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteRequest() throws InterruptedException, IOException { HttpGet get = new HttpGet("http://www.baeldung.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) .build(); - MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get); - MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get); - MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread4 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread5 = new MultiHttpClientConnThread(client, get, connManager); + MultiHttpClientConnThread thread6 = new MultiHttpClientConnThread(client, get, connManager); thread1.start(); thread2.start(); thread3.start(); + thread4.start(); + thread5.start(); + thread6.start(); thread1.join(); thread2.join(); thread3.join(); + thread4.join(); + thread5.join(); + thread6.join(); + client.close(); + connManager.close(); } // Example 5.1. A Custom Keep Alive Strategy @@ -120,22 +136,19 @@ public class HttpClientConnectionManagementLiveTest { public final void whenCustomizingKeepAliveStrategy_thenNoExceptions() { final ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { @Override - public long getKeepAliveDuration(final HttpResponse myResponse, final HttpContext myContext) { - final HeaderElementIterator it = new BasicHeaderElementIterator(myResponse.headerIterator(HTTP.CONN_KEEP_ALIVE)); - while (it.hasNext()) { - final HeaderElement he = it.nextElement(); - final String param = he.getName(); - final String value = he.getValue(); - if ((value != null) && param.equalsIgnoreCase("timeout")) { - return Long.parseLong(value) * 1000; + public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context) { + Args.notNull(response, "HTTP response"); + final Iterator it = MessageSupport.iterate(response, HeaderElements.KEEP_ALIVE); + final HeaderElement he = it.next(); + final String param = he.getName(); + final String value = he.getValue(); + if (value != null && param.equalsIgnoreCase("timeout")) { + try { + return TimeValue.ofSeconds(Long.parseLong(value)); + } catch (final NumberFormatException ignore) { } } - final HttpHost target = (HttpHost) myContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); - if ("localhost".equalsIgnoreCase(target.getHostName())) { - return 10 * 1000; - } else { - return 5 * 1000; - } + return TimeValue.ofSeconds(5); } }; @@ -144,42 +157,38 @@ public class HttpClientConnectionManagementLiveTest { .setKeepAliveStrategy(myStrategy) .setConnectionManager(connManager) .build(); + connManager.close(); } - // Example 6.1. BasicHttpClientConnectionManager Connection Reuse + //Example 6.1. BasicHttpClientConnectionManager Connection Reuse @Test - public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws IOException, HttpException, InterruptedException, ExecutionException { - BasicHttpClientConnectionManager basicConnManager = new BasicHttpClientConnectionManager(); - HttpClientContext context = HttpClientContext.create(); - - // low level + public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws InterruptedException, ExecutionException, TimeoutException, IOException, URISyntaxException { + BasicHttpClientConnectionManager connMgr = new BasicHttpClientConnectionManager(); HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); - ConnectionRequest connRequest = basicConnManager.requestConnection(route, null); - HttpClientConnection conn = connRequest.get(10, TimeUnit.SECONDS); - basicConnManager.connect(conn, route, 1000, context); - basicConnManager.routeComplete(conn, route, context); + final HttpContext context = new BasicHttpContext(); - HttpRequestExecutor exeRequest = new HttpRequestExecutor(); - context.setTargetHost((new HttpHost("www.baeldung.com", 80))); - HttpGet get = new HttpGet("http://www.baeldung.com"); - exeRequest.execute(get, conn, context); + final LeaseRequest connRequest = connMgr.lease("some-id", route, null); + final ConnectionEndpoint endpoint = connRequest.get(Timeout.ZERO_MILLISECONDS); + connMgr.connect(endpoint, Timeout.ZERO_MILLISECONDS, context); - basicConnManager.releaseConnection(conn, null, 1, TimeUnit.SECONDS); + connMgr.release(endpoint, null, TimeValue.ZERO_MILLISECONDS); - // high level CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(basicConnManager) + .setConnectionManager(connMgr) .build(); - client.execute(get); + HttpGet httpGet = new HttpGet("https://www.example.com"); + client.execute(httpGet, context, response -> response); + client.close(); + connMgr.close(); } // Example 6.2. PoolingHttpClientConnectionManager: Re-Using Connections with Threads @Test - public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException { - HttpGet get = new HttpGet("http://echo.200please.com"); + public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException, IOException { + HttpGet get = new HttpGet("http://www.baeldung.com"); PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - connManager.setDefaultMaxPerRoute(5); - connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(6); + connManager.setMaxTotal(6); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) .build(); @@ -193,48 +202,71 @@ public class HttpClientConnectionManagementLiveTest { for (MultiHttpClientConnThread thread : threads) { thread.join(1000); } + client.close(); + connManager.close(); } // Example 7.1. Setting Socket Timeout to 5 Seconds @Test - public final void whenConfiguringTimeOut_thenNoExceptions() { - HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); - try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { - connManager.setSocketConfig(route.getTargetHost(), SocketConfig.custom() - .setSoTimeout(5000) - .build()); - assertTrue(connManager.getSocketConfig(route.getTargetHost()) - .getSoTimeout() == 5000); - } + public final void whenConfiguringTimeOut_thenNoExceptions() throws ExecutionException, InterruptedException, TimeoutException, IOException { + final HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + final HttpContext context = new BasicHttpContext(); + final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + + final ConnectionConfig connConfig = ConnectionConfig.custom() + .setSocketTimeout(5, TimeUnit.SECONDS) + .build(); + + connManager.setDefaultConnectionConfig(connConfig); + + final LeaseRequest leaseRequest = connManager.lease("id1", route, null); + final ConnectionEndpoint endpoint = leaseRequest.get(Timeout.ZERO_MILLISECONDS); + connManager.connect(endpoint, null, context); + connManager.close(); } // Example 8.1. Setting the HttpClient to Check for Stale Connections @Test - public final void whenHttpClientChecksStaleConns_thenNoExceptions() { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - HttpClients.custom() - .setDefaultRequestConfig(RequestConfig.custom() - .setStaleConnectionCheckEnabled(true) - .build()) + public final void whenEvictIdealConn_thenNoExceptions() throws InterruptedException, IOException { + final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setMaxTotal(100); + try (final CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(connManager) - .build(); - } + .evictExpiredConnections() + .evictIdleConnections(TimeValue.ofSeconds(2)) + .build()) { + // create an array of URIs to perform GETs on + final String[] urisToGet = { "http://hc.apache.org/", "http://hc.apache.org/httpcomponents-core-ga/"}; - // Example 8.2. Using a Stale Connection Monitor Thread - @Test - public final void whenCustomizedIdleConnMonitor_thenNoExceptions() throws InterruptedException { - PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); - HttpClients.custom() - .setConnectionManager(connManager) - .build(); - IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager); - staleMonitor.start(); - staleMonitor.join(1000); + for (final String requestURI : urisToGet) { + final HttpGet request = new HttpGet(requestURI); + + System.out.println("Executing request " + request.getMethod() + " " + request.getRequestUri()); + + httpclient.execute(request, response -> { + System.out.println("----------------------------------------"); + System.out.println(request + "->" + new StatusLine(response)); + EntityUtils.consume(response.getEntity()); + return null; + }); + } + + final PoolStats stats1 = connManager.getTotalStats(); + System.out.println("Connections kept alive: " + stats1.getAvailable()); + + // Sleep 10 sec and let the connection evict or do its job + Thread.sleep(4000); + + final PoolStats stats2 = connManager.getTotalStats(); + System.out.println("Connections kept alive: " + stats2.getAvailable()); + + connManager.close(); + } } // Example 9.1. Closing Connection and Releasing Resources - @Test(expected = IllegalStateException.class) - public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws InterruptedException, ExecutionException, IOException, HttpException { + @Test + public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws IOException { PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); CloseableHttpClient client = HttpClients.custom() .setConnectionManager(connManager) @@ -246,16 +278,11 @@ public class HttpClientConnectionManagementLiveTest { response.close(); client.close(); connManager.close(); - connManager.shutdown(); - - client.execute(get); - - assertTrue(response.getEntity() == null); } @Test // Example 3.2. TESTER VERSION - public final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException { + public final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException, IOException { HttpGet get1 = new HttpGet("https://www.baeldung.com"); HttpGet get2 = new HttpGet("https://www.google.com"); @@ -273,77 +300,11 @@ public class HttpClientConnectionManagementLiveTest { thread2.start(); thread1.join(); thread2.join(1000); - assertTrue(poolingConnManager.getTotalStats() + Assert.assertTrue(poolingConnManager.getTotalStats() .getLeased() == 2); - } - @Test - // Example 4.2 Tester Version - public final void whenExecutingSameRequestsInDifferentThreads_thenUseDefaultConnLimit() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); - thread1.start(); - thread2.start(); - thread3.start(); - thread1.join(10000); - thread2.join(10000); - thread3.join(10000); - } - - @Test - // 6.2 TESTER VERSION - public final void whenConnectionsNeededGreaterThanMaxTotal_thenReuseConnections() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - poolingConnManager.setDefaultMaxPerRoute(5); - poolingConnManager.setMaxTotal(5); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; - int countConnMade = 0; - for (int i = 0; i < threads.length; i++) { - threads[i] = new MultiHttpClientConnThread(client, new HttpGet("http://www.baeldung.com/"), poolingConnManager); - } - for (final MultiHttpClientConnThread thread : threads) { - thread.start(); - } - for (final MultiHttpClientConnThread thread : threads) { - thread.join(10000); - countConnMade++; - if (countConnMade == 0) { - assertTrue(thread.getLeasedConn() == 5); - } - } - } - - @Test - @Ignore("Very Long Running") - // 8.2 TESTER VERSION - public final void whenCustomizedIdleConnMonitor_thenEliminateIdleConns() throws InterruptedException { - PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); - CloseableHttpClient client = HttpClients.custom() - .setConnectionManager(poolingConnManager) - .build(); - final IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(poolingConnManager); - final HttpGet get = new HttpGet("http://google.com"); - final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); - staleMonitor.start(); - thread1.start(); - thread1.join(); - thread2.start(); - thread2.join(); - thread3.start(); - assertTrue(poolingConnManager.getTotalStats() - .getAvailable() == 1); - thread3.join(32000); - assertTrue(poolingConnManager.getTotalStats() - .getAvailable() == 0); + client1.close(); + client2.close(); + poolingConnManager.close(); } } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java index acadd1f240..16bb49123a 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/MultiHttpClientConnThread.java @@ -2,12 +2,12 @@ package com.baeldung.httpclient.conn; import java.io.IOException; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.util.EntityUtils; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.io.entity.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,22 +45,21 @@ public class MultiHttpClientConnThread extends Thread { try { logger.debug("Thread Running: " + getName()); - logger.debug("Thread Running: " + getName()); if (connManager != null) { logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); } - final HttpResponse response = client.execute(get); + HttpEntity entity = client.execute(get).getEntity(); if (connManager != null) { leasedConn = connManager.getTotalStats().getLeased(); logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); } + EntityUtils.consume(entity); - EntityUtils.consume(response.getEntity()); } catch (final IOException ex) { logger.error("", ex); } diff --git a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java index a50858672e..6703d6880c 100644 --- a/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java +++ b/apache-httpclient/src/test/java/com/baeldung/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java @@ -2,10 +2,9 @@ package com.baeldung.httpclient.conn; import java.io.IOException; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java b/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java new file mode 100644 index 0000000000..c58763b1c0 --- /dev/null +++ b/apache-httpclient4/src/main/java/com/baeldung/tlsversion/ClientTlsVersionExamples.java @@ -0,0 +1,64 @@ +package com.baeldung.tlsversion; + +import javax.net.ssl.SSLSocket; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +public class ClientTlsVersionExamples { + + public static CloseableHttpClient setViaSocketFactory() { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + SSLContexts.createDefault(), + new String[] { "TLSv1.2", "TLSv1.3" }, + null, + SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } + + public static CloseableHttpClient setTlsVersionPerConnection() { + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) { + + @Override + protected void prepareSocket(SSLSocket socket) { + String hostname = socket.getInetAddress().getHostName(); + if (hostname.endsWith("internal.system.com")) { + socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }); + } else { + socket.setEnabledProtocols(new String[] { "TLSv1.3" }); + } + } + }; + + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } + + // To configure the TLS versions for the client, set the https.protocols system property during runtime. + // For example: java -Dhttps.protocols=TLSv1.1,TLSv1.2,TLSv1.3 -jar webClient.jar + public static CloseableHttpClient setViaSystemProperties() { + return HttpClients.createSystem(); + // Alternatively: + // return HttpClients.custom().useSystemProperties().build(); + } + + public static void main(String[] args) throws IOException { + // Alternatively: + // CloseableHttpClient httpClient = setTlsVersionPerConnection(); + // CloseableHttpClient httpClient = setViaSystemProperties(); + try (CloseableHttpClient httpClient = setViaSocketFactory(); + CloseableHttpResponse response = httpClient.execute(new HttpGet("https://httpbin.org/"))) { + + HttpEntity entity = response.getEntity(); + EntityUtils.consume(entity); + } + } +} \ No newline at end of file diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java new file mode 100644 index 0000000000..c894d72af0 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/HttpClientConnectionManagementLiveTest.java @@ -0,0 +1,349 @@ +package com.baeldung.httpclient.httpclient.conn; + +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.apache.http.HeaderElement; +import org.apache.http.HeaderElementIterator; +import org.apache.http.HttpClientConnection; +import org.apache.http.HttpException; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.conn.ConnectionPoolTimeoutException; +import org.apache.http.conn.ConnectionRequest; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeaderElementIterator; +import org.apache.http.protocol.HTTP; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpCoreContext; +import org.apache.http.protocol.HttpRequestExecutor; +import org.apache.http.util.EntityUtils; +import org.junit.Ignore; +import org.junit.Test; + +public class HttpClientConnectionManagementLiveTest { + + // Example 2.1. Getting a Connection Request for a Low Level Connection (HttpClientConnection) + @Test + public final void whenLowLevelConnectionIsEstablished_thenNoExceptions() throws ConnectionPoolTimeoutException, InterruptedException, ExecutionException { + try (BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager()) { + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + final ConnectionRequest connRequest = connManager.requestConnection(route, null); + assertNotNull(connRequest.get(1000, TimeUnit.SECONDS)); + } + } + + // Example 3.1. Setting the PoolingHttpClientConnectionManager on a HttpClient + @Test + public final void whenPollingConnectionManagerIsConfiguredOnHttpClient_thenNoExceptions() throws ClientProtocolException, IOException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + client.execute(new HttpGet("https://www.baeldung.com")); + + assertTrue(poolingConnManager.getTotalStats() + .getLeased() == 1); + } + + // Example 3.2. Using Two HttpClients to Connect to One Target Host Each + @Test + public final void whenTwoConnectionsForTwoRequests_thenNoExceptions() throws InterruptedException { + HttpGet get1 = new HttpGet("https://www.baeldung.com"); + HttpGet get2 = new HttpGet("https://www.google.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client1 = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + CloseableHttpClient client2 = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client1, get1); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client2, get2); + thread1.start(); + thread2.start(); + thread1.join(); + thread2.join(); + + assertTrue(connManager.getTotalStats() + .getLeased() == 0); + } + + // Example 4.1. Increasing the Number of Connections that Can be Open and Managed Beyond the default Limits + @Test + public final void whenIncreasingConnectionPool_thenNoEceptions() { + try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(4); + HttpHost host = new HttpHost("www.baeldung.com", 80); + connManager.setMaxPerRoute(new HttpRoute(host), 5); + } + } + + // Example 4.2. Using Threads to Execute Connections + @Test + public final void whenExecutingSameRequestsInDifferentThreads_thenExecuteReuqest() throws InterruptedException { + HttpGet get = new HttpGet("http://www.baeldung.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + MultiHttpClientConnThread thread1 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread2 = new MultiHttpClientConnThread(client, get); + MultiHttpClientConnThread thread3 = new MultiHttpClientConnThread(client, get); + thread1.start(); + thread2.start(); + thread3.start(); + thread1.join(); + thread2.join(); + thread3.join(); + } + + // Example 5.1. A Custom Keep Alive Strategy + @Test + public final void whenCustomizingKeepAliveStrategy_thenNoExceptions() { + final ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() { + @Override + public long getKeepAliveDuration(final HttpResponse myResponse, final HttpContext myContext) { + final HeaderElementIterator it = new BasicHeaderElementIterator(myResponse.headerIterator(HTTP.CONN_KEEP_ALIVE)); + while (it.hasNext()) { + final HeaderElement he = it.nextElement(); + final String param = he.getName(); + final String value = he.getValue(); + if ((value != null) && param.equalsIgnoreCase("timeout")) { + return Long.parseLong(value) * 1000; + } + } + final HttpHost target = (HttpHost) myContext.getAttribute(HttpCoreContext.HTTP_TARGET_HOST); + if ("localhost".equalsIgnoreCase(target.getHostName())) { + return 10 * 1000; + } else { + return 5 * 1000; + } + } + + }; + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setKeepAliveStrategy(myStrategy) + .setConnectionManager(connManager) + .build(); + } + + // Example 6.1. BasicHttpClientConnectionManager Connection Reuse + @Test + public final void givenBasicHttpClientConnManager_whenConnectionReuse_thenNoExceptions() throws IOException, HttpException, InterruptedException, ExecutionException { + BasicHttpClientConnectionManager basicConnManager = new BasicHttpClientConnectionManager(); + HttpClientContext context = HttpClientContext.create(); + + // low level + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 443)); + ConnectionRequest connRequest = basicConnManager.requestConnection(route, null); + HttpClientConnection conn = connRequest.get(10, TimeUnit.SECONDS); + basicConnManager.connect(conn, route, 1000, context); + basicConnManager.routeComplete(conn, route, context); + + HttpRequestExecutor exeRequest = new HttpRequestExecutor(); + context.setTargetHost((new HttpHost("www.baeldung.com", 80))); + HttpGet get = new HttpGet("http://www.baeldung.com"); + exeRequest.execute(get, conn, context); + + basicConnManager.releaseConnection(conn, null, 1, TimeUnit.SECONDS); + + // high level + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(basicConnManager) + .build(); + client.execute(get); + } + + // Example 6.2. PoolingHttpClientConnectionManager: Re-Using Connections with Threads + @Test + public final void whenConnectionsNeededGreaterThanMaxTotal_thenLeaseMasTotalandReuse() throws InterruptedException { + HttpGet get = new HttpGet("http://echo.200please.com"); + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + connManager.setDefaultMaxPerRoute(5); + connManager.setMaxTotal(5); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; + for (int i = 0; i < threads.length; i++) { + threads[i] = new MultiHttpClientConnThread(client, get, connManager); + } + for (MultiHttpClientConnThread thread : threads) { + thread.start(); + } + for (MultiHttpClientConnThread thread : threads) { + thread.join(1000); + } + } + + // Example 7.1. Setting Socket Timeout to 5 Seconds + @Test + public final void whenConfiguringTimeOut_thenNoExceptions() { + HttpRoute route = new HttpRoute(new HttpHost("www.baeldung.com", 80)); + try (PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager()) { + connManager.setSocketConfig(route.getTargetHost(), SocketConfig.custom() + .setSoTimeout(5000) + .build()); + assertTrue(connManager.getSocketConfig(route.getTargetHost()) + .getSoTimeout() == 5000); + } + } + + // Example 8.1. Setting the HttpClient to Check for Stale Connections + @Test + public final void whenHttpClientChecksStaleConns_thenNoExceptions() { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom() + .setStaleConnectionCheckEnabled(true) + .build()) + .setConnectionManager(connManager) + .build(); + } + + // Example 8.2. Using a Stale Connection Monitor Thread + @Test + public final void whenCustomizedIdleConnMonitor_thenNoExceptions() throws InterruptedException { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + HttpClients.custom() + .setConnectionManager(connManager) + .build(); + IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(connManager); + staleMonitor.start(); + staleMonitor.join(1000); + } + + // Example 9.1. Closing Connection and Releasing Resources + @Test(expected = IllegalStateException.class) + public final void whenClosingConnectionsandManager_thenCloseWithNoExceptions1() throws InterruptedException, ExecutionException, IOException, HttpException { + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(connManager) + .build(); + final HttpGet get = new HttpGet("http://google.com"); + CloseableHttpResponse response = client.execute(get); + + EntityUtils.consume(response.getEntity()); + response.close(); + client.close(); + connManager.close(); + connManager.shutdown(); + + client.execute(get); + + assertTrue(response.getEntity() == null); + } + + @Test + // Example 3.2. TESTER VERSION + public final void whenTwoConnectionsForTwoRequests_thenTwoConnectionsAreLeased() throws InterruptedException { + HttpGet get1 = new HttpGet("https://www.baeldung.com"); + HttpGet get2 = new HttpGet("https://www.google.com"); + + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + final CloseableHttpClient client1 = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final CloseableHttpClient client2 = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client1, get1, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client2, get2, poolingConnManager); + thread1.start(); + thread2.start(); + thread1.join(); + thread2.join(1000); + assertTrue(poolingConnManager.getTotalStats() + .getLeased() == 2); + } + + @Test + // Example 4.2 Tester Version + public final void whenExecutingSameRequestsInDifferentThreads_thenUseDefaultConnLimit() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, new HttpGet("http://www.google.com"), poolingConnManager); + thread1.start(); + thread2.start(); + thread3.start(); + thread1.join(10000); + thread2.join(10000); + thread3.join(10000); + } + + @Test + // 6.2 TESTER VERSION + public final void whenConnectionsNeededGreaterThanMaxTotal_thenReuseConnections() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + poolingConnManager.setDefaultMaxPerRoute(5); + poolingConnManager.setMaxTotal(5); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final MultiHttpClientConnThread[] threads = new MultiHttpClientConnThread[10]; + int countConnMade = 0; + for (int i = 0; i < threads.length; i++) { + threads[i] = new MultiHttpClientConnThread(client, new HttpGet("http://www.baeldung.com/"), poolingConnManager); + } + for (final MultiHttpClientConnThread thread : threads) { + thread.start(); + } + for (final MultiHttpClientConnThread thread : threads) { + thread.join(10000); + countConnMade++; + if (countConnMade == 0) { + assertTrue(thread.getLeasedConn() == 5); + } + } + } + + @Test + @Ignore("Very Long Running") + // 8.2 TESTER VERSION + public final void whenCustomizedIdleConnMonitor_thenEliminateIdleConns() throws InterruptedException { + PoolingHttpClientConnectionManager poolingConnManager = new PoolingHttpClientConnectionManager(); + CloseableHttpClient client = HttpClients.custom() + .setConnectionManager(poolingConnManager) + .build(); + final IdleConnectionMonitorThread staleMonitor = new IdleConnectionMonitorThread(poolingConnManager); + final HttpGet get = new HttpGet("http://google.com"); + final TesterVersion_MultiHttpClientConnThread thread1 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread2 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + final TesterVersion_MultiHttpClientConnThread thread3 = new TesterVersion_MultiHttpClientConnThread(client, get, poolingConnManager); + staleMonitor.start(); + thread1.start(); + thread1.join(); + thread2.start(); + thread2.join(); + thread3.start(); + assertTrue(poolingConnManager.getTotalStats() + .getAvailable() == 1); + thread3.join(32000); + assertTrue(poolingConnManager.getTotalStats() + .getAvailable() == 0); + } +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java new file mode 100644 index 0000000000..4bf97e4fa6 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/IdleConnectionMonitorThread.java @@ -0,0 +1,41 @@ +package com.baeldung.httpclient.httpclient.conn; + +import java.util.concurrent.TimeUnit; + +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; + +public class IdleConnectionMonitorThread extends Thread { + private final HttpClientConnectionManager connMgr; + private volatile boolean shutdown; + + IdleConnectionMonitorThread(final PoolingHttpClientConnectionManager connMgr) { + super(); + this.connMgr = connMgr; + } + + // API + + @Override + public final void run() { + try { + while (!shutdown) { + synchronized (this) { + wait(1000); + connMgr.closeExpiredConnections(); + connMgr.closeIdleConnections(30, TimeUnit.SECONDS); + } + } + } catch (final InterruptedException ex) { + shutdown(); + } + } + + private void shutdown() { + shutdown = true; + synchronized (this) { + notifyAll(); + } + } + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java new file mode 100644 index 0000000000..4183094621 --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/MultiHttpClientConnThread.java @@ -0,0 +1,69 @@ +package com.baeldung.httpclient.httpclient.conn; + +import java.io.IOException; + +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MultiHttpClientConnThread extends Thread { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final CloseableHttpClient client; + private final HttpGet get; + + private PoolingHttpClientConnectionManager connManager; + private int leasedConn; + + MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get, final PoolingHttpClientConnectionManager connManager) { + this.client = client; + this.get = get; + this.connManager = connManager; + leasedConn = 0; + } + + MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get) { + this.client = client; + this.get = get; + } + + // API + + final int getLeasedConn() { + return leasedConn; + } + + // + + @Override + public final void run() { + try { + logger.debug("Thread Running: " + getName()); + + logger.debug("Thread Running: " + getName()); + + if (connManager != null) { + logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); + } + + final HttpResponse response = client.execute(get); + + if (connManager != null) { + leasedConn = connManager.getTotalStats().getLeased(); + logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); + } + + EntityUtils.consume(response.getEntity()); + } catch (final IOException ex) { + logger.error("", ex); + } + } + +} diff --git a/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java new file mode 100644 index 0000000000..5e2710342d --- /dev/null +++ b/apache-httpclient4/src/test/java/com/baeldung/httpclient/httpclient/conn/TesterVersion_MultiHttpClientConnThread.java @@ -0,0 +1,46 @@ +package com.baeldung.httpclient.httpclient.conn; + +import java.io.IOException; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +public class TesterVersion_MultiHttpClientConnThread extends Thread { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final CloseableHttpClient client; + private final HttpGet get; + private PoolingHttpClientConnectionManager connManager; + + TesterVersion_MultiHttpClientConnThread(final CloseableHttpClient client, final HttpGet get, final PoolingHttpClientConnectionManager connManager) { + this.client = client; + this.get = get; + this.connManager = Preconditions.checkNotNull(connManager); + } + + // + + @Override + public final void run() { + try { + logger.debug("Thread Running: " + getName()); + + logger.info("Before - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("Before - Available Connections = " + connManager.getTotalStats().getAvailable()); + + client.execute(get); + + logger.info("After - Leased Connections = " + connManager.getTotalStats().getLeased()); + logger.info("After - Available Connections = " + connManager.getTotalStats().getAvailable()); + } catch (final IOException ex) { + logger.error("", ex); + } + } + +} diff --git a/apache-kafka-2/README.md b/apache-kafka-2/README.md index 81239d4a7b..dc675a0811 100644 --- a/apache-kafka-2/README.md +++ b/apache-kafka-2/README.md @@ -12,3 +12,4 @@ You can build the project from the command line using: *mvn clean install*, or i - [Is a Key Required as Part of Sending Messages to Kafka?](https://www.baeldung.com/java-kafka-message-key) - [Read Data From the Beginning Using Kafka Consumer API](https://www.baeldung.com/java-kafka-consumer-api-read) - [Get Partition Count for a Topic in Kafka](https://www.baeldung.com/java-kafka-partition-count-topic) +- [bootstrap-server in Kafka Configuration](https://www.baeldung.com/java-kafka-bootstrap-server) diff --git a/apache-poi-2/README.md b/apache-poi-2/README.md index 0132147201..65641e7c37 100644 --- a/apache-poi-2/README.md +++ b/apache-poi-2/README.md @@ -13,4 +13,5 @@ This module contains articles about Apache POI. - [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas) - [Set the Date Format Using Apache POI](https://www.baeldung.com/java-apache-poi-date-format) - [Replacing Variables in a Document Template with Java](https://www.baeldung.com/java-replace-pattern-word-document-doc-docx) +- [Lock Header Rows With Apache POI](https://www.baeldung.com/java-apache-poi-lock-header-rows) - More articles: [[<-- prev]](../apache-poi) diff --git a/aws-modules/aws-s3-update-object/pom.xml b/aws-modules/aws-s3-update-object/pom.xml index b44cdb8c6a..574a63977b 100644 --- a/aws-modules/aws-s3-update-object/pom.xml +++ b/aws-modules/aws-s3-update-object/pom.xml @@ -2,26 +2,21 @@ 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.1.2 - - - com.baeldung aws-s3-update-object 0.0.1-SNAPSHOT aws-s3-update-object Project demonstrating overwriting of S3 objects - - 17 - + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + org.springframework.boot spring-boot-starter-web - org.springframework.boot spring-boot-starter-test @@ -30,10 +25,9 @@ com.amazonaws aws-java-sdk - 1.12.523 + ${aws-java-sdk-version} - @@ -42,5 +36,7 @@ - + + 1.12.523 + diff --git a/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/service/FileService.java b/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/service/FileService.java index 8f3458d060..23eaad7913 100644 --- a/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/service/FileService.java +++ b/aws-modules/aws-s3-update-object/src/main/java/com/baeldung/awss3updateobject/service/FileService.java @@ -7,13 +7,13 @@ import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.*; -import jakarta.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; +import javax.annotation.PostConstruct; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; diff --git a/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/controller/FileControllerUnitTest.java b/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/controller/FileControllerUnitTest.java index ec2385f62b..823391c139 100644 --- a/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/controller/FileControllerUnitTest.java +++ b/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/controller/FileControllerUnitTest.java @@ -11,6 +11,7 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.multipart.MultipartFile; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -34,28 +35,28 @@ public class FileControllerUnitTest { @Test public void givenValidMultipartFile_whenUploadedViaEndpoint_thenCorrectPathIsReturned() throws Exception { - MockMultipartFile multipartFile = new MockMultipartFile("multipartFile", "test.txt", - "text/plain", "test data".getBytes()); + MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain", "sample file content".getBytes()); + String expectedResult = "File Uploaded Successfully"; - when(fileService.uploadFile(any(MultipartFile.class))).thenReturn("/documents/test.txt"); + when(fileService.uploadFile(multipartFile)).thenReturn(expectedResult); - mockMvc.perform(multipart("/file/upload").file(multipartFile)) + mockMvc.perform(multipart("/api/v1/file/upload").file(multipartFile)) .andExpect(status().isOk()) - .andExpect(content().string("/documents/test.txt")); + .andExpect(content().string(expectedResult)); } @Test public void givenValidMultipartFileAndExistingPath_whenUpdatedViaEndpoint_thenSamePathIsReturned() throws Exception { - MockMultipartFile multipartFile = new MockMultipartFile("multipartFile", "test.txt", - "text/plain", "test update data".getBytes()); - String existingFilePath = "/documents/existingFile.txt"; + MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", "text/plain", "updated file content".getBytes()); + String filePath = "some/path/to/file"; + String expectedResult = "File Updated Successfully"; - when(fileService.updateFile(any(MultipartFile.class), eq(existingFilePath))).thenReturn(existingFilePath); + when(fileService.updateFile(multipartFile, filePath)).thenReturn(expectedResult); - mockMvc.perform(multipart("/file/update") + mockMvc.perform(multipart("/api/v1/file/update") .file(multipartFile) - .param("exitingFilePath", existingFilePath)) + .param("filePath", filePath)) .andExpect(status().isOk()) - .andExpect(content().string(existingFilePath)); + .andExpect(content().string(expectedResult)); } } \ No newline at end of file diff --git a/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/service/FileServiceUnitTest.java b/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/service/FileServiceUnitTest.java index 3ccd41820e..90ed77b148 100644 --- a/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/service/FileServiceUnitTest.java +++ b/aws-modules/aws-s3-update-object/src/test/java/com/baeldung/awss3updateobject/service/FileServiceUnitTest.java @@ -41,6 +41,7 @@ public class FileServiceUnitTest { @Test public void givenValidFile_whenUploaded_thenKeyMatchesDocumentPath() throws Exception { when(multipartFile.getName()).thenReturn("testFile"); + when(multipartFile.getOriginalFilename()).thenReturn("testFile"); when(multipartFile.getContentType()).thenReturn("application/pdf"); when(multipartFile.getSize()).thenReturn(1024L); when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class)); @@ -57,6 +58,7 @@ public class FileServiceUnitTest { @Test public void givenValidFile_whenUploadFailsDueToNoBucket_thenExceptionIsThrown() throws Exception { when(multipartFile.getName()).thenReturn("testFile"); + when(multipartFile.getOriginalFilename()).thenReturn("testFile"); when(multipartFile.getContentType()).thenReturn("application/pdf"); when(multipartFile.getSize()).thenReturn(1024L); when(multipartFile.getInputStream()).thenReturn(mock(InputStream.class)); diff --git a/aws-modules/pom.xml b/aws-modules/pom.xml index 02473815b5..b94faafa86 100644 --- a/aws-modules/pom.xml +++ b/aws-modules/pom.xml @@ -19,6 +19,7 @@ aws-miscellaneous aws-reactive aws-s3 + aws-s3-update-object diff --git a/core-java-modules/core-java-arrays-convert/README.md b/core-java-modules/core-java-arrays-convert/README.md index b68773463d..dcaaaac12e 100644 --- a/core-java-modules/core-java-arrays-convert/README.md +++ b/core-java-modules/core-java-arrays-convert/README.md @@ -9,3 +9,4 @@ This module contains articles about arrays conversion in Java - [Converting a String Array Into an int Array in Java](https://www.baeldung.com/java-convert-string-array-to-int-array) - [Convert Java Array to Iterable](https://www.baeldung.com/java-array-convert-to-iterable) - [Converting an int[] to HashSet in Java](https://www.baeldung.com/java-converting-int-array-to-hashset) +- [Convert an ArrayList of String to a String Array in Java](https://www.baeldung.com/java-convert-string-arraylist-array) diff --git a/core-java-modules/core-java-collections-conversions-2/README.md b/core-java-modules/core-java-collections-conversions-2/README.md index fe17af0a7a..efd01c46ee 100644 --- a/core-java-modules/core-java-collections-conversions-2/README.md +++ b/core-java-modules/core-java-collections-conversions-2/README.md @@ -12,4 +12,5 @@ This module contains articles about conversions among Collection types and array - [Convert a List of Integers to a List of Strings](https://www.baeldung.com/java-convert-list-integers-to-list-strings) - [Combining Two Lists Into a Map in Java](https://www.baeldung.com/java-combine-two-lists-into-map) - [Convert a List of Strings to a List of Integers](https://www.baeldung.com/java-convert-list-strings-to-integers) +- [Convert List to Long[] Array in Java](https://www.baeldung.com/java-convert-list-object-to-long-array) - More articles: [[<-- prev]](../core-java-collections-conversions) diff --git a/core-java-modules/core-java-collections-maps-6/README.md b/core-java-modules/core-java-collections-maps-6/README.md index bebcdea82b..d4f432bdcb 100644 --- a/core-java-modules/core-java-collections-maps-6/README.md +++ b/core-java-modules/core-java-collections-maps-6/README.md @@ -8,3 +8,4 @@ - [How to Modify a Key in a HashMap?](https://www.baeldung.com/java-hashmap-modify-key) - [Converting String or String Array to Map in Java](https://www.baeldung.com/java-convert-string-to-map) - [Remove Duplicate Values From HashMap in Java](https://www.baeldung.com/java-hashmap-delete-duplicates) +- [Sorting Java Map in Descending Order](https://www.baeldung.com/java-sort-map-descending) diff --git a/core-java-modules/core-java-conditionals/README.md b/core-java-modules/core-java-conditionals/README.md index ae5694c3ba..828f3484f1 100644 --- a/core-java-modules/core-java-conditionals/README.md +++ b/core-java-modules/core-java-conditionals/README.md @@ -3,3 +3,4 @@ This module contains articles about Java Conditionals. ### Relevant articles: +- [Guide to the yield Keyword in Java](https://www.baeldung.com/java-yield-switch) diff --git a/core-java-modules/core-java-datetime-conversion/README.md b/core-java-modules/core-java-datetime-conversion/README.md index 11e4348838..98c2d6694b 100644 --- a/core-java-modules/core-java-datetime-conversion/README.md +++ b/core-java-modules/core-java-datetime-conversion/README.md @@ -8,3 +8,4 @@ This module contains articles about converting between Java date and time object - [Convert Date to LocalDate or LocalDateTime and Back](http://www.baeldung.com/java-date-to-localdate-and-localdatetime) - [Convert Between java.time.Instant and java.sql.Timestamp](https://www.baeldung.com/java-time-instant-to-java-sql-timestamp) - [Convert Between LocalDateTime and ZonedDateTime](https://www.baeldung.com/java-localdatetime-zoneddatetime) +- [Conversion From 12-Hour Time to 24-Hour Time in Java](https://www.baeldung.com/java-convert-time-format) diff --git a/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java new file mode 100644 index 0000000000..ae783fa8bd --- /dev/null +++ b/core-java-modules/core-java-exceptions-2/src/main/java/com/baeldung/socketexception/SslServer.java @@ -0,0 +1,32 @@ +package com.baeldung.socketexception; + +import java.io.IOException; + +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + +public class SslServer { + + public static void createSSLSocketWithEnabledProtocols(SSLServerSocketFactory socketFactory, int port, String[] enabledProtocols) { + SSLServerSocket serverSocket = null; + + try { + serverSocket = (SSLServerSocket) socketFactory.createServerSocket(port); + // Set the enabled protocols + serverSocket.setEnabledProtocols(enabledProtocols); + System.out.println("Server is running on port " + port); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java index 08b21c6299..197046d273 100644 --- a/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java +++ b/core-java-modules/core-java-exceptions-2/src/test/java/com/baeldung/socketexception/SocketExceptionHandlingUnitTest.java @@ -1,25 +1,33 @@ package com.baeldung.socketexception; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import java.io.IOException; import java.net.SocketException; import java.util.concurrent.Executors; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + import org.junit.BeforeClass; import org.junit.Test; public class SocketExceptionHandlingUnitTest { + private static final int PORT = 6699; @BeforeClass public static void runServer() throws IOException, InterruptedException { Executors.newSingleThreadExecutor() - .submit(() -> new SocketServer().start(6699)); + .submit(() -> new SocketServer().start(PORT)); Thread.sleep(100); } @Test public void givenRunningServer_whenConnectToClosedSocket_thenHandleException() throws IOException { SocketClient client = new SocketClient(); - client.startConnection("127.0.0.1", 6699); + client.startConnection("127.0.0.1", PORT); try { client.sendMessage("hi"); client.sendMessage("hi again"); @@ -28,4 +36,22 @@ public class SocketExceptionHandlingUnitTest { } } + @Test + public void givenRunningServer_whenConnectToSocket_thenHandleConnectionResetException() throws IOException { + // Enable multiple SSL/TLS protocols + String[] enabledProtocols = { "TLSv1.2", "TLSv1.3", "TLSv1.1", "TLSv1", "SSLv3", "SSLv3" }; + SSLServerSocketFactory mockFactory = mock(SSLServerSocketFactory.class); + SSLServerSocket mockServerSocket = mock(SSLServerSocket.class); + + // Set up the mock factory to return the mock server socket + when(mockFactory.createServerSocket(PORT)).thenReturn(mockServerSocket); + + // Call the method being tested + SslServer.createSSLSocketWithEnabledProtocols(mockFactory, PORT, enabledProtocols); + + // Verify that setEnabledProtocols and close were called + verify(mockServerSocket).setEnabledProtocols(enabledProtocols); + verify(mockServerSocket).close(); + } + } diff --git a/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java new file mode 100644 index 0000000000..5b203db515 --- /dev/null +++ b/core-java-modules/core-java-lang-6/src/main/java/com/baeldung/randominset/RandomInSetUtil.java @@ -0,0 +1,50 @@ +package com.baeldung.randominset; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public class RandomInSetUtil { + + public static T getByRandomClass(Set set) { + if (set == null || set.isEmpty()) { + throw new IllegalArgumentException("The Set cannot be empty."); + } + int randomIndex = new Random().nextInt(set.size()); + int i = 0; + for (T element : set) { + if (i == randomIndex) { + return element; + } + i++; + } + throw new IllegalStateException("Something went wrong while picking a random element."); + } + + public static T getByThreadLocalRandom(Set set) { + if (set == null || set.isEmpty()) { + throw new IllegalArgumentException("The Set cannot be empty."); + } + int randomIndex = ThreadLocalRandom.current().nextInt(set.size()); + int i = 0; + for (T element : set) { + if (i == randomIndex) { + return element; + } + i++; + } + throw new IllegalStateException("Something went wrong while picking a random element."); + } + + public static void main(String[] args) { + Set animals = new HashSet<>(); + animals.add("Lion"); + animals.add("Elephant"); + animals.add("Giraffe"); + + String randomAnimal = getByThreadLocalRandom(animals); + System.out.println("Randomly picked animal: " + randomAnimal); + } + +} diff --git a/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/README.md b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/README.md new file mode 100644 index 0000000000..b2f7ece88a --- /dev/null +++ b/core-java-modules/core-java-lang-math-3/src/test/java/com/baeldung/magicsquare/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Creating a Magic Square in Java](https://www.baeldung.com/java-magic-square) diff --git a/core-java-modules/core-java-lang-oop-generics/README.md b/core-java-modules/core-java-lang-oop-generics/README.md index 720ba9dcfd..3e33ba5315 100644 --- a/core-java-modules/core-java-lang-oop-generics/README.md +++ b/core-java-modules/core-java-lang-oop-generics/README.md @@ -9,3 +9,4 @@ This module contains articles about generics in Java - [Super Type Tokens in Java Generics](https://www.baeldung.com/java-super-type-tokens) - [Java Warning “unchecked conversion”](https://www.baeldung.com/java-unchecked-conversion) - [Java Warning “Unchecked Cast”](https://www.baeldung.com/java-warning-unchecked-cast) +- [What Does the Holder Class Do in Java?](https://www.baeldung.com/java-holder-class) diff --git a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java index 1ade675e87..9f3e140926 100644 --- a/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java +++ b/core-java-modules/core-java-lang-oop-inheritance/src/main/java/com/baeldung/subclassinnerclass/EmailNotifier.java @@ -1,11 +1,12 @@ package com.baeldung.subclassinnerclass; -import java.util.HashMap; - public class EmailNotifier extends Notifier { @Override void notify(Message e) { - // Provide email specific implementation here + // connect to the email connector + EmailConnector emailConnector = new EmailConnector(); + emailConnector.connect(); + // send email } // Inner class for email connection @@ -13,5 +14,9 @@ public class EmailNotifier extends Notifier { private String emailHost; private int emailPort; // Getter Setters + + private void connect() { + // connect to the smtp server + } } } diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java index f8367cfd50..75edca087f 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Course.java @@ -1,6 +1,7 @@ package com.baeldung.deepcopyarraylist; import java.io.Serializable; +import java.util.Objects; public class Course implements Serializable, Cloneable { @@ -39,4 +40,23 @@ public class Course implements Serializable, Cloneable { throw new IllegalStateException(e); } } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + Course that = (Course) o; + + return Objects.equals(courseId,that.courseId) + && Objects.equals(courseName,that.courseName); + } + + @Override + public int hashCode() { + return Objects.hash(courseId,courseName); + } } diff --git a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java index 0b3f1ba4a9..ce9f773bc7 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/deepcopyarraylist/Student.java @@ -2,6 +2,7 @@ package com.baeldung.deepcopyarraylist; import java.io.Serializable; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.lang3.SerializationUtils; @@ -100,4 +101,23 @@ public class Student implements Serializable, Cloneable { student.course = this.course.clone(); return student; } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + Student that = (Student) o; + + return Objects.equals(studentId,that.studentId) && + Objects.equals(studentName, that.studentName) && + Objects.equals(course, that.course); + } + + @Override + public int hashCode() { + return Objects.hash(studentId,studentName,course); + } } diff --git a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java index 625c7e8385..d7e4c0ff64 100644 --- a/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java +++ b/core-java-modules/core-java-lang-oop-patterns/src/test/java/com/baeldung/deepcopyarraylist/DeepCopyArrayListUnitTest.java @@ -19,8 +19,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingCloneable(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @@ -37,8 +39,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingCopyConstructor(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @Test @@ -54,8 +58,10 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingSerialization(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } @Test @@ -71,7 +77,9 @@ public class DeepCopyArrayListUnitTest { List deepCopy = Student.deepCopyUsingJackson(students); - Assertions.assertNotEquals(students.get(0), deepCopy.get(0)); - Assertions.assertNotEquals(students.get(1), deepCopy.get(1)); + Assertions.assertEquals(students.get(0), deepCopy.get(0)); + Assertions.assertNotSame(students.get(0),deepCopy.get(0)); + Assertions.assertEquals(students.get(1), deepCopy.get(1)); + Assertions.assertNotSame(students.get(1),deepCopy.get(1)); } } diff --git a/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java b/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java index dac05a85b1..612fd7e097 100644 --- a/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java +++ b/core-java-modules/core-java-lang/src/test/java/com/baeldung/comparator/Java8ComparatorUnitTest.java @@ -30,13 +30,13 @@ public class Java8ComparatorUnitTest { System.out.println("************** Java 8 Comaparator **************"); Comparator byRanking = (Player player1, Player player2) -> Integer.compare(player1.getRanking(), player2.getRanking()); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byRanking); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Steven"); - assertEquals(footballTeam.get(2) - .getRanking(), 67); + assertEquals(footballTeam.get(0).getName(), "Steven"); + assertEquals(footballTeam.get(0).getRanking(), 45); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getRanking(), 59); + assertEquals(footballTeam.get(2).getName(), "Roger"); + assertEquals(footballTeam.get(2).getRanking(), 67); } @Test @@ -45,24 +45,24 @@ public class Java8ComparatorUnitTest { System.out.println("********* byRanking *********"); Comparator byRanking = Comparator.comparing(Player::getRanking); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byRanking); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Steven"); - assertEquals(footballTeam.get(2) - .getRanking(), 67); - + assertEquals(footballTeam.get(0).getName(), "Steven"); + assertEquals(footballTeam.get(0).getRanking(), 45); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getRanking(), 59); + assertEquals(footballTeam.get(2).getName(), "Roger"); + assertEquals(footballTeam.get(2).getRanking(), 67); + System.out.println("********* byAge *********"); Comparator byAge = Comparator.comparing(Player::getAge); - System.out.println("Before Sorting : " + footballTeam); Collections.sort(footballTeam, byAge); - System.out.println("After Sorting : " + footballTeam); - assertEquals(footballTeam.get(0) - .getName(), "Roger"); - assertEquals(footballTeam.get(2) - .getRanking(), 45); + assertEquals(footballTeam.get(0).getName(), "Roger"); + assertEquals(footballTeam.get(0).getAge(), 20); + assertEquals(footballTeam.get(1).getName(), "John"); + assertEquals(footballTeam.get(1).getAge(), 22); + assertEquals(footballTeam.get(2).getName(), "Steven"); + assertEquals(footballTeam.get(2).getAge(), 24); } } diff --git a/core-java-modules/core-java-string-conversions-3/README.md b/core-java-modules/core-java-string-conversions-3/README.md index 96799d1660..4b348dd555 100644 --- a/core-java-modules/core-java-string-conversions-3/README.md +++ b/core-java-modules/core-java-string-conversions-3/README.md @@ -1,3 +1,4 @@ ## Relevant Articles - [Object.toString() vs String.valueOf()](https://www.baeldung.com/java-object-tostring-vs-string-valueof) - [Convert String to Int Using Encapsulation](https://www.baeldung.com/java-encapsulation-convert-string-to-int) +- [HashMap with Multiple Values for the Same Key](https://www.baeldung.com/java-hashmap-multiple-values-per-key) diff --git a/di-modules/avaje/README.md b/di-modules/avaje/README.md index ea914e551f..f0fa9f058e 100644 --- a/di-modules/avaje/README.md +++ b/di-modules/avaje/README.md @@ -4,4 +4,4 @@ This module contains articles about Avaje ### Relevant articles: -- [Introduction to Avaje Inject](https://www.baeldung.com/avaje-inject/intro) \ No newline at end of file +- [Introduction to Avaje Inject](https://www.baeldung.com/avaje-inject) diff --git a/javaxval-2/README.md b/javaxval-2/README.md index b7603d9e84..3ae53ebd94 100644 --- a/javaxval-2/README.md +++ b/javaxval-2/README.md @@ -7,4 +7,5 @@ This module contains articles about Bean Validation. - [Guide to ParameterMessageInterpolator](https://www.baeldung.com/hibernate-parametermessageinterpolator) - [Hibernate Validator Annotation Processor in Depth](https://www.baeldung.com/hibernate-validator-annotation-processor) - [Object Validation After Deserialization](https://www.baeldung.com/java-object-validation-deserialization) +- [Java Validation List Annotations](https://www.baeldung.com/java-validation-list-annotations) - More articles: [[<-- prev]](../javaxval) diff --git a/json-modules/json-2/pom.xml b/json-modules/json-2/pom.xml index 82fe689ebf..7253088516 100644 --- a/json-modules/json-2/pom.xml +++ b/json-modules/json-2/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 json-2 0.0.1-SNAPSHOT @@ -123,6 +123,26 @@ javax.annotation-api 1.3.2 + + com.github.victools + jsonschema-generator + ${jsonschema-generator.version} + + + com.github.victools + jsonschema-module-jackson + ${jsonschema-generator.version} + + + jakarta.validation + jakarta.validation-api + ${jakarta.validation.version} + + + com.github.victools + jsonschema-module-jakarta-validation + ${jsonschema-generator.version} + @@ -162,6 +182,55 @@ + + + com.github.victools + jsonschema-maven-plugin + ${jsonschema-generator.version} + + + + generate + + + + + + com.baeldung.jsonschemageneration.plugin + + + com.baeldung.jsonschemageneration.plugin.Person + + DRAFT_2020_12 + src/main/resources/schemas + {1}/{0}.json + true + + PLAIN_JSON + + + + + SCHEMA_VERSION_INDICATOR + + + + Jackson + + + + + + JakartaValidation + + + + + + + + + @@ -173,6 +242,8 @@ 0.1.1 0.4.2 0.13.0 + 4.31.1 + 3.0.2 \ No newline at end of file diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java new file mode 100644 index 0000000000..07e00bba0f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedArticle.java @@ -0,0 +1,70 @@ +package com.baeldung.jsonschemageneration.configuration; + +import java.sql.Timestamp; +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class AdvancedArticle { + private UUID id; + private String title; + + private String content; + + @AllowedTypes({ Timestamp.class, Date.class }) + private Object createdAt; + private Area area; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Object getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Object createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java new file mode 100644 index 0000000000..3fbf6bac6e --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AdvancedConfigurationSchemaGenerator.java @@ -0,0 +1,39 @@ +package com.baeldung.jsonschemageneration.configuration; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class AdvancedConfigurationSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + + configBuilder.forFields().withInstanceAttributeOverride((node, field, context) -> node.put("readOnly", field.getDeclaredType().isInstanceOf(UUID.class))); + + configBuilder.forFields() + .withTargetTypeOverridesResolver(field -> Optional.ofNullable(field.getAnnotationConsideringFieldAndGetterIfSupported(AllowedTypes.class)) + .map(AllowedTypes::value) + .map(Stream::of) + .map(stream -> stream.map(subtype -> field.getContext().resolve(subtype))) + .map(stream -> stream.collect(Collectors.toList())) + .orElse(null)); + + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(AdvancedArticle.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java new file mode 100644 index 0000000000..9c2ae2780d --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/AllowedTypes.java @@ -0,0 +1,13 @@ +package com.baeldung.jsonschemageneration.configuration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface AllowedTypes { + Class[] value(); +} + diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java new file mode 100644 index 0000000000..3e1b556311 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/configuration/IndividualConfigurationSchemaGenerator.java @@ -0,0 +1,44 @@ +package com.baeldung.jsonschemageneration.configuration; + +import com.baeldung.jsonschemageneration.recursive.Author; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class IndividualConfigurationSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + + configBuilder.forFields().withRequiredCheck(field -> field.getAnnotationConsideringFieldAndGetter(Nullable.class) == null).withArrayUniqueItemsResolver(scope -> scope.getType().getErasedType() == (List.class) ? true : null); + + configBuilder.forMethods().withRequiredCheck(method -> method.getAnnotationConsideringFieldAndGetter(NotNull.class) != null); + + configBuilder.forTypesInGeneral() + .withArrayUniqueItemsResolver(scope -> scope.getType().getErasedType() == (List.class) ? true : null) + .withDefaultResolver(scope -> scope.getType().getErasedType() == List.class ? Collections.EMPTY_LIST : null) + .withDefaultResolver(scope -> scope.getType().getErasedType() == Date.class ? Date.from(Instant.now()) : null) + .withEnumResolver(scope -> scope.getType().getErasedType().isEnum() ? Stream.of(scope.getType().getErasedType().getEnumConstants()).map(v -> ((Enum) v).name()).collect(Collectors.toList()) : null); + + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(Author.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java new file mode 100644 index 0000000000..eda5015400 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JacksonModuleSchemaGenerator.java @@ -0,0 +1,68 @@ +package com.baeldung.jsonschemageneration.modules; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.module.jackson.JacksonModule; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static com.github.victools.jsonschema.generator.Option.EXTRA_OPEN_API_FORMAT_VALUES; +import static com.github.victools.jsonschema.generator.OptionPreset.PLAIN_JSON; +import static com.github.victools.jsonschema.generator.SchemaVersion.DRAFT_2020_12; +import static com.github.victools.jsonschema.module.jackson.JacksonOption.RESPECT_JSONPROPERTY_REQUIRED; + +public class JacksonModuleSchemaGenerator { + public static void main(String[] args) { + + JacksonModule module = new JacksonModule(RESPECT_JSONPROPERTY_REQUIRED); + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(DRAFT_2020_12, PLAIN_JSON).with(module).with(EXTRA_OPEN_API_FORMAT_VALUES); + + SchemaGenerator generator = new SchemaGenerator(configBuilder.build()); + JsonNode jsonSchema = generator.generateSchema(Person.class); + + System.out.println(jsonSchema.toPrettyString()); + } + + static class Person { + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + UUID id; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String name; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String surname; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + Address address; + + @JsonIgnore + String fullName; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Date createdAt; + + @JsonProperty(access = JsonProperty.Access.READ_WRITE) + List friends; + + } + + static class Address { + + @JsonProperty() + String street; + + @JsonProperty(required = true) + String city; + + @JsonProperty(required = true) + String country; + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java new file mode 100644 index 0000000000..ca19d35357 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/modules/JakartaValidationModuleSchemaGenerator.java @@ -0,0 +1,63 @@ +package com.baeldung.jsonschemageneration.modules; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationModule; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static com.github.victools.jsonschema.generator.OptionPreset.PLAIN_JSON; +import static com.github.victools.jsonschema.generator.SchemaVersion.DRAFT_2020_12; +import static com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationOption.INCLUDE_PATTERN_EXPRESSIONS; +import static com.github.victools.jsonschema.module.jakarta.validation.JakartaValidationOption.NOT_NULLABLE_FIELD_IS_REQUIRED; + +public class JakartaValidationModuleSchemaGenerator { + public static void main(String[] args) { + + JakartaValidationModule module = new JakartaValidationModule(NOT_NULLABLE_FIELD_IS_REQUIRED, INCLUDE_PATTERN_EXPRESSIONS); + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(DRAFT_2020_12, PLAIN_JSON).with(module); + + SchemaGenerator generator = new SchemaGenerator(configBuilder.build()); + JsonNode jsonSchema = generator.generateSchema(Person.class); + + System.out.println(jsonSchema.toPrettyString()); + } + + static class Person { + + @NotNull UUID id; + + @NotNull String name; + + @NotNull @Email @Pattern(regexp = "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b") String email; + + @NotNull String surname; + + @NotNull Address address; + + @Null String fullName; + + @NotNull Date createdAt; + + @Size(max = 10) List friends; + + } + + static class Address { + + @Null String street; + + @NotNull String city; + + @NotNull String country; + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java new file mode 100644 index 0000000000..f87dcd5981 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/plugin/Person.java @@ -0,0 +1,61 @@ +package com.baeldung.jsonschemageneration.plugin; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Null; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +public class Person { + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + UUID id; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + String name; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + @Email @Pattern(regexp = "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b") String email; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + + String surname; + + @NotNull + @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true) + Address address; + + @Null String fullName; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Date createdAt; + + @Size(max = 10) + @JsonProperty(access = JsonProperty.Access.READ_WRITE) + List friends; + +} + +class Address { + + @Null + @JsonProperty + String street; + + @NotNull + @JsonProperty(required = true) + String city; + + @NotNull + @JsonProperty(required = true) + String country; +} \ No newline at end of file diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java new file mode 100644 index 0000000000..a19afb3f6f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/Author.java @@ -0,0 +1,12 @@ +package com.baeldung.jsonschemageneration.recursive; + +import java.util.List; +import java.util.UUID; + +public class Author { + private UUID id; + private String name; + private String role; + + private List articles; +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java new file mode 100644 index 0000000000..3ab7464aaf --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/AuthoredArticle.java @@ -0,0 +1,68 @@ +package com.baeldung.jsonschemageneration.recursive; + +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class AuthoredArticle { + private UUID id; + private String title; + private String content; + private Date createdAt; + private Area area; + + private Author author; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java new file mode 100644 index 0000000000..2047dac53f --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/recursive/RecursiveSchemaGenerator.java @@ -0,0 +1,23 @@ +package com.baeldung.jsonschemageneration.recursive; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +public class RecursiveSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).without(Option.FLATTENED_ENUMS_FROM_TOSTRING).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(AuthoredArticle.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java new file mode 100644 index 0000000000..480dc2e425 --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/Article.java @@ -0,0 +1,66 @@ +package com.baeldung.jsonschemageneration.simple; + +import java.util.Date; +import java.util.UUID; + +enum Area { + JAVA("JAVA"), KOTLIN("KOTLIN"), SCALA("SCALA"), LINUX("LINUX"); + + private final String area; + + Area(String area) { + this.area = area; + } + + public String getArea() { + return area; + } +} + +public class Article { + private UUID id; + private String title; + private String content; + private Date createdAt; + private Area area; + + public Area getArea() { + return area; + } + + public void setArea(Area area) { + this.area = area; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java new file mode 100644 index 0000000000..daea643b1b --- /dev/null +++ b/json-modules/json-2/src/main/java/com/baeldung/jsonschemageneration/simple/SimpleSchemaGenerator.java @@ -0,0 +1,23 @@ +package com.baeldung.jsonschemageneration.simple; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.Option; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfig; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; + +public class SimpleSchemaGenerator { + public static void main(String[] args) { + + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); + SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES).without(Option.FLATTENED_ENUMS_FROM_TOSTRING).build(); + + SchemaGenerator generator = new SchemaGenerator(config); + JsonNode jsonSchema = generator.generateSchema(Article.class); + + System.out.println(jsonSchema.toPrettyString()); + } + +} diff --git a/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json b/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json new file mode 100644 index 0000000000..d52a527684 --- /dev/null +++ b/json-modules/json-2/src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json @@ -0,0 +1,54 @@ +{ + "$defs" : { + "Address" : { + "type" : "object", + "properties" : { + "city" : { + "type" : "string" + }, + "country" : { + "type" : "string" + }, + "street" : { + "type" : [ "string", "null" ] + } + }, + "required" : [ "city", "country" ], + "additionalProperties" : false + } + }, + "type" : "object", + "properties" : { + "address" : { + "$ref" : "#/$defs/Address" + }, + "createdAt" : { + "type" : "string", + "readOnly" : true + }, + "email" : { + "type" : "string", + "format" : "email", + "pattern" : "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b" + }, + "friends" : { + "maxItems" : 10, + "type" : "array", + "items" : { + "$ref" : "#" + } + }, + "id" : { + "type" : "string", + "readOnly" : true + }, + "name" : { + "type" : "string" + }, + "surname" : { + "type" : "string" + } + }, + "required" : [ "address", "email", "id", "name", "surname" ], + "additionalProperties" : false +} \ No newline at end of file diff --git a/json-modules/json-arrays/pom.xml b/json-modules/json-arrays/pom.xml new file mode 100644 index 0000000000..0eefbc86fc --- /dev/null +++ b/json-modules/json-arrays/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + org.baeldung + json-arrays + json-arrays + + + com.baeldung + json-modules + 1.0.0-SNAPSHOT + + + + + org.json + json + ${json.version} + + + com.google.code.gson + gson + ${gson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + javax.json.bind + javax.json.bind-api + ${jsonb-api.version} + + + + + 1.0 + 20230227 + 2.8.5 + 1.1.2 + 2.28.0 + + + diff --git a/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java b/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java new file mode 100644 index 0000000000..6e1cbb7ab0 --- /dev/null +++ b/json-modules/json-arrays/src/test/java/com.baeldung.checkforkey/CheckForKeyUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.checkforkey; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Objects; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + +public class CheckForKeyUnitTest { + + private final String exampleJson = "[{\"colour\":\"red\"},{\"colour\":\"blue\"},{\"colour\":\"green\"}]"; + + @Test + public void givenJsonArray_whenUsingJackson_thenDetectKeyInArray() throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode tree = objectMapper.readTree(exampleJson); + + Stream s = StreamSupport.stream(tree.spliterator(), false); + boolean result = s.map(entry -> entry.get("colour")) + .filter(Objects::nonNull) + .anyMatch(colour -> "green".equals(colour.asText())); + assertTrue(result); + } + + @Test + public void givenJsonArray_whenUsingGson_thenDetectKeyInArray() { + Gson gson = new Gson(); + JsonArray parsed = gson.fromJson(exampleJson, JsonArray.class); + + Stream s = StreamSupport.stream(parsed.spliterator(), false); + boolean result = s.map(entry -> entry.getAsJsonObject() + .get("colour")) + .filter(Objects::nonNull) + .anyMatch(colour -> "green".equals(colour.getAsString())); + assertTrue(result); + } + +} diff --git a/json-modules/pom.xml b/json-modules/pom.xml index 82314e0edf..306b404049 100644 --- a/json-modules/pom.xml +++ b/json-modules/pom.xml @@ -16,6 +16,7 @@ json json-2 + json-arrays json-conversion json-path gson diff --git a/kubernetes-modules/README.md b/kubernetes-modules/README.md new file mode 100644 index 0000000000..cb52c12465 --- /dev/null +++ b/kubernetes-modules/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Guide to Eclipse JKube](https://www.baeldung.com/ops/eclipse-jkube) diff --git a/lombok-modules/lombok-2/pom.xml b/lombok-modules/lombok-2/pom.xml index 88fbaf530f..ea562ad896 100644 --- a/lombok-modules/lombok-2/pom.xml +++ b/lombok-modules/lombok-2/pom.xml @@ -25,10 +25,58 @@ jackson-databind ${jackson.version} + + com.google.code.gson + gson + ${gson.version} + + + javax.annotation + javax.annotation-api + ${javax.annotation} + + + io.swagger + swagger-annotations + ${swagger.annotation} + org.springframework.boot spring-boot-starter-web + + + + org.openapitools + openapi-generator-maven-plugin + ${openapi.version} + + + + generate + + + ${project.basedir}/src/main/resources/bookapi.yml + java + com.baeldung.openapi.model + + @lombok.Data @lombok.NoArgsConstructor @lombok.AllArgsConstructor + + false + false + false + + + + + + + + 4.2.3 + 2.10.1 + 1.3.2 + 1.6.2 + \ No newline at end of file diff --git a/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java b/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java new file mode 100644 index 0000000000..2da2e74a40 --- /dev/null +++ b/lombok-modules/lombok-2/src/main/java/com/baeldung/lombok/openapiandlombook/Book.java @@ -0,0 +1,12 @@ +package com.baeldung.lombok.openapiandlombook; + +@lombok.Data +@lombok.NoArgsConstructor +@lombok.AllArgsConstructor +public class Book { + + private Long id; + private String name; + private String author; + +} diff --git a/lombok-modules/lombok-2/src/main/resources/bookapi.yml b/lombok-modules/lombok-2/src/main/resources/bookapi.yml new file mode 100644 index 0000000000..e9b63b2f85 --- /dev/null +++ b/lombok-modules/lombok-2/src/main/resources/bookapi.yml @@ -0,0 +1,39 @@ +openapi: 3.0.2 +info: + version: 1.0.0 + title: Book Store + license: + name: MIT +paths: + /books: + get: + tags: + - book + summary: Get All Books + responses: + 200: + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Book' + + 404: + description: Book not found + content: { } +components: + schemas: + Book: + type: object + required: + - id + - name + - author + properties: + id: + type: integer + format: int64 + name: + type: string + author: + type: string diff --git a/lombok-modules/lombok/pom.xml b/lombok-modules/lombok/pom.xml index 6ba90f33b5..a04233bc2b 100644 --- a/lombok-modules/lombok/pom.xml +++ b/lombok-modules/lombok/pom.xml @@ -43,7 +43,6 @@ - edge-SNAPSHOT 1.0.0.Final 1.18.20.0 23.0.0 diff --git a/lombok-modules/pom.xml b/lombok-modules/pom.xml index 5100ed1790..46d91462fb 100644 --- a/lombok-modules/pom.xml +++ b/lombok-modules/pom.xml @@ -16,7 +16,7 @@ - + lombok lombok-2 diff --git a/maven-modules/maven-build-optimization/README.md b/maven-modules/maven-build-optimization/README.md new file mode 100644 index 0000000000..c1764b67ac --- /dev/null +++ b/maven-modules/maven-build-optimization/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [How to Speed Up Maven Build](https://www.baeldung.com/maven-fast-build) diff --git a/pants/README.md b/pants/README.md new file mode 100644 index 0000000000..a37d2e3d31 --- /dev/null +++ b/pants/README.md @@ -0,0 +1,2 @@ +## Relevant Articles +- [Introduction to the Pants Build Tool](https://www.baeldung.com/ops/pants-build-tool-guide) diff --git a/persistence-modules/core-java-persistence-2/pom.xml b/persistence-modules/core-java-persistence-2/pom.xml index 0bec7a808f..2013bdb6af 100644 --- a/persistence-modules/core-java-persistence-2/pom.xml +++ b/persistence-modules/core-java-persistence-2/pom.xml @@ -70,6 +70,16 @@ ${assertj.version} test + + org.mybatis + mybatis + ${mybatis.version} + + + org.springframework + spring-jdbc + ${spring-jdbc.version} + @@ -80,6 +90,8 @@ 20220320 07.00.00-MS-GA 2.1.214 + 5.3.29 + 3.5.7 \ No newline at end of file diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java new file mode 100644 index 0000000000..8a9bbb6e20 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java @@ -0,0 +1,13 @@ +package com.baeldung.script; + +import org.apache.ibatis.jdbc.ScriptRunner; +import java.sql.Connection; + +public class MyBatisScriptUtility { + public static void runScript(String path, Connection connection) throws Exception { + ScriptRunner scriptRunner = new ScriptRunner(connection); + scriptRunner.setSendFullScript(false); + scriptRunner.setStopOnError(true); + scriptRunner.runScript(new java.io.FileReader(path)); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java new file mode 100644 index 0000000000..cf70dfa890 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java @@ -0,0 +1,29 @@ +package com.baeldung.script; + +import org.springframework.core.io.PathResource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.jdbc.datasource.init.ScriptUtils; + +import java.sql.Connection; + +public class SpringScriptUtility { + public static void runScript(String path, Connection connection) { + boolean continueOrError = false; + boolean ignoreFailedDrops = false; + String commentPrefix = "--"; + String separator = ";"; + String blockCommentStartDelimiter = "/*"; + String blockCommentEndDelimiter = "*/"; + + ScriptUtils.executeSqlScript( + connection, + new EncodedResource(new PathResource(path)), + continueOrError, + ignoreFailedDrops, + commentPrefix, + separator, + blockCommentStartDelimiter, + blockCommentEndDelimiter + ); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java new file mode 100644 index 0000000000..b9da968abe --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java @@ -0,0 +1,74 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SqlScriptBatchExecutor { + private static final Log logger = LogFactory.getLog(SqlScriptBatchExecutor.class); + private static final Pattern COMMENT_PATTERN = Pattern.compile("--.*|/\\*(.|[\\r\\n])*?\\*/"); + public static void executeBatchedSQL(String scriptFilePath, Connection connection, int batchSize) throws Exception { + List sqlStatements = parseSQLScript(scriptFilePath); + executeSQLBatches(connection, sqlStatements, batchSize); + } + private static List parseSQLScript(String scriptFilePath) throws IOException { + List sqlStatements = new ArrayList<>(); + + try (BufferedReader reader = new BufferedReader(new FileReader(scriptFilePath))) { + StringBuilder currentStatement = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + Matcher commentMatcher = COMMENT_PATTERN.matcher(line); + line = commentMatcher.replaceAll(""); + line = line.trim(); + + if (line.isEmpty()) { + continue; + } + + currentStatement.append(line).append(" "); + + if (line.endsWith(";")) { + sqlStatements.add(currentStatement.toString()); + logger.info(currentStatement.toString()); + currentStatement.setLength(0); + } + } + } catch (IOException e) { + throw e; + } + return sqlStatements; + } + + private static void executeSQLBatches(Connection connection, List sqlStatements, int batchSize) + throws SQLException { + int count = 0; + Statement statement = connection.createStatement(); + + for (String sql : sqlStatements) { + statement.addBatch(sql); + count++; + + if (count % batchSize == 0) { + logger.info("Executing batch"); + statement.executeBatch(); + statement.clearBatch(); + } + } + // Execute any remaining statements + if (count % batchSize != 0) { + statement.executeBatch(); + } + connection.commit(); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java new file mode 100644 index 0000000000..98f82cfbd5 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class MyBatisScriptUtilityUnitTest { + private static final Log logger = LogFactory.getLog(MyBatisScriptUtilityUnitTest.class); + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb1"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + MyBatisScriptUtility.runScript(path, connection); + + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java new file mode 100644 index 0000000000..be6e39ca31 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class SpringScriptUtilityUnitTest { + private static final Log logger = LogFactory.getLog(SpringScriptUtilityUnitTest.class); + + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb2"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + SpringScriptUtility.runScript(path, connection); + + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java new file mode 100644 index 0000000000..3b1210fd00 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class SqlScriptBatchExecutorUnitTest { + private static final Log logger = LogFactory.getLog(SqlScriptBatchExecutorUnitTest.class); + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb3"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + SqlScriptBatchExecutor.executeBatchedSQL(path, connection, 10); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } + +} diff --git a/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql b/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql new file mode 100644 index 0000000000..c532458163 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql @@ -0,0 +1,75 @@ +/** +Script Name : Create employees script +Author: Parthiv Pradhan + +**/ + +-- Create the employees table if it doesn't exist +CREATE TABLE employees ( + id INT PRIMARY KEY, + first_name VARCHAR(50), + last_name VARCHAR(50), + department VARCHAR(50), + salary DECIMAL(10, 2) +); + +-- Insert employee records +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (1, 'John', 'Doe', 'HR', 50000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (2, 'Jane', 'Smith', 'IT', 60000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (3, 'Michael', 'Johnson', 'Finance', 55000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (4, 'Emily', 'Williams', 'Marketing', 52000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (5, 'David', 'Brown', 'IT', 65000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (6, 'Sarah', 'Miller', 'Finance', 58000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (7, 'Robert', 'Jones', 'HR', 53000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (8, 'Jessica', 'Davis', 'Marketing', 51000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (9, 'William', 'Wilson', 'IT', 59000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (10, 'Jennifer', 'Taylor', 'Finance', 57000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (11, 'Daniel', 'Anderson', 'Marketing', 54000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (12, 'Linda', 'Martinez', 'HR', 52000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (13, 'Christopher', 'Lopez', 'IT', 62000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (14, 'Karen', 'Hernandez', 'Finance', 56000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (15, 'Mark', 'Garcia', 'Marketing', 53000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (16, 'Patricia', 'Lee', 'HR', 51000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (17, 'Anthony', 'Clark', 'IT', 60000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (18, 'Maria', 'Lewis', 'Finance', 59000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (19, 'Paul', 'Walker', 'Marketing', 55000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (20, 'Ruth', 'Young', 'HR', 54000.00); diff --git a/persistence-modules/hibernate-enterprise/pom.xml b/persistence-modules/hibernate-enterprise/pom.xml index eaa7b0e765..954f8f40d3 100644 --- a/persistence-modules/hibernate-enterprise/pom.xml +++ b/persistence-modules/hibernate-enterprise/pom.xml @@ -82,7 +82,6 @@ 8.0.32 2.6.0 0.9 - 1.14.2 \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties index b030527cca..df322cd15e 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-off.properties @@ -5,7 +5,7 @@ spring.datasource.password= spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console -spring.sql.init.data-locations=data-trans.sql +spring.sql.init.data-locations=classpath:data-trans.sql logging.level.org.hibernate.SQL=INFO logging.level.org.hibernate.type=INFO diff --git a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties index 972a7bb0f3..e5c488f3be 100644 --- a/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties +++ b/persistence-modules/spring-boot-persistence-h2/src/main/resources/application-lazy-load-no-trans-on.properties @@ -5,7 +5,7 @@ spring.datasource.password= spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console -spring.sql.init.data-locations=data-trans.sql +spring.sql.init.data-locations=classpath:data-trans.sql logging.level.org.hibernate.SQL=INFO logging.level.org.hibernate.type=INFO diff --git a/pom.xml b/pom.xml index 8b9c61550a..f06cd438f8 100644 --- a/pom.xml +++ b/pom.xml @@ -427,7 +427,6 @@ spring-security-modules/spring-security-ldap - spring-soap spring-swagger-codegen video-tutorials @@ -594,7 +593,6 @@ spring-security-modules/spring-security-ldap - spring-soap spring-swagger-codegen video-tutorials @@ -908,6 +906,7 @@ spring-kafka spring-native + spring-soap spring-security-modules spring-protobuf spring-quartz @@ -1180,6 +1179,7 @@ spring-kafka spring-native + spring-soap spring-security-modules spring-protobuf spring-quartz @@ -1261,7 +1261,7 @@ 2.2 1.3 4.4.0 - 1.12.13 + 1.14.6 @@ -1278,7 +1278,7 @@ 1.36 2.21.0 4.4 - 2.11.0 + 2.13.0 2.6 3.13.0 1.5.0 @@ -1288,7 +1288,7 @@ 2.3.3 1.2 2.15.2 - 1.4 + 1.5 1.9.2 5.9.2 1.3.2 diff --git a/spring-boot-modules/spring-boot-telegram/.gitignore b/spring-boot-modules/spring-boot-telegram/.gitignore new file mode 100644 index 0000000000..a8e6c9dbce --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/.gitignore @@ -0,0 +1,35 @@ +HELP.md +target/ +.mvn +mvnw +mvnw.cmd +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/spring-boot-modules/spring-boot-telegram/pom.xml b/spring-boot-modules/spring-boot-telegram/pom.xml new file mode 100644 index 0000000000..b960137449 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + com.baelding + spring-boot-telegram + 0.0.1-SNAPSHOT + spring-boot-telegram + Demo project for Spring Boot with Spring Data Redis + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../parent-boot-3 + + + + + org.telegram + telegrambots-spring-boot-starter + 6.7.0 + + + org.telegram + telegrambots-abilities + 6.7.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 17 + + + diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java new file mode 100644 index 0000000000..5c529bf15c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/Constants.java @@ -0,0 +1,9 @@ +package com.baeldung.telegram; + +public class Constants { + + public static final String START_DESCRIPTION = "Starts the bot"; + + public static final String CHAT_STATES = "chatStates"; + public static final String START_TEXT = "Welcome to Baeldung Pizza Bot.\nPlease enter your name"; +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java new file mode 100644 index 0000000000..367c5a4c7c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/KeyboardFactory.java @@ -0,0 +1,30 @@ +package com.baeldung.telegram; + +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardMarkup; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.KeyboardRow; + +import java.util.List; + +public class KeyboardFactory { +public static ReplyKeyboard getPizzaToppingsKeyboard() { + KeyboardRow row = new KeyboardRow(); + row.add("Margherita"); + row.add("Pepperoni"); + return new ReplyKeyboardMarkup(List.of(row)); +} + + public static ReplyKeyboard getPizzaOrDrinkKeyboard(){ + KeyboardRow row = new KeyboardRow(); + row.add("Pizza"); + row.add("Drink"); + return new ReplyKeyboardMarkup(List.of(row)); + } + + public static ReplyKeyboard getYesOrNo() { + KeyboardRow row = new KeyboardRow(); + row.add("Yes"); + row.add("No"); + return new ReplyKeyboardMarkup(List.of(row)); + } +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java new file mode 100644 index 0000000000..802cb586d7 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/PizzaBot.java @@ -0,0 +1,48 @@ +package com.baeldung.telegram; + +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.telegram.abilitybots.api.bot.AbilityBot; +import org.telegram.abilitybots.api.bot.BaseAbilityBot; +import org.telegram.abilitybots.api.objects.Ability; +import org.telegram.abilitybots.api.objects.Flag; +import org.telegram.abilitybots.api.objects.Reply; +import org.telegram.telegrambots.meta.api.objects.Update; + +import java.util.function.BiConsumer; + +import static org.telegram.abilitybots.api.objects.Locality.USER; +import static org.telegram.abilitybots.api.objects.Privacy.PUBLIC; +import static org.telegram.abilitybots.api.util.AbilityUtils.getChatId; + +@Component +public class PizzaBot extends AbilityBot { + + private final ResponseHandler responseHandler; + + public PizzaBot(Environment environment) { + super(environment.getProperty("BOT_TOKEN"), "baeldungbot"); + responseHandler = new ResponseHandler(silent, db); + } + +public Ability startBot() { + return Ability + .builder() + .name("start") + .info(Constants.START_DESCRIPTION) + .locality(USER) + .privacy(PUBLIC) + .action(ctx -> responseHandler.replyToStart(ctx.chatId())) + .build(); +} + +public Reply replyToButtons() { + BiConsumer action = (abilityBot, upd) -> responseHandler.replyToButtons(getChatId(upd), upd.getMessage()); + return Reply.of(action, Flag.TEXT,upd -> responseHandler.userIsActive(getChatId(upd))); +} + +@Override +public long creatorId() { + return 1L; +} +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java new file mode 100644 index 0000000000..862edc962c --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/ResponseHandler.java @@ -0,0 +1,132 @@ +package com.baeldung.telegram; + +import org.telegram.abilitybots.api.db.DBContext; +import org.telegram.abilitybots.api.sender.SilentSender; +import org.telegram.telegrambots.meta.api.methods.send.SendMessage; +import org.telegram.telegrambots.meta.api.objects.Message; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboardRemove; + +import java.util.Map; + +import static com.baeldung.telegram.Constants.START_TEXT; +import static com.baeldung.telegram.UserState.*; + +public class ResponseHandler { + private final SilentSender sender; + private final Map chatStates; + + public ResponseHandler(SilentSender sender, DBContext db) { + this.sender = sender; + chatStates = db.getMap(Constants.CHAT_STATES); + } + + public void replyToStart(long chatId) { + SendMessage message = new SendMessage(); + message.setChatId(chatId); + message.setText(START_TEXT); + sender.execute(message); + chatStates.put(chatId, AWAITING_NAME); + } + +public void replyToButtons(long chatId, Message message) { + if (message.getText().equalsIgnoreCase("/stop")) { + stopChat(chatId); + } + + switch (chatStates.get(chatId)) { + case AWAITING_NAME -> replyToName(chatId, message); + case FOOD_DRINK_SELECTION -> replyToFoodDrinkSelection(chatId, message); + case PIZZA_TOPPINGS -> replyToPizzaToppings(chatId, message); + case AWAITING_CONFIRMATION -> replyToOrder(chatId, message); + default -> unexpectedMessage(chatId); + } +} + + private void unexpectedMessage(long chatId) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("I did not expect that."); + sender.execute(sendMessage); + } + +private void stopChat(long chatId) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("Thank you for your order. See you soon!\nPress /start to order again"); + chatStates.remove(chatId); + sendMessage.setReplyMarkup(new ReplyKeyboardRemove(true)); + sender.execute(sendMessage); +} + + private void replyToOrder(long chatId, Message message) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + if ("yes".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We will deliver it soon. Thank you!\nOrder another?"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + chatStates.put(chatId, FOOD_DRINK_SELECTION); + } else if ("no".equalsIgnoreCase(message.getText())) { + stopChat(chatId); + } else { + sendMessage.setText("Please select yes or no"); + sendMessage.setReplyMarkup(KeyboardFactory.getYesOrNo()); + sender.execute(sendMessage); + } + } + + private void replyToPizzaToppings(long chatId, Message message) { + if ("margherita".equalsIgnoreCase(message.getText())) { + promptWithKeyboardForState(chatId, "You selected Margherita Pizza.\nWe will deliver it soon. Thank you!\nOrder again?", + KeyboardFactory.getYesOrNo(), AWAITING_CONFIRMATION); + } else if ("pepperoni".equalsIgnoreCase(message.getText())) { + promptWithKeyboardForState(chatId, "We finished the Pepperoni Pizza.\nSelect another Topping", + KeyboardFactory.getPizzaToppingsKeyboard(), PIZZA_TOPPINGS); + } else { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText("We don't sell " + message.getText() + " Pizza.\nSelect the toppings!"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaToppingsKeyboard()); + sender.execute(sendMessage); + } + } + + private void promptWithKeyboardForState(long chatId, String text, ReplyKeyboard YesOrNo, UserState awaitingReorder) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + sendMessage.setText(text); + sendMessage.setReplyMarkup(YesOrNo); + sender.execute(sendMessage); + chatStates.put(chatId, awaitingReorder); + } + +private void replyToFoodDrinkSelection(long chatId, Message message) { + SendMessage sendMessage = new SendMessage(); + sendMessage.setChatId(chatId); + if ("drink".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We don't sell drinks.\nBring your own drink!! :)"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + } else if ("pizza".equalsIgnoreCase(message.getText())) { + sendMessage.setText("We love Pizza in here.\nSelect the toppings!"); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaToppingsKeyboard()); + sender.execute(sendMessage); + chatStates.put(chatId, UserState.PIZZA_TOPPINGS); + } else { + sendMessage.setText("We don't sell " + message.getText() + ". Please select from the options below."); + sendMessage.setReplyMarkup(KeyboardFactory.getPizzaOrDrinkKeyboard()); + sender.execute(sendMessage); + } +} + +private void replyToName(long chatId, Message message) { + promptWithKeyboardForState(chatId, "Hello " + message.getText() + ". What would you like to have?", + KeyboardFactory.getPizzaOrDrinkKeyboard(), + UserState.FOOD_DRINK_SELECTION); +} + + public boolean userIsActive(Long chatId) { + return chatStates.containsKey(chatId); + } +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java new file mode 100644 index 0000000000..041478f42b --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/SpringBootTelegramApplication.java @@ -0,0 +1,24 @@ +package com.baeldung.telegram; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.telegram.abilitybots.api.bot.AbilityBot; +import org.telegram.telegrambots.meta.TelegramBotsApi; +import org.telegram.telegrambots.meta.exceptions.TelegramApiException; +import org.telegram.telegrambots.updatesreceivers.DefaultBotSession; + +@SpringBootApplication +public class SpringBootTelegramApplication { + + public static void main(String[] args) { + ConfigurableApplicationContext ctx = SpringApplication.run(SpringBootTelegramApplication.class, args); + try { + TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class); + botsApi.registerBot(ctx.getBean("pizzaBot", AbilityBot.class)); + } catch (TelegramApiException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java new file mode 100644 index 0000000000..a0b53a6a02 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/java/com/baeldung/telegram/UserState.java @@ -0,0 +1,5 @@ +package com.baeldung.telegram; + +public enum UserState { + AWAITING_NAME, FOOD_DRINK_SELECTION, PIZZA_TOPPINGS, AWAITING_CONFIRMATION +} diff --git a/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties b/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties new file mode 100644 index 0000000000..6b2753c3a8 --- /dev/null +++ b/spring-boot-modules/spring-boot-telegram/src/main/resources/application.properties @@ -0,0 +1,2 @@ +server.port=8081 +BOT_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties index 2ea30b9ab7..597899bd16 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/book-service.properties @@ -10,8 +10,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=never -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties index 42e114450d..44d5267d10 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/gateway.properties @@ -6,8 +6,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=always -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties index 059b87e4e7..89f8ee40fe 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/rating-service.properties @@ -10,8 +10,8 @@ eureka.client.registryFetchIntervalSeconds = 5 management.security.sessions=never -logging.level.org.springframework.web.=debug -logging.level.org.springframework.security=debug +logging.level.org.springframework.web.=INFO +logging.level.org.springframework.security=INFO spring.redis.host=localhost spring.redis.port=6379 diff --git a/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties b/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties index ca3aed2263..1a689123cb 100644 --- a/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties +++ b/spring-cloud-modules/spring-cloud-bootstrap/application-config/zipkin.properties @@ -4,4 +4,4 @@ server.port=9411 eureka.client.region = default eureka.client.registryFetchIntervalSeconds = 5 -logging.level.org.springframework.web=debug +logging.level.org.springframework.web=INFO diff --git a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml index ba923c4ae6..3e2b1632c7 100644 --- a/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml +++ b/spring-cloud-modules/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/pom.xml @@ -46,7 +46,6 @@ 1.3.1.RELEASE Edgware.SR6 5.2.12.Final - 1.11.20 3.1.0 diff --git a/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..fb1f109a18 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties index aa0dc6a382..0a31d79ee0 100644 --- a/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties +++ b/spring-cloud-modules/spring-cloud-openfeign-2/src/main/resources/application.properties @@ -4,7 +4,7 @@ feign.okhttp.enabled=true server.port=8085 spring.main.allow-bean-definition-overriding=true -logging.level.com.baeldung.cloud.openfeign.client=DEBUG +logging.level.com.baeldung.cloud.openfeign.client=INFO feign.hystrix.enabled=true spring.cloud.openfeign.client.config.postClient.url=https://jsonplaceholder.typicode.com/posts/ \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..233cfa7e23 --- /dev/null +++ b/spring-cloud-modules/spring-cloud-stream/spring-cloud-stream-rabbit/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..2a5eefdd1f --- /dev/null +++ b/spring-cloud-modules/spring-cloud-task/springcloudtasksink/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml b/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..4ff950099a --- /dev/null +++ b/spring-cloud-modules/spring-cloud-zuul-fallback/spring-cloud-zuul-fallback-weather-service/src/test/resources/logback-test.xml @@ -0,0 +1,17 @@ + + + + + # Pattern of log message for console appender + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/spring-integration/src/test/resources/logback-test.xml b/spring-integration/src/test/resources/logback-test.xml index 8f1be4eb7a..98bfc86d71 100644 --- a/spring-integration/src/test/resources/logback-test.xml +++ b/spring-integration/src/test/resources/logback-test.xml @@ -9,6 +9,8 @@ + + diff --git a/spring-soap/.gitignore b/spring-soap/.gitignore index cce17abdb9..2b04fd0719 100644 --- a/spring-soap/.gitignore +++ b/spring-soap/.gitignore @@ -1,2 +1,4 @@ /target/ sun-jaxb.episode + +**/gen/** \ No newline at end of file diff --git a/spring-soap/pom.xml b/spring-soap/pom.xml index 8188178d61..594eb3dd19 100644 --- a/spring-soap/pom.xml +++ b/spring-soap/pom.xml @@ -30,6 +30,22 @@ spring-boot-starter-test test + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.0 + + + + org.glassfish.jaxb + jaxb-runtime + + + + javax.xml.bind + jaxb-api + @@ -42,7 +58,7 @@ org.codehaus.mojo jaxb2-maven-plugin - 1.6 + 3.1.0 xjc @@ -52,8 +68,10 @@ - ${project.basedir}/src/main/resources/ - ${project.basedir}/src/main/java + + src/main/resources/countries.xsd + + src/main/java false @@ -61,7 +79,7 @@ org.jvnet.jaxb2.maven2 maven-jaxb2-plugin - 0.14.0 + 0.15.3 @@ -83,4 +101,7 @@ + + 17 + \ No newline at end of file diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java b/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java index 745131767a..49020cec21 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/CountryEndpoint.java @@ -1,12 +1,14 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload; +import com.baeldung.springsoap.client.gen.GetCountryRequest; +import com.baeldung.springsoap.client.gen.GetCountryResponse; + @Endpoint public class CountryEndpoint { diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java b/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java index 8a0f58a64e..183027cdb6 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/CountryRepository.java @@ -1,12 +1,15 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.*; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; + import org.springframework.stereotype.Component; import org.springframework.util.Assert; -import javax.annotation.PostConstruct; -import java.util.HashMap; -import java.util.Map; +import com.baeldung.springsoap.client.gen.Country; +import com.baeldung.springsoap.client.gen.Currency; @Component public class CountryRepository { diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java b/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java index 930a961208..57636e9891 100644 --- a/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java +++ b/spring-soap/src/main/java/com/baeldung/springsoap/WebServiceConfig.java @@ -17,11 +17,11 @@ import org.springframework.xml.xsd.XsdSchema; public class WebServiceConfig extends WsConfigurerAdapter { @Bean - public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { + public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(applicationContext); servlet.setTransformWsdlLocations(true); - return new ServletRegistrationBean(servlet, "/ws/*"); + return new ServletRegistrationBean<>(servlet, "/ws/*"); } @Bean(name = "countries") diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java deleted file mode 100644 index bb196d625d..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Country.java +++ /dev/null @@ -1,139 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlSchemaType; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for country complex type. - * - *

The following schema fragment specifies the expected content contained within this class. - * - *

- * <complexType name="country">
- *   <complexContent>
- *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       <sequence>
- *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         <element name="population" type="{http://www.w3.org/2001/XMLSchema}int"/>
- *         <element name="capital" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *         <element name="currency" type="{http://www.baeldung.com/springsoap/gen}currency"/>
- *       </sequence>
- *     </restriction>
- *   </complexContent>
- * </complexType>
- * 
- * - * - */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlType(name = "country", propOrder = { - "name", - "population", - "capital", - "currency" -}) -public class Country { - - @XmlElement(required = true) - protected String name; - protected int population; - @XmlElement(required = true) - protected String capital; - @XmlElement(required = true) - @XmlSchemaType(name = "string") - protected Currency currency; - - /** - * Gets the value of the name property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getName() { - return name; - } - - /** - * Sets the value of the name property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setName(String value) { - this.name = value; - } - - /** - * Gets the value of the population property. - * - */ - public int getPopulation() { - return population; - } - - /** - * Sets the value of the population property. - * - */ - public void setPopulation(int value) { - this.population = value; - } - - /** - * Gets the value of the capital property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getCapital() { - return capital; - } - - /** - * Sets the value of the capital property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setCapital(String value) { - this.capital = value; - } - - /** - * Gets the value of the currency property. - * - * @return - * possible object is - * {@link Currency } - * - */ - public Currency getCurrency() { - return currency; - } - - /** - * Sets the value of the currency property. - * - * @param value - * allowed object is - * {@link Currency } - * - */ - public void setCurrency(Currency value) { - this.currency = value; - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java deleted file mode 100644 index 023a8103e5..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/Currency.java +++ /dev/null @@ -1,40 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlEnum; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for currency. - * - *

The following schema fragment specifies the expected content contained within this class. - *

- *

- * <simpleType name="currency">
- *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
- *     <enumeration value="GBP"/>
- *     <enumeration value="EUR"/>
- *     <enumeration value="PLN"/>
- *   </restriction>
- * </simpleType>
- * 
- * - */ -@XmlType(name = "currency") -@XmlEnum -public enum Currency { - - GBP, - EUR, - PLN; - - public String value() { - return name(); - } - - public static Currency fromValue(String v) { - return valueOf(v); - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java deleted file mode 100644 index dcd5b1f08b..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryRequest.java +++ /dev/null @@ -1,64 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for anonymous complex type. - * - *

The following schema fragment specifies the expected content contained within this class. - * - *

- * <complexType>
- *   <complexContent>
- *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       <sequence>
- *         <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
- *       </sequence>
- *     </restriction>
- *   </complexContent>
- * </complexType>
- * 
- * - * - */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlType(name = "", propOrder = { - "name" -}) -@XmlRootElement(name = "getCountryRequest") -public class GetCountryRequest { - - @XmlElement(required = true) - protected String name; - - /** - * Gets the value of the name property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getName() { - return name; - } - - /** - * Sets the value of the name property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setName(String value) { - this.name = value; - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java deleted file mode 100644 index 11135c32e1..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/GetCountryResponse.java +++ /dev/null @@ -1,64 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - - -/** - *

Java class for anonymous complex type. - * - *

The following schema fragment specifies the expected content contained within this class. - * - *

- * <complexType>
- *   <complexContent>
- *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
- *       <sequence>
- *         <element name="country" type="{http://www.baeldung.com/springsoap/gen}country"/>
- *       </sequence>
- *     </restriction>
- *   </complexContent>
- * </complexType>
- * 
- * - * - */ -@XmlAccessorType(XmlAccessType.FIELD) -@XmlType(name = "", propOrder = { - "country" -}) -@XmlRootElement(name = "getCountryResponse") -public class GetCountryResponse { - - @XmlElement(required = true) - protected Country country; - - /** - * Gets the value of the country property. - * - * @return - * possible object is - * {@link Country } - * - */ - public Country getCountry() { - return country; - } - - /** - * Sets the value of the country property. - * - * @param value - * allowed object is - * {@link Country } - * - */ - public void setCountry(Country value) { - this.country = value; - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java deleted file mode 100644 index e6d56d5aba..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/ObjectFactory.java +++ /dev/null @@ -1,56 +0,0 @@ - -package com.baeldung.springsoap.client.gen; - -import javax.xml.bind.annotation.XmlRegistry; - - -/** - * This object contains factory methods for each - * Java content interface and Java element interface - * generated in the com.baeldung.springsoap.client.gen package. - *

An ObjectFactory allows you to programatically - * construct new instances of the Java representation - * for XML content. The Java representation of XML - * content can consist of schema derived interfaces - * and classes representing the binding of schema - * type definitions, element declarations and model - * groups. Factory methods for each of these are - * provided in this class. - * - */ -@XmlRegistry -public class ObjectFactory { - - - /** - * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.baeldung.springsoap.client.gen - * - */ - public ObjectFactory() { - } - - /** - * Create an instance of {@link GetCountryRequest } - * - */ - public GetCountryRequest createGetCountryRequest() { - return new GetCountryRequest(); - } - - /** - * Create an instance of {@link GetCountryResponse } - * - */ - public GetCountryResponse createGetCountryResponse() { - return new GetCountryResponse(); - } - - /** - * Create an instance of {@link Country } - * - */ - public Country createCountry() { - return new Country(); - } - -} diff --git a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java b/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java deleted file mode 100644 index 9432e0c328..0000000000 --- a/spring-soap/src/main/java/com/baeldung/springsoap/client/gen/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.baeldung.com/springsoap/gen", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) -package com.baeldung.springsoap.client.gen; diff --git a/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java b/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java index 3b071c286f..1150b8d91b 100644 --- a/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java +++ b/spring-soap/src/test/java/com/baeldung/springsoap/ApplicationIntegrationTest.java @@ -1,18 +1,19 @@ package com.baeldung.springsoap; -import com.baeldung.springsoap.gen.GetCountryRequest; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.ClassUtils; import org.springframework.ws.client.core.WebServiceTemplate; -import static org.assertj.core.api.Assertions.assertThat; +import com.baeldung.springsoap.client.gen.GetCountryRequest; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @@ -20,7 +21,8 @@ public class ApplicationIntegrationTest { private Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); - @LocalServerPort private int port = 0; + @LocalServerPort + private int port = 0; @Before public void init() throws Exception { @@ -34,6 +36,8 @@ public class ApplicationIntegrationTest { GetCountryRequest request = new GetCountryRequest(); request.setName("Spain"); - assertThat(ws.marshalSendAndReceive("http://localhost:" + port + "/ws", request)).isNotNull(); + Object response = ws.marshalSendAndReceive("http://localhost:" + port + "/ws", request); + + assertThat(response).isNotNull(); } }