From 4331871e09966b5521600c9076617c7ad465b4b9 Mon Sep 17 00:00:00 2001 From: Markus Gulden Date: Tue, 2 Jan 2018 15:21:09 +0100 Subject: [PATCH 01/48] BAEL-592 Guide to Hibernate 5 with Spring --- .../hibernate/bootstrap/BarHibernateDAO.java | 39 ++++++++++++ .../hibernate/bootstrap/HibernateConf.java | 61 +++++++++++++++++++ .../hibernate/bootstrap/HibernateXMLConf.java | 24 ++++++++ .../hibernate/bootstrap/model/TestEntity.java | 29 +++++++++ .../resources/hibernate5Configuration.xml | 30 +++++++++ .../main/resources/persistence-h2.properties | 1 + .../HibernateBootstrapIntegrationTest.java | 38 ++++++++++++ .../HibernateXMLBootstrapIntegrationTest.java | 36 +++++++++++ 8 files changed, 258 insertions(+) create mode 100644 persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/BarHibernateDAO.java create mode 100644 persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateConf.java create mode 100644 persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java create mode 100644 persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java create mode 100644 persistence-modules/spring-hibernate-5/src/main/resources/hibernate5Configuration.xml create mode 100644 persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java create mode 100644 persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/BarHibernateDAO.java b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/BarHibernateDAO.java new file mode 100644 index 0000000000..5fc932b256 --- /dev/null +++ b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/BarHibernateDAO.java @@ -0,0 +1,39 @@ +package com.baeldung.hibernate.bootstrap; + +import com.baeldung.hibernate.bootstrap.model.TestEntity; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class BarHibernateDAO { + + @Autowired + private SessionFactory sessionFactory; + + public TestEntity findEntity(int id) { + + return getCurrentSession().find(TestEntity.class, 1); + } + + public void createEntity(TestEntity entity) { + + getCurrentSession().save(entity); + } + + public void createEntity(int id, String newDescription) { + + TestEntity entity = findEntity(id); + entity.setDescription(newDescription); + getCurrentSession().save(entity); + } + + public void deleteEntity(int id) { + + TestEntity entity = findEntity(id); + getCurrentSession().delete(entity); + } + + protected Session getCurrentSession() { + return sessionFactory.getCurrentSession(); + } +} diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateConf.java b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateConf.java new file mode 100644 index 0000000000..150e3778af --- /dev/null +++ b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateConf.java @@ -0,0 +1,61 @@ +package com.baeldung.hibernate.bootstrap; + +import com.google.common.base.Preconditions; +import org.apache.tomcat.dbcp.dbcp2.BasicDataSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.orm.hibernate5.HibernateTransactionManager; +import org.springframework.orm.hibernate5.LocalSessionFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.util.Properties; + +@Configuration +@EnableTransactionManagement +@PropertySource({ "classpath:persistence-h2.properties" }) +public class HibernateConf { + + @Autowired + private Environment env; + + @Bean + public LocalSessionFactoryBean sessionFactory() { + final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); + sessionFactory.setDataSource(dataSource()); + sessionFactory.setPackagesToScan(new String[] { "com.baeldung.hibernate.bootstrap.model" }); + sessionFactory.setHibernateProperties(hibernateProperties()); + + return sessionFactory; + } + + @Bean + public DataSource dataSource() { + final BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName"))); + dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url"))); + dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user"))); + dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass"))); + + return dataSource; + } + + @Bean + public PlatformTransactionManager hibernateTransactionManager() { + final HibernateTransactionManager transactionManager = new HibernateTransactionManager(); + transactionManager.setSessionFactory(sessionFactory().getObject()); + return transactionManager; + } + + private final Properties hibernateProperties() { + final Properties hibernateProperties = new Properties(); + hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); + + return hibernateProperties; + } +} diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java new file mode 100644 index 0000000000..b3e979478f --- /dev/null +++ b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/HibernateXMLConf.java @@ -0,0 +1,24 @@ +package com.baeldung.hibernate.bootstrap; + +import com.google.common.base.Preconditions; +import org.apache.tomcat.dbcp.dbcp2.BasicDataSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.orm.hibernate5.HibernateTransactionManager; +import org.springframework.orm.hibernate5.LocalSessionFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.util.Properties; + +@Configuration +@EnableTransactionManagement +@ImportResource({ "classpath:hibernate5Configuration.xml" }) +public class HibernateXMLConf { + +} diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java new file mode 100644 index 0000000000..cae41db831 --- /dev/null +++ b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/hibernate/bootstrap/model/TestEntity.java @@ -0,0 +1,29 @@ +package com.baeldung.hibernate.bootstrap.model; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class TestEntity { + + private int id; + + private String description; + + @Id + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/persistence-modules/spring-hibernate-5/src/main/resources/hibernate5Configuration.xml b/persistence-modules/spring-hibernate-5/src/main/resources/hibernate5Configuration.xml new file mode 100644 index 0000000000..cb6cf0aa5c --- /dev/null +++ b/persistence-modules/spring-hibernate-5/src/main/resources/hibernate5Configuration.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + ${hibernate.hbm2ddl.auto} + ${hibernate.dialect} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-5/src/main/resources/persistence-h2.properties b/persistence-modules/spring-hibernate-5/src/main/resources/persistence-h2.properties index 915bc4317b..0325174b67 100644 --- a/persistence-modules/spring-hibernate-5/src/main/resources/persistence-h2.properties +++ b/persistence-modules/spring-hibernate-5/src/main/resources/persistence-h2.properties @@ -2,6 +2,7 @@ jdbc.driverClassName=org.h2.Driver jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 jdbc.eventGeneratedId=sa +jdbc.user=sa jdbc.pass=sa # hibernate.X diff --git a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java b/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java new file mode 100644 index 0000000000..ffe82b7ced --- /dev/null +++ b/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java @@ -0,0 +1,38 @@ +package com.baeldung.hibernate.bootstrap; + +import com.baeldung.hibernate.bootstrap.model.TestEntity; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.springframework.transaction.annotation.Transactional; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { HibernateConf.class }) +@Transactional +public class HibernateBootstrapIntegrationTest { + + @Autowired + private SessionFactory sessionFactory; + + @Test + public void whenBootstrapHibernateSession_thenNoException() { + + Session session = sessionFactory.getCurrentSession(); + + TestEntity newEntity = new TestEntity(); + newEntity.setId(1); + session.save(newEntity); + + TestEntity searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNotNull(searchEntity); + } + +} diff --git a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java b/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java new file mode 100644 index 0000000000..5b811ad576 --- /dev/null +++ b/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateXMLBootstrapIntegrationTest.java @@ -0,0 +1,36 @@ +package com.baeldung.hibernate.bootstrap; + +import com.baeldung.hibernate.bootstrap.model.TestEntity; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.annotation.Transactional; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { HibernateXMLConf.class }) +@Transactional +public class HibernateXMLBootstrapIntegrationTest { + + @Autowired + private SessionFactory sessionFactory; + + @Test + public void whenBootstrapHibernateSession_thenNoException() { + + Session session = sessionFactory.getCurrentSession(); + + TestEntity newEntity = new TestEntity(); + newEntity.setId(1); + session.save(newEntity); + + TestEntity searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNotNull(searchEntity); + } + +} From 02b0c1d2933ee636241ae1446773af770f68dd13 Mon Sep 17 00:00:00 2001 From: Markus Gulden Date: Thu, 4 Jan 2018 10:26:48 +0100 Subject: [PATCH 02/48] BAEL-592: Upgrade to Spring 5 --- persistence-modules/spring-hibernate-5/pom.xml | 2 +- .../com/baeldung/manytomany/spring/PersistenceConfig.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/persistence-modules/spring-hibernate-5/pom.xml b/persistence-modules/spring-hibernate-5/pom.xml index 88db38b2fc..86e952c0e4 100644 --- a/persistence-modules/spring-hibernate-5/pom.xml +++ b/persistence-modules/spring-hibernate-5/pom.xml @@ -179,7 +179,7 @@ - 4.3.10.RELEASE + 5.0.2.RELEASE 1.10.6.RELEASE diff --git a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/manytomany/spring/PersistenceConfig.java b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/manytomany/spring/PersistenceConfig.java index 6f359054b6..5dace1f742 100644 --- a/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/manytomany/spring/PersistenceConfig.java +++ b/persistence-modules/spring-hibernate-5/src/main/java/com/baeldung/manytomany/spring/PersistenceConfig.java @@ -10,8 +10,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; -import org.springframework.orm.hibernate4.HibernateTransactionManager; -import org.springframework.orm.hibernate4.LocalSessionFactoryBean; +import org.springframework.orm.hibernate5.HibernateTransactionManager; +import org.springframework.orm.hibernate5.LocalSessionFactoryBean; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; From 369ec4e181bee2df90e96b4edac5b26a6c6cc04b Mon Sep 17 00:00:00 2001 From: Adi Date: Fri, 19 Jan 2018 00:06:57 +0200 Subject: [PATCH 03/48] BAEL-1267: programmatically create, configure and run a tomcat server --- libraries/pom.xml | 33 ++++++++++ .../java/com/baeldung/tomcat/MyFilter.java | 31 +++++++++ .../java/com/baeldung/tomcat/MyServlet.java | 25 ++++++++ .../baeldung/tomcat/ProgrammaticTomcat.java | 63 +++++++++++++++++++ .../tomcat/ProgrammaticTomcatTest.java | 62 ++++++++++++++++++ 5 files changed, 214 insertions(+) create mode 100644 libraries/src/main/java/com/baeldung/tomcat/MyFilter.java create mode 100644 libraries/src/main/java/com/baeldung/tomcat/MyServlet.java create mode 100644 libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java create mode 100644 libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java diff --git a/libraries/pom.xml b/libraries/pom.xml index 09c8cb8335..404c8fa397 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -705,6 +705,38 @@ test test + + + + org.apache.tomcat + tomcat-catalina + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-jasper + ${tomcat.version} + + + org.apache.tomcat + tomcat-jasper + ${tomcat.version} + + + org.apache.tomcat + tomcat-jasper-el + ${tomcat.version} + + + org.apache.tomcat + tomcat-jsp-api + ${tomcat.version} + @@ -786,5 +818,6 @@ v4-rev493-1.21.0 1.0.0 3.0.14 + 8.5.24 \ No newline at end of file diff --git a/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java b/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java new file mode 100644 index 0000000000..9cf4a0ed95 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java @@ -0,0 +1,31 @@ +package com.baeldung.tomcat; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by adi on 1/14/18. + */ +@WebFilter(urlPatterns = "/my-servlet/*") +public class MyFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + System.out.println("Filtering stuff..."); + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.addHeader("myHeader", "myHeaderValue"); + chain.doFilter(request, httpResponse); + } + + @Override + public void destroy() { + + } +} diff --git a/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java b/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java new file mode 100644 index 0000000000..4bbf3c03a7 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java @@ -0,0 +1,25 @@ +package com.baeldung.tomcat; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by adi on 1/10/18. + */ +@WebServlet( + name = "com.baeldung.tomcat.programmatic.MyServlet", + urlPatterns = {"/my-servlet"} +) +public class MyServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.setStatus(HttpServletResponse.SC_OK); + resp.getWriter().write("test"); + resp.getWriter().flush(); + resp.getWriter().close(); + } +} diff --git a/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java b/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java new file mode 100644 index 0000000000..b84b6b5c6d --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java @@ -0,0 +1,63 @@ +package com.baeldung.tomcat; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.startup.Tomcat; +import org.apache.tomcat.util.descriptor.web.FilterDef; +import org.apache.tomcat.util.descriptor.web.FilterMap; + +import java.io.File; + +/** + * Created by adi on 1/10/18. + */ +public class ProgrammaticTomcat { + + private Tomcat tomcat = null; + + //uncomment for live test + // public static void main(String[] args) throws LifecycleException, ServletException, URISyntaxException, IOException { + // startTomcat(); + // } + + public void startTomcat() throws LifecycleException { + tomcat = new Tomcat(); + tomcat.setPort(8080); + tomcat.setHostname("localhost"); + String appBase = "."; + tomcat + .getHost() + .setAppBase(appBase); + + File docBase = new File(System.getProperty("java.io.tmpdir")); + Context context = tomcat.addContext("", docBase.getAbsolutePath()); + + //add a servlet + Class servletClass = MyServlet.class; + Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName()); + context.addServletMappingDecoded("/my-servlet/*", servletClass.getSimpleName()); + + //add a filter and filterMapping + Class filterClass = MyFilter.class; + FilterDef myFilterDef = new FilterDef(); + myFilterDef.setFilterClass(filterClass.getName()); + myFilterDef.setFilterName(filterClass.getSimpleName()); + context.addFilterDef(myFilterDef); + + FilterMap myFilterMap = new FilterMap(); + myFilterMap.setFilterName(filterClass.getSimpleName()); + myFilterMap.addURLPattern("/my-servlet/*"); + context.addFilterMap(myFilterMap); + + tomcat.start(); + //uncomment for live test + // tomcat + // .getServer() + // .await(); + } + + public void stopTomcat() throws LifecycleException { + tomcat.stop(); + tomcat.destroy(); + } +} diff --git a/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java b/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java new file mode 100644 index 0000000000..d559c3d408 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java @@ -0,0 +1,62 @@ +package com.baeldung.tomcat; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + + +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Created by adi on 1/14/18. + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class ProgrammaticTomcatTest { + + private ProgrammaticTomcat tomcat = new ProgrammaticTomcat(); + + @Before + public void setUp() throws Exception { + tomcat.startTomcat(); + } + + @After + public void tearDown() throws Exception { + tomcat.stopTomcat(); + } + + @Test + public void givenTomcatStarted_whenAccessServlet_responseIsTestAndResponseHeaderIsSet() throws Exception { + CloseableHttpClient httpClient = HttpClientBuilder + .create() + .build(); + HttpGet getServlet = new HttpGet("http://localhost:8080/my-servlet"); + + HttpResponse response = httpClient.execute(getServlet); + assertEquals(HttpStatus.SC_OK, response + .getStatusLine() + .getStatusCode()); + + String myHeaderValue = response + .getFirstHeader("myHeader") + .getValue(); + assertEquals("myHeaderValue", myHeaderValue); + + HttpEntity responseEntity = response.getEntity(); + assertNotNull(responseEntity); + + String responseString = EntityUtils.toString(responseEntity, "UTF-8"); + assertEquals("test", responseString); + } + +} From 3f3204e14f9e13dcf174c12894ae53d34ae1dac1 Mon Sep 17 00:00:00 2001 From: Adi Date: Fri, 26 Jan 2018 21:18:17 +0200 Subject: [PATCH 04/48] BAEL-1267: programmatically create, configure and run a tomcat server - remove unused dependencies --- libraries/pom.xml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/libraries/pom.xml b/libraries/pom.xml index 404c8fa397..6c0e6c2577 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -712,31 +712,6 @@ tomcat-catalina ${tomcat.version} - - org.apache.tomcat.embed - tomcat-embed-core - ${tomcat.version} - - - org.apache.tomcat.embed - tomcat-embed-jasper - ${tomcat.version} - - - org.apache.tomcat - tomcat-jasper - ${tomcat.version} - - - org.apache.tomcat - tomcat-jasper-el - ${tomcat.version} - - - org.apache.tomcat - tomcat-jsp-api - ${tomcat.version} - From 81e8da29a402f0cb8fd1c362ce249271b1e94f5d Mon Sep 17 00:00:00 2001 From: Markus Gulden Date: Sat, 27 Jan 2018 11:14:14 +0100 Subject: [PATCH 05/48] BAEL-1335 --- javaxval/pom.xml | 15 +- .../MethodValidationConfig.java | 38 ++++ .../ConsistentDateParameterValidator.java | 32 +++ .../constraints/ConsistentDateParameters.java | 23 ++ .../constraints/ValidReservation.java | 24 +++ .../ValidReservationValidator.java | 40 ++++ .../methodvalidation/model/Customer.java | 41 ++++ .../methodvalidation/model/Reservation.java | 60 ++++++ .../model/ReservationManagement.java | 50 +++++ .../ContainerValidationIntegrationTest.java | 86 ++++++++ .../ValidationIntegrationTest.java | 199 ++++++++++++++++++ 11 files changed, 606 insertions(+), 2 deletions(-) create mode 100644 javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java create mode 100644 javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java create mode 100644 javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java create mode 100644 javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java create mode 100644 javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java create mode 100644 javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java create mode 100644 javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java create mode 100644 javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java create mode 100644 javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java create mode 100644 javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java diff --git a/javaxval/pom.xml b/javaxval/pom.xml index 6a83a25f01..0891fe6959 100644 --- a/javaxval/pom.xml +++ b/javaxval/pom.xml @@ -6,10 +6,11 @@ 0.1-SNAPSHOT - 2.0.0.Final - 6.0.2.Final + 2.0.1.Final + 6.0.7.Final 3.0.0 2.2.6 + 5.0.2.RELEASE @@ -50,6 +51,16 @@ javax.el ${javax.el.version} + + org.springframework + spring-context + ${org.springframework.version} + + + org.springframework + spring-test + ${org.springframework.version} + diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java new file mode 100644 index 0000000000..206a145337 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java @@ -0,0 +1,38 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import java.time.LocalDate; + +@Configuration +@ComponentScan({ "org.baeldung.javaxval.methodvalidation.model" }) +public class MethodValidationConfig { + + @Bean + public MethodValidationPostProcessor methodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + + @Bean("customer") + @Scope(BeanDefinition.SCOPE_PROTOTYPE) + public Customer customer(String firstName, String lastName) { + + Customer customer = new Customer(firstName, lastName); + return customer; + } + + @Bean("reservation") + @Scope(BeanDefinition.SCOPE_PROTOTYPE) + public Reservation reservation(LocalDate begin, LocalDate end, Customer customer, int room) { + + Reservation reservation = new Reservation(begin, end, customer, room); + return reservation; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java new file mode 100644 index 0000000000..b28abcba45 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java @@ -0,0 +1,32 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraintvalidation.SupportedValidationTarget; +import javax.validation.constraintvalidation.ValidationTarget; +import java.time.LocalDate; + +@SupportedValidationTarget(ValidationTarget.PARAMETERS) +public class ConsistentDateParameterValidator implements ConstraintValidator { + + @Override + public void initialize(ConsistentDateParameters constraintAnnotation) { + } + + @Override + public boolean isValid(Object[] value, ConstraintValidatorContext context) { + if (value.length != 4 && value.length != 3) { + throw new IllegalArgumentException("Illegal method signature"); + } + + if (value[0] == null || value[1] == null) { + return false; + } + + if (!(value[0] instanceof LocalDate) || !(value[1] instanceof LocalDate)) { + throw new IllegalArgumentException("Illegal method signature, expected two parameters of type LocalDate."); + } + + return ((LocalDate) value[0]).isBefore((LocalDate) value[1]); + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java new file mode 100644 index 0000000000..6b321f545c --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java @@ -0,0 +1,23 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Constraint(validatedBy = ConsistentDateParameterValidator.class) +@Target({ METHOD, CONSTRUCTOR }) +@Retention(RUNTIME) +@Documented +public @interface ConsistentDateParameters { + + String message() default "End date must be after begin date and both must be in the future"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java new file mode 100644 index 0000000000..f9cdea1483 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java @@ -0,0 +1,24 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Constraint(validatedBy = ValidReservationValidator.class) +@Target({ METHOD, CONSTRUCTOR }) +@Retention(RUNTIME) +@Documented +public @interface ValidReservation { + + String message() default "End date must be after begin date and both must be in the future, room number must be bigger than 0"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java new file mode 100644 index 0000000000..1da257044b --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java @@ -0,0 +1,40 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import org.baeldung.javaxval.methodvalidation.model.Reservation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.time.LocalDate; + +public class ValidReservationValidator implements ConstraintValidator { + + @Override + public void initialize(ValidReservation constraintAnnotation) { + } + + @Override + public boolean isValid(Reservation reservation, ConstraintValidatorContext context) { + + if (reservation == null) { + return true; + } + + if (!(reservation instanceof Reservation)) { + throw new IllegalArgumentException("Illegal method signature, expected parameter of type Reservation."); + } + + if (reservation.getBegin() == null || reservation.getEnd() == null || reservation.getCustomer() == null) { + return false; + } + + if (reservation.getBegin() + .isAfter(LocalDate.now()) + && reservation.getBegin() + .isBefore(reservation.getEnd()) + && reservation.getRoom() > 0) { + + return true; + } + return false; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java new file mode 100644 index 0000000000..529cf436da --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java @@ -0,0 +1,41 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Validated +public class Customer { + + @Size(min = 5, max = 200) + private String firstName; + + @Size(min = 5, max = 200) + private String lastName; + + public Customer(@Size(min = 5, max = 200) @NotNull String firstName, @Size(min = 5, max = 200) String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public Customer() { + + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java new file mode 100644 index 0000000000..89f13e9e37 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java @@ -0,0 +1,60 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.baeldung.javaxval.methodvalidation.constraints.ConsistentDateParameters; +import org.baeldung.javaxval.methodvalidation.constraints.ValidReservation; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDate; + +@Validated +public class Reservation { + + private LocalDate begin; + + private LocalDate end; + + private Customer customer; + + private int room; + + @ConsistentDateParameters + @ValidReservation + public Reservation(LocalDate begin, LocalDate end, Customer customer, int room) { + this.begin = begin; + this.end = end; + this.customer = customer; + this.room = room; + } + + public LocalDate getBegin() { + return begin; + } + + public void setBegin(LocalDate begin) { + this.begin = begin; + } + + public LocalDate getEnd() { + return end; + } + + public void setEnd(LocalDate end) { + this.end = end; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public int getRoom() { + return room; + } + + public void setRoom(int room) { + this.room = room; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java new file mode 100644 index 0000000000..0aeeb52e1f --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java @@ -0,0 +1,50 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.baeldung.javaxval.methodvalidation.constraints.ConsistentDateParameters; +import org.baeldung.javaxval.methodvalidation.constraints.ValidReservation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.time.LocalDate; +import java.util.List; + +@Controller +@Validated +public class ReservationManagement { + + @Autowired + private ApplicationContext applicationContext; + + @ConsistentDateParameters + public void createReservation(LocalDate begin, LocalDate end, @NotNull Customer customer) { + + // ... + } + + public void createReservation(@NotNull @Future LocalDate begin, @Min(1) int duration, @NotNull Customer customer) { + + // ... + } + + @NotNull + @Size(min = 1) + public List<@NotNull Customer> getAllCustomers() { + + return null; + } + + public void createNewCustomer(@Valid Customer customer) { + + // ... + } + + @Valid + public Customer getCustomerById() { + + return null; + } +} diff --git a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java new file mode 100644 index 0000000000..53133edd48 --- /dev/null +++ b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java @@ -0,0 +1,86 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.ReservationManagement; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import javax.validation.ConstraintViolationException; +import java.time.LocalDate; +import java.util.List; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { MethodValidationConfig.class }, loader = AnnotationConfigContextLoader.class) +public class ContainerValidationIntegrationTest { + + @Autowired + ReservationManagement reservationManagement; + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void whenValidationWithInvalidMethodParameters_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + reservationManagement.createReservation(LocalDate.now(), 0, null); + } + + @Test + public void whenValidationWithValidMethodParameters_thenNoException() { + + reservationManagement.createReservation(LocalDate.now() + .plusDays(1), 1, new Customer("William", "Smith")); + } + + @Test + public void whenCrossParameterValidationWithInvalidParameters_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + reservationManagement.createReservation(LocalDate.now(), LocalDate.now(), null); + } + + @Test + public void whenCrossParameterValidationWithValidParameters_thenNoException() { + + reservationManagement.createReservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith")); + } + + @Test + public void whenValidationWithInvalidReturnValue_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + List list = reservationManagement.getAllCustomers(); + } + + @Test + public void whenValidationWithInvalidCascadedValue_thenConstraintViolationException() { + + Customer customer = new Customer(); + customer.setFirstName("John"); + customer.setLastName("Doe"); + + exception.expect(ConstraintViolationException.class); + reservationManagement.createNewCustomer(customer); + } + + @Test + public void whenValidationWithValidCascadedValue_thenCNoException() { + + Customer customer = new Customer(); + customer.setFirstName("William"); + customer.setLastName("Smith"); + + reservationManagement.createNewCustomer(customer); + } +} diff --git a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java new file mode 100644 index 0000000000..6a750698c6 --- /dev/null +++ b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java @@ -0,0 +1,199 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; +import org.baeldung.javaxval.methodvalidation.model.ReservationManagement; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.ValidatorFactory; +import javax.validation.executable.ExecutableValidator; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.time.LocalDate; +import java.util.Collections; +import java.util.Set; + +public class ValidationIntegrationTest { + + private ExecutableValidator executableValidator; + + @Before + public void getExecutableValidator() { + + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + this.executableValidator = factory.getValidator() + .forExecutables(); + } + + @Test + public void whenValidationWithInvalidMethodParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, int.class, Customer.class); + Object[] parameterValues = { LocalDate.now(), 0, null }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(3, violations.size()); + } + + @Test + public void whenValidationWithValidMethodParameters_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, int.class, Customer.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), 1, new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithInvalidParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, LocalDate.class, Customer.class); + Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(1, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithValidParameters_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, LocalDate.class, Customer.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Customer.class.getConstructor(String.class, String.class); + Object[] parameterValues = { "John", "Doe" }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(2, violations.size()); + } + + @Test + public void whenValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Customer.class.getConstructor(String.class, String.class); + Object[] parameterValues = { "William", "Smith" }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 1 }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(1, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith"), 1 }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("getAllCustomers"); + Object returnValue = Collections. emptyList(); + Set> violations = executableValidator.validateReturnValue(object, method, returnValue); + + assertEquals(1, violations.size()); + } + + @Test + public void whenValidationWithValidReturnValue_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("getAllCustomers"); + Object returnValue = Collections.singletonList(new Customer("William", "Smith")); + Set> violations = executableValidator.validateReturnValue(object, method, returnValue); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidConstructorReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Reservation createdObject = new Reservation(LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 0); + Set> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject); + + assertEquals(1, violations.size()); + } + + @Test + public void whenValidationWithValidConstructorReturnValue_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Reservation createdObject = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith"), 1); + Set> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createNewCustomer", Customer.class); + Customer customer = new Customer(); + customer.setFirstName("John"); + customer.setLastName("Doe"); + Object[] parameterValues = { customer }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(2, violations.size()); + } + + @Test + public void whenValidationWithValidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createNewCustomer", Customer.class); + Customer customer = new Customer(); + customer.setFirstName("William"); + customer.setLastName("Smith"); + Object[] parameterValues = { customer }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + +} From 6e23e8f4fdc8bf1b1e37570c6d69fad80cef781d Mon Sep 17 00:00:00 2001 From: Nam Thai Nguyen Date: Thu, 1 Feb 2018 03:16:53 +0700 Subject: [PATCH 06/48] Initial commit for BAEL-1516 --- .../com/baeldung/testing/assertj/Member.java | 19 +++++ .../assertj/AssertJConditionUnitTest.java | 72 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java create mode 100644 testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java diff --git a/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java new file mode 100644 index 0000000000..a0b3d0daac --- /dev/null +++ b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java @@ -0,0 +1,19 @@ +package com.baeldung.testing.assertj; + +public class Member { + private String name; + private int age; + + public Member(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java new file mode 100644 index 0000000000..153af828f1 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.testing.assertj; + +import static org.assertj.core.api.Assertions.allOf; +import static org.assertj.core.api.Assertions.anyOf; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.not; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import org.assertj.core.api.Condition; +import org.junit.Test; + +public class AssertJConditionUnitTest { + private Condition senior = new Condition<>(m -> m.getAge() >= 60, "senior"); + private Condition nameJohn = new Condition<>(m -> m.getName().equalsIgnoreCase("John"), "name John"); + + @Test + public void whenUsingMemberAgeCondition_thenCorrect() { + Member member = new Member("John", 65); + assertThat(member).is(senior); + + try { + assertThat(member).isNot(senior); + fail(); + } catch (AssertionError e) { + assertThat(e).hasMessageContaining("not to be "); + } + } + + @Test + public void whenUsingMemberNameCondition_thenCorrect() { + Member member = new Member("Jane", 60); + assertThat(member).doesNotHave(nameJohn); + + try { + assertThat(member).has(nameJohn); + fail(); + } catch (AssertionError e) { + assertThat(e).hasMessageContaining("to have:\n "); + } + } + + @Test + public void whenCollectionConditionsAreSatisfied_thenCorrect() { + List members = new ArrayList<>(); + members.add(new Member("Alice", 50)); + members.add(new Member("Bob", 60)); + + assertThat(members).haveExactly(1, senior); + assertThat(members).doNotHave(nameJohn); + } + + @Test + public void whenCombiningAllOfConditions_thenCorrect() { + Member john = new Member("John", 60); + Member jane = new Member("Jane", 50); + + assertThat(john).is(allOf(senior, nameJohn)); + assertThat(jane).is(allOf(not(nameJohn), not(senior))); + } + + @Test + public void whenCombiningAnyOfConditions_thenCorrect() { + Member john = new Member("John", 50); + Member jane = new Member("Jane", 60); + + assertThat(john).is(anyOf(senior, nameJohn)); + assertThat(jane).is(anyOf(nameJohn, senior)); + } +} From b9ac0dc78b8e51e0bda526b420746227ab53eff3 Mon Sep 17 00:00:00 2001 From: Markus Gulden Date: Sat, 3 Feb 2018 12:51:59 +0100 Subject: [PATCH 07/48] Updates after editor feedback --- .../ConsistentDateParameterValidator.java | 5 +---- .../constraints/ValidReservationValidator.java | 2 +- .../methodvalidation/model/Reservation.java | 4 ++++ .../model/ReservationManagement.java | 12 ++++++------ .../ContainerValidationIntegrationTest.java | 15 +++++++++++++-- .../ValidationIntegrationTest.java | 18 ++++++++++++++---- 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java index b28abcba45..0ee1b6eda1 100644 --- a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java @@ -15,9 +15,6 @@ public class ConsistentDateParameterValidator implements ConstraintValidator getAllCustomers() { @@ -37,13 +42,8 @@ public class ReservationManagement { return null; } - public void createNewCustomer(@Valid Customer customer) { - - // ... - } - @Valid - public Customer getCustomerById() { + public Reservation getReservationById(int id) { return null; } diff --git a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java index 53133edd48..2363bf8f5d 100644 --- a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java +++ b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java @@ -1,6 +1,7 @@ package org.baeldung.javaxval.methodvalidation; import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; import org.baeldung.javaxval.methodvalidation.model.ReservationManagement; import org.junit.Rule; import org.junit.Test; @@ -69,9 +70,14 @@ public class ContainerValidationIntegrationTest { Customer customer = new Customer(); customer.setFirstName("John"); customer.setLastName("Doe"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); exception.expect(ConstraintViolationException.class); - reservationManagement.createNewCustomer(customer); + reservationManagement.createReservation(reservation); } @Test @@ -80,7 +86,12 @@ public class ContainerValidationIntegrationTest { Customer customer = new Customer(); customer.setFirstName("William"); customer.setLastName("Smith"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); - reservationManagement.createNewCustomer(customer); + reservationManagement.createReservation(reservation); } } diff --git a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java index 6a750698c6..6b53d3a107 100644 --- a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java +++ b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java @@ -172,11 +172,16 @@ public class ValidationIntegrationTest { public void whenValidationWithInvalidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { ReservationManagement object = new ReservationManagement(); - Method method = ReservationManagement.class.getMethod("createNewCustomer", Customer.class); + Method method = ReservationManagement.class.getMethod("createReservation", Reservation.class); Customer customer = new Customer(); customer.setFirstName("John"); customer.setLastName("Doe"); - Object[] parameterValues = { customer }; + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + Object[] parameterValues = { reservation }; Set> violations = executableValidator.validateParameters(object, method, parameterValues); assertEquals(2, violations.size()); @@ -186,11 +191,16 @@ public class ValidationIntegrationTest { public void whenValidationWithValidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { ReservationManagement object = new ReservationManagement(); - Method method = ReservationManagement.class.getMethod("createNewCustomer", Customer.class); + Method method = ReservationManagement.class.getMethod("createReservation", Reservation.class); Customer customer = new Customer(); customer.setFirstName("William"); customer.setLastName("Smith"); - Object[] parameterValues = { customer }; + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + Object[] parameterValues = { reservation }; Set> violations = executableValidator.validateParameters(object, method, parameterValues); assertEquals(0, violations.size()); From e15f2fc7dd347b42dbf414747cac8aa11e3c0b86 Mon Sep 17 00:00:00 2001 From: Markus Gulden Date: Sat, 3 Feb 2018 13:10:31 +0100 Subject: [PATCH 08/48] Updates after editor feedback --- .../constraints/ValidReservationValidator.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java index a1cba9a5f6..fc225999be 100644 --- a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java @@ -27,14 +27,10 @@ public class ValidReservationValidator implements ConstraintValidator 0) { - - return true; - } - return false; + && reservation.getRoom() > 0); } } From 5a31640528ac3e7fce5314b06e194077b0cccd4b Mon Sep 17 00:00:00 2001 From: Markus Gulden Date: Sat, 3 Feb 2018 13:30:52 +0100 Subject: [PATCH 09/48] Updates after editor feedback --- .../org/baeldung/javaxval/methodvalidation/model/Customer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java index 529cf436da..fe9ad7080e 100644 --- a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java @@ -14,7 +14,7 @@ public class Customer { @Size(min = 5, max = 200) private String lastName; - public Customer(@Size(min = 5, max = 200) @NotNull String firstName, @Size(min = 5, max = 200) String lastName) { + public Customer(@Size(min = 5, max = 200) @NotNull String firstName, @Size(min = 5, max = 200) @NotNull String lastName) { this.firstName = firstName; this.lastName = lastName; } From 53bb9276100b3714cdf08cc49de91e17dc172a7e Mon Sep 17 00:00:00 2001 From: Nam Thai Nguyen Date: Sat, 3 Feb 2018 20:21:46 +0700 Subject: [PATCH 10/48] Modifies the Data class --- .../main/java/com/baeldung/javac/Data.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/core-java/src/main/java/com/baeldung/javac/Data.java b/core-java/src/main/java/com/baeldung/javac/Data.java index f6912fbd14..feef0c4f1e 100644 --- a/core-java/src/main/java/com/baeldung/javac/Data.java +++ b/core-java/src/main/java/com/baeldung/javac/Data.java @@ -1,28 +1,16 @@ package com.baeldung.javac; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; -public class Data implements Serializable { - static List textList = new ArrayList(); +public class Data { + List textList = new ArrayList(); - private static void addText() { - textList.add("baeldung"); - textList.add("."); - textList.add("com"); + public void addText(String text) { + textList.add(text); } public List getTextList() { - this.addText(); - List result = new ArrayList(); - String firstElement = (String) textList.get(0); - switch (firstElement) { - case "baeldung": - result.add("baeldung"); - case "com": - result.add("com"); - } - return result; + return this.textList; } -} +} \ No newline at end of file From ecf1cae3f7802bfb52e60777c95e9312ff7a5a53 Mon Sep 17 00:00:00 2001 From: Marcos Date: Sat, 3 Feb 2018 19:01:20 +0100 Subject: [PATCH 11/48] JPA Attribute Converters --- .../com/baeldung/hibernate/HibernateUtil.java | 1 + .../converters/PersonNameConverter.java | 43 +++++++++++ .../com/baeldung/hibernate/pojo/Person.java | 32 ++++++++ .../baeldung/hibernate/pojo/PersonName.java | 32 ++++++++ .../converter/PersonNameConverterTest.java | 73 +++++++++++++++++++ 5 files changed, 181 insertions(+) create mode 100644 hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java create mode 100644 hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java create mode 100644 hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java create mode 100644 hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java index 25fc0d7b02..130edec8cc 100644 --- a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java +++ b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java @@ -81,6 +81,7 @@ public class HibernateUtil { metadataSources.addAnnotatedClass(Bag.class); metadataSources.addAnnotatedClass(PointEntity.class); metadataSources.addAnnotatedClass(PolygonEntity.class); + metadataSources.addAnnotatedClass(com.baeldung.hibernate.pojo.Person.class); Metadata metadata = metadataSources.buildMetadata(); return metadata.getSessionFactoryBuilder() diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java b/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java new file mode 100644 index 0000000000..c8b3397b09 --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java @@ -0,0 +1,43 @@ +package com.baeldung.hibernate.converters; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +import com.baeldung.hibernate.pojo.PersonName; + +@Converter +public class PersonNameConverter implements AttributeConverter { + + private static final String SEPARATOR = ", "; + + @Override + public String convertToDatabaseColumn(PersonName person) { + StringBuilder sb = new StringBuilder(); + if (person.getSurname() != null) { + sb.append(person.getSurname()); + sb.append(SEPARATOR); + } + + if (person.getName() != null) { + sb.append(person.getName()); + } + + return sb.toString(); + } + + @Override + public PersonName convertToEntityAttribute(String dbPerson) { + String[] pieces = dbPerson.split(SEPARATOR); + + if (pieces == null || pieces.length != 2) { + return null; + } + + PersonName personName = new PersonName(); + personName.setSurname(pieces[0]); + personName.setName(pieces[1]); + + return personName; + } + +} diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java new file mode 100644 index 0000000000..390a5954ed --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java @@ -0,0 +1,32 @@ +package com.baeldung.hibernate.pojo; + +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import com.baeldung.hibernate.converters.PersonNameConverter; + +@Entity(name = "PersonTable") +public class Person { + + @Id + @GeneratedValue + private Long id; + + @Convert(converter = PersonNameConverter.class) + private PersonName personName; + + public PersonName getPersonName() { + return personName; + } + + public void setPersonName(PersonName personName) { + this.personName = personName; + } + + public Long getId() { + return id; + } + +} diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java new file mode 100644 index 0000000000..689afd463a --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java @@ -0,0 +1,32 @@ +package com.baeldung.hibernate.pojo; + +import java.io.Serializable; + +import javax.persistence.Entity; + +@Entity +public class PersonName implements Serializable { + + private static final long serialVersionUID = 7883094644631050150L; + + private String name; + + private String surname; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + +} diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java new file mode 100644 index 0000000000..6eb89713f5 --- /dev/null +++ b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java @@ -0,0 +1,73 @@ +package com.baeldung.hibernate.converter; + +import java.io.IOException; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.pojo.Person; +import com.baeldung.hibernate.pojo.PersonName; +import com.vividsolutions.jts.util.Assert; + +public class PersonNameConverterTest { + + private Session session; + private Transaction transaction; + + @Before + public void setUp() throws IOException { + session = HibernateUtil.getSessionFactory() + .openSession(); + transaction = session.beginTransaction(); + + session.createNativeQuery("delete from personTable") + .executeUpdate(); + + transaction.commit(); + transaction = session.beginTransaction(); + } + + @After + public void tearDown() { + transaction.rollback(); + session.close(); + } + + @Test + public void givenPersonName_WhenSaving_ThenNameAndSurnameConcat() { + final String name = "name"; + final String surname = "surname"; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + Assert.equals(surname + ", " + name, dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + Assert.equals(dbPerson.getPersonName() + .getName(), name); + Assert.equals(dbPerson.getPersonName() + .getSurname(), surname); + } + +} From 0bf31021884f5c40668fab1ccd3a3fbbdc62ead9 Mon Sep 17 00:00:00 2001 From: Marcos Date: Sat, 3 Feb 2018 19:25:48 +0100 Subject: [PATCH 12/48] code cleanup --- .../src/main/java/com/baeldung/hibernate/pojo/PersonName.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java index 689afd463a..335fe73f75 100644 --- a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java +++ b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java @@ -2,9 +2,6 @@ package com.baeldung.hibernate.pojo; import java.io.Serializable; -import javax.persistence.Entity; - -@Entity public class PersonName implements Serializable { private static final long serialVersionUID = 7883094644631050150L; From bf5b3045a1f6fe710a1ae63e935504a6139f05ba Mon Sep 17 00:00:00 2001 From: Eric Goebelbecker Date: Sat, 3 Feb 2018 22:49:11 -0500 Subject: [PATCH 13/48] BAEL-1486 - sample code for JGroups. Fixed a typo in InfluxDB. (#3578) --- influxdb/README.md | 1 - .../influxdb/InfluxDBConnectionLiveTest.java | 3 +- jgroups/README.md | 15 ++ jgroups/pom.xml | 36 +++ .../baeldung/jgroups/JGroupsMessenger.java | 222 ++++++++++++++++++ jgroups/src/main/resources/udp.xml | 48 ++++ pom.xml | 1 + 7 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 jgroups/README.md create mode 100644 jgroups/pom.xml create mode 100644 jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java create mode 100644 jgroups/src/main/resources/udp.xml diff --git a/influxdb/README.md b/influxdb/README.md index 7d1684688d..f2c421580e 100644 --- a/influxdb/README.md +++ b/influxdb/README.md @@ -2,7 +2,6 @@ ### Relevant Article: - [Introduction to using InfluxDB with Java](http://www.baeldung.com/using-influxdb-with-java/) -- [Using InfluxDB with Java](http://www.baeldung.com/java-influxdb) ### Overview This Maven project contains the Java code for the article linked above. diff --git a/influxdb/src/test/java/com/baeldung/influxdb/InfluxDBConnectionLiveTest.java b/influxdb/src/test/java/com/baeldung/influxdb/InfluxDBConnectionLiveTest.java index 6c7a03cb70..858903a676 100644 --- a/influxdb/src/test/java/com/baeldung/influxdb/InfluxDBConnectionLiveTest.java +++ b/influxdb/src/test/java/com/baeldung/influxdb/InfluxDBConnectionLiveTest.java @@ -8,7 +8,6 @@ import org.influxdb.dto.*; import org.influxdb.impl.InfluxDBResultMapper; import org.junit.Test; -import java.io.IOException; import java.util.List; import java.util.concurrent.TimeUnit; @@ -103,7 +102,7 @@ public class InfluxDBConnectionLiveTest { // another brief pause. Thread.sleep(10); - List memoryPointList = getPoints(connection, "Select * from memory", "baeldung"); + List memoryPointList = getPoints(connection, "Select * from memory", "baeldung"); assertEquals(10, memoryPointList.size()); diff --git a/jgroups/README.md b/jgroups/README.md new file mode 100644 index 0000000000..bb2813c3d6 --- /dev/null +++ b/jgroups/README.md @@ -0,0 +1,15 @@ +## Reliable Messaging with JGroups Tutorial Project + +### Relevant Article: +- [Reliable Messaging with JGroups](http://www.baeldung.com/reliable-messaging-with-jgroups/) + +### Overview +This Maven project contains the Java code for the article linked above. + +### Package Organization +Java classes for the intro tutorial are in the org.baeldung.jgroups package. + + +### Running the tests + +``` diff --git a/jgroups/pom.xml b/jgroups/pom.xml new file mode 100644 index 0000000000..0e5971875e --- /dev/null +++ b/jgroups/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + jgroups + 0.1-SNAPSHOT + jar + jgroups + Reliable Messaging with JGroups Tutorial + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.jgroups + jgroups + 4.0.10.Final + + + + commons-cli + commons-cli + 1.4 + + + + + 1.8 + UTF-8 + + + diff --git a/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java b/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java new file mode 100644 index 0000000000..2a8df8a9ab --- /dev/null +++ b/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java @@ -0,0 +1,222 @@ +package com.baeldung.jgroups; + +import org.apache.commons.cli.*; +import org.jgroups.*; +import org.jgroups.util.Util; + +import java.io.*; +import java.util.List; +import java.util.Optional; + +public class JGroupsMessenger extends ReceiverAdapter { + + private JChannel channel; + private String userName; + private String clusterName; + private View lastView; + private boolean running = true; + + // Our shared state + private Integer messageCount = 0; + + /** + * Connect to a JGroups cluster using command line options + * @param args command line arguments + * @throws Exception + */ + private void start(String[] args) throws Exception { + processCommandline(args); + + // Create the channel + // This file could be moved, or made a command line option. + channel = new JChannel("src/main/resources/udp.xml"); + + // Set a name + channel.name(userName); + + // Register for callbacks + channel.setReceiver(this); + + // Ignore our messages + channel.setDiscardOwnMessages(true); + + // Connect + channel.connect(clusterName); + + // Start state transfer + channel.getState(null, 0); + + // Do the things + processInput(); + + // Clean up + channel.close(); + + } + + /** + * Quick and dirty implementaton of commons cli for command line args + * @param args the command line args + * @throws ParseException + */ + private void processCommandline(String[] args) throws ParseException { + + // Options, parser, friendly help + Options options = new Options(); + CommandLineParser parser = new DefaultParser(); + HelpFormatter formatter = new HelpFormatter(); + + options.addOption("u", "user", true, "User name") + .addOption("c", "cluster", true, "Cluster name"); + + CommandLine line = parser.parse(options, args); + + if (line.hasOption("user")) { + userName = line.getOptionValue("user"); + } else { + formatter.printHelp("JGroupsMessenger: need a user name.\n", options); + System.exit(-1); + } + + if (line.hasOption("cluster")) { + clusterName = line.getOptionValue("cluster"); + } else { + formatter.printHelp("JGroupsMessenger: need a cluster name.\n", options); + System.exit(-1); + } + } + + // Start it up + public static void main(String[] args) throws Exception { + new JGroupsMessenger().start(args); + } + + + @Override + public void viewAccepted(View newView) { + + // Save view if this is the first + if (lastView == null) { + System.out.println("Received initial view:"); + newView.forEach(System.out::println); + } else { + + // Compare to last view + System.out.println("Received new view."); + + List
newMembers = View.newMembers(lastView, newView); + if (newMembers.size() > 0) { + System.out.println("New members: "); + newMembers.forEach(System.out::println); + } + + List
exMembers = View.leftMembers(lastView, newView); + if (exMembers.size() > 0) { + System.out.println("Exited members:"); + exMembers.forEach(System.out::println); + } + } + lastView = newView; + } + + /** + * Loop on console input until we see 'x' to exit + */ + private void processInput() { + + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + while (running) { + try { + + // Get a destination, means broadcast + Address destination = null; + System.out.print("Enter a destination: "); + System.out.flush(); + String destinationName = in.readLine().toLowerCase(); + + if (destinationName.equals("x")) { + running = false; + continue; + } else if (!destinationName.isEmpty()) { + Optional
optDestination = getAddress(destinationName); + if (optDestination.isPresent()) { + destination = optDestination.get(); + } else { + System.out.println("Destination not found, try again."); + continue; + } + } + + // Accept a string to send + System.out.print("Enter a message: "); + System.out.flush(); + String line = in.readLine().toLowerCase(); + sendMessage(destination, line); + } catch (IOException ioe) { + running = false; + } + } + System.out.println("Exiting."); + } + + /** + * Send message from here + * @param destination the destination + * @param messageString the message + */ + private void sendMessage(Address destination, String messageString) { + try { + System.out.println("Sending " + messageString + " to " + destination); + Message message = new Message(destination, messageString); + channel.send(message); + } catch (Exception exception) { + System.err.println("Exception sending message: " + exception.getMessage()); + running = false; + } + } + + @Override + public void receive(Message message) { + // Print source and dest with message + String line = "Message received from: " + message.getSrc() + " to: " + message.getDest() + " -> " + message.getObject(); + + // Only track the count of broadcast messages + // Tracking direct message would make for a pointless state + if (message.getDest() == null) { + messageCount++; + System.out.println("Message count: " + messageCount); + } + + System.out.println(line); + } + + @Override + public void getState(OutputStream output) throws Exception { + // Serialize into the stream + Util.objectToStream(messageCount, new DataOutputStream(output)); + } + + @Override + public void setState(InputStream input) { + + // NOTE: since we know that incrementing the count and transferring the state + // is done inside the JChannel's thread, we don't have to worry about synchronizing + // messageCount. For production code it should be synchronized! + try { + // Deserialize + messageCount = Util.objectFromStream(new DataInputStream(input)); + } catch (Exception e) { + System.out.println("Error deserialing state!"); + } + System.out.println(messageCount + " is the current messagecount."); + } + + + private Optional
getAddress(String name) { + View view = channel.view(); + return view.getMembers().stream().filter(address -> name.equals(address.toString())).findFirst(); + } + +} + + diff --git a/jgroups/src/main/resources/udp.xml b/jgroups/src/main/resources/udp.xml new file mode 100644 index 0000000000..5a9bfd0851 --- /dev/null +++ b/jgroups/src/main/resources/udp.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 582ee6696e..ca6d4afe82 100644 --- a/pom.xml +++ b/pom.xml @@ -93,6 +93,7 @@ javax-servlets javaxval jaxb + jgroups jee-7 jjwt From 581e8592ae52591525054054e906f8d9df7cf9a3 Mon Sep 17 00:00:00 2001 From: shouvikbhattacharya Date: Sun, 4 Feb 2018 18:22:17 +0530 Subject: [PATCH 14/48] BAEL-1525: Article code completed. --- .../java/com/baeldung/string/Palindrome.java | 14 +++++++ .../string/WhenCheckingPalindrome.java | 37 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 core-java/src/main/java/com/baeldung/string/Palindrome.java create mode 100644 core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java diff --git a/core-java/src/main/java/com/baeldung/string/Palindrome.java b/core-java/src/main/java/com/baeldung/string/Palindrome.java new file mode 100644 index 0000000000..e339d92447 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/string/Palindrome.java @@ -0,0 +1,14 @@ +package com.baeldung.string; + +public class Palindrome { + + public boolean isPalindrome(String text) { + text = text.replaceAll("\\s+", "").toLowerCase(); + int length = text.length(); + int forward = 0; + int backward = length - 1; + boolean palindrome = true; + while ((backward > forward)?(palindrome=(text.charAt(forward++) == text.charAt(backward--))):false); + return palindrome; + } +} diff --git a/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java b/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java new file mode 100644 index 0000000000..691d74c751 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java @@ -0,0 +1,37 @@ +package com.baeldung.string; + +import org.junit.Assert; +import org.junit.Test; + +public class WhenCheckingPalindrome { + + private String[] words = { + "Anna", + "Civic", + "Kayak", + "Level", + "Madam", + }; + + private String[] sentences = { + "Sore was I ere I saw Eros", + "Euston saw I was not Sue", + "Too hot to hoot", + "No mists or frost Simon", + "Stella won no wallets" + }; + + private Palindrome palindrome = new Palindrome(); + + @Test + public void whenWord_shouldBePalindrome() { + for(String word:words) + Assert.assertTrue(palindrome.isPalindrome(word)); + } + + @Test + public void whenSentence_shouldBePalindrome() { + for(String sentence:sentences) + Assert.assertTrue(palindrome.isPalindrome(sentence)); + } +} From 796277bdaa4faf45cf549ee58b18dee56e872564 Mon Sep 17 00:00:00 2001 From: Marcos Date: Sun, 4 Feb 2018 14:06:11 +0100 Subject: [PATCH 15/48] fix assert --- .../hibernate/converter/PersonNameConverterTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java index 6eb89713f5..aec2311294 100644 --- a/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java +++ b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java @@ -11,7 +11,8 @@ import org.junit.Test; import com.baeldung.hibernate.HibernateUtil; import com.baeldung.hibernate.pojo.Person; import com.baeldung.hibernate.pojo.PersonName; -import com.vividsolutions.jts.util.Assert; + +import static org.junit.Assert.assertEquals; public class PersonNameConverterTest { @@ -58,15 +59,15 @@ public class PersonNameConverterTest { .setParameter("id", id) .getSingleResult(); - Assert.equals(surname + ", " + name, dbPersonName); + assertEquals(surname + ", " + name, dbPersonName); Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) .setParameter("id", id) .getSingleResult(); - Assert.equals(dbPerson.getPersonName() + assertEquals(dbPerson.getPersonName() .getName(), name); - Assert.equals(dbPerson.getPersonName() + assertEquals(dbPerson.getPersonName() .getSurname(), surname); } From 84782d054e429e5d71a4bda0d18029edd1f61ac3 Mon Sep 17 00:00:00 2001 From: abialas Date: Sun, 4 Feb 2018 23:44:22 +0100 Subject: [PATCH 16/48] BAEL-21 (#3587) * BAEL-1412 add java 8 spring data features * BAEL-21 new HTTP API overview * BAEL-21 fix executor --- .../com/baeldung/java9/httpclient/HttpClientTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java b/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java index a4c6ac0d7d..5cf3b9098f 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java +++ b/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; @@ -116,18 +117,20 @@ public class HttpClientTest { .GET() .build(); + ExecutorService executorService = Executors.newFixedThreadPool(2); + CompletableFuture> response1 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); CompletableFuture> response2 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); CompletableFuture> response3 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); From c03e0919e1195bdc06139a930220568dfefa72b1 Mon Sep 17 00:00:00 2001 From: Markus Gulden Date: Mon, 5 Feb 2018 10:21:36 +0100 Subject: [PATCH 17/48] Updates after editor feedback --- javaxval/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/javaxval/pom.xml b/javaxval/pom.xml index 0891fe6959..a05ee43aaf 100644 --- a/javaxval/pom.xml +++ b/javaxval/pom.xml @@ -22,12 +22,6 @@ - - javax.validation - validation-api - ${validation-api.version} - - org.hibernate hibernate-validator From 7ecceaf5e25ba9d1b549bf2bfad60f592a8677c2 Mon Sep 17 00:00:00 2001 From: Markus Gulden Date: Mon, 5 Feb 2018 11:17:37 +0100 Subject: [PATCH 18/48] Updates after editor feedback --- .../constraints/ConsistentDateParameterValidator.java | 6 +----- .../constraints/ValidReservationValidator.java | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java index 0ee1b6eda1..f1c97760d7 100644 --- a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java @@ -9,15 +9,11 @@ import java.time.LocalDate; @SupportedValidationTarget(ValidationTarget.PARAMETERS) public class ConsistentDateParameterValidator implements ConstraintValidator { - @Override - public void initialize(ConsistentDateParameters constraintAnnotation) { - } - @Override public boolean isValid(Object[] value, ConstraintValidatorContext context) { if (value[0] == null || value[1] == null) { - return false; + return true; } if (!(value[0] instanceof LocalDate) || !(value[1] instanceof LocalDate)) { diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java index fc225999be..7b730480ed 100644 --- a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java @@ -8,15 +8,11 @@ import java.time.LocalDate; public class ValidReservationValidator implements ConstraintValidator { - @Override - public void initialize(ValidReservation constraintAnnotation) { - } - @Override public boolean isValid(Reservation reservation, ConstraintValidatorContext context) { if (reservation == null) { - return false; + return true; } if (!(reservation instanceof Reservation)) { From a6a291ce22607fc8e7d50f4a90bb1c1f1e649d06 Mon Sep 17 00:00:00 2001 From: daoire Date: Mon, 5 Feb 2018 12:18:04 +0000 Subject: [PATCH 19/48] Update README --- libraries/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/README.md b/libraries/README.md index d001f13698..fbf2b4e876 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -59,6 +59,7 @@ - [Intro to JDO Queries 2/2](http://www.baeldung.com/jdo-queries) - [Guide to google-http-client](http://www.baeldung.com/google-http-client) - [Interact with Google Sheets from Java](http://www.baeldung.com/google-sheets-java-client) +- [Programatically Create, Configure, and Run a Tomcat Server] (http://www.baeldung.com/tomcat-programmatic-setup) From 34e8c290fd57bbe98646ff50a423fd4f863b7f2d Mon Sep 17 00:00:00 2001 From: daoire Date: Mon, 5 Feb 2018 12:30:23 +0000 Subject: [PATCH 20/48] Update README.md --- logging-modules/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/logging-modules/README.md b/logging-modules/README.md index 8ae7316047..6de71adb43 100644 --- a/logging-modules/README.md +++ b/logging-modules/README.md @@ -4,3 +4,4 @@ ### Relevant Articles: - [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender) +- [Get Log Output in JSON Format](http://www.baeldung.com/java-log-json-output) From fcb114b50c1cf920085d55c2c1acd2785d12c0ed Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Mon, 5 Feb 2018 20:55:45 +0200 Subject: [PATCH 21/48] Update README.md --- mesos-marathon/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mesos-marathon/README.md b/mesos-marathon/README.md index 3223eb2478..164f0db5d3 100644 --- a/mesos-marathon/README.md +++ b/mesos-marathon/README.md @@ -1,3 +1,5 @@ ### Relevant articles - [Simple Jenkins Pipeline with Marathon and Mesos](http://www.baeldung.com/jenkins-pipeline-with-marathon-mesos) + +To run the pipeline, please modify the dockerise.sh file with your own useranema and password for docker login. From 43d0f4c15c6b8813a86305ba9c218331458f6d92 Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Mon, 5 Feb 2018 20:10:44 +0100 Subject: [PATCH 22/48] added link to article --- testing-modules/testing/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/testing-modules/testing/README.md b/testing-modules/testing/README.md index 3511bb1bb9..2894da3496 100644 --- a/testing-modules/testing/README.md +++ b/testing-modules/testing/README.md @@ -17,3 +17,4 @@ - [Introduction to Jukito](http://www.baeldung.com/jukito) - [Custom JUnit 4 Test Runners](http://www.baeldung.com/junit-4-custom-runners) - [Guide to JSpec](http://www.baeldung.com/jspec) +- [Custom Assertions with AssertJ](http://www.baeldung.com/assertj-custom-assertion) From 1011edf288140b87a68341f05b2774e153ffbac3 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Mon, 5 Feb 2018 21:16:09 +0200 Subject: [PATCH 23/48] Update README.md --- mesos-marathon/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesos-marathon/README.md b/mesos-marathon/README.md index 164f0db5d3..1d4d4995a8 100644 --- a/mesos-marathon/README.md +++ b/mesos-marathon/README.md @@ -2,4 +2,4 @@ - [Simple Jenkins Pipeline with Marathon and Mesos](http://www.baeldung.com/jenkins-pipeline-with-marathon-mesos) -To run the pipeline, please modify the dockerise.sh file with your own useranema and password for docker login. + To run the pipeline, please modify the dockerise.sh file with your own useranema and password for docker login. From 372cba10bb23e5e1fc50631c63dfa5ad4da6db20 Mon Sep 17 00:00:00 2001 From: Eric Goebelbecker Date: Mon, 5 Feb 2018 19:47:17 -0500 Subject: [PATCH 24/48] BAEL-1486 - small changes to JGroups (#3590) * BAEL-1486 - sample code for JGroups. Fixed a typo in InfluxDB. * BAEL-1486 - updates for JGroups. --- .../baeldung/jgroups/JGroupsMessenger.java | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java b/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java index 2a8df8a9ab..70eacabf1e 100644 --- a/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java +++ b/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java @@ -100,21 +100,16 @@ public class JGroupsMessenger extends ReceiverAdapter { System.out.println("Received initial view:"); newView.forEach(System.out::println); } else { - // Compare to last view System.out.println("Received new view."); List
newMembers = View.newMembers(lastView, newView); - if (newMembers.size() > 0) { - System.out.println("New members: "); - newMembers.forEach(System.out::println); - } + System.out.println("New members: "); + newMembers.forEach(System.out::println); List
exMembers = View.leftMembers(lastView, newView); - if (exMembers.size() > 0) { - System.out.println("Exited members:"); - exMembers.forEach(System.out::println); - } + System.out.println("Exited members:"); + exMembers.forEach(System.out::println); } lastView = newView; } @@ -122,7 +117,7 @@ public class JGroupsMessenger extends ReceiverAdapter { /** * Loop on console input until we see 'x' to exit */ - private void processInput() { + private void processInput() throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); while (running) { @@ -138,13 +133,8 @@ public class JGroupsMessenger extends ReceiverAdapter { running = false; continue; } else if (!destinationName.isEmpty()) { - Optional
optDestination = getAddress(destinationName); - if (optDestination.isPresent()) { - destination = optDestination.get(); - } else { - System.out.println("Destination not found, try again."); - continue; - } + destination = getAddress(destinationName) + . orElseThrow(() -> new Exception("Destination not found")); } // Accept a string to send From 56316fd029ff941e39e5bdf7dc3f5cca170946b0 Mon Sep 17 00:00:00 2001 From: linhvovn Date: Wed, 7 Feb 2018 03:43:44 +0800 Subject: [PATCH 25/48] [tlinh2110-BAEL1382] Add Security in SI (#3593) * [tlinh2110-BAEL1382] Add Security in SI * [tlinh2110-BAEL1382] Upgrade to Spring 5 & add Logger --- spring-integration/pom.xml | 41 ++++++++-- .../baeldung/si/security/MessageConsumer.java | 45 ++++++++++ .../si/security/SecuredDirectChannel.java | 50 +++++++++++ .../baeldung/si/security/SecurityConfig.java | 46 +++++++++++ .../si/security/SecurityPubSubChannel.java | 82 +++++++++++++++++++ .../security/UsernameAccessDecisionVoter.java | 45 ++++++++++ .../si/TestSpringIntegrationSecurity.java | 81 ++++++++++++++++++ ...TestSpringIntegrationSecurityExecutor.java | 68 +++++++++++++++ 8 files changed, 452 insertions(+), 6 deletions(-) create mode 100644 spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java create mode 100644 spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java create mode 100644 spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java create mode 100644 spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java create mode 100644 spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java create mode 100644 spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java create mode 100644 spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java diff --git a/spring-integration/pom.xml b/spring-integration/pom.xml index 4e210122b0..27cc7381e3 100644 --- a/spring-integration/pom.xml +++ b/spring-integration/pom.xml @@ -18,7 +18,7 @@ UTF-8 - 4.3.5.RELEASE + 5.0.1.RELEASE 1.1.4.RELEASE 1.4.7 1.1.1 @@ -68,7 +68,7 @@ org.springframework.integration spring-integration-core - ${spring.integration.version} + ${spring.version} javax.activation @@ -84,17 +84,17 @@ org.springframework.integration spring-integration-twitter - ${spring.integration.version} + ${spring.version} org.springframework.integration spring-integration-mail - ${spring.integration.version} + ${spring.version} org.springframework.integration spring-integration-ftp - ${spring.integration.version} + ${spring.version} org.springframework.social @@ -104,7 +104,36 @@ org.springframework.integration spring-integration-file - ${spring.integration.version} + ${spring.version} + + + + org.springframework.security + spring-security-core + ${spring.version} + + + org.springframework.security + spring-security-config + ${spring.version} + + + org.springframework.integration + spring-integration-security + ${spring.version} + + + + org.springframework.security + spring-security-test + ${spring.version} + test + + + org.springframework + spring-test + ${spring.version} + test junit diff --git a/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java b/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java new file mode 100644 index 0000000000..af925c63a7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java @@ -0,0 +1,45 @@ +package com.baeldung.si.security; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Service; + +@Service +public class MessageConsumer { + + private String messageContent; + + private Map messagePSContent = new ConcurrentHashMap<>(); + + public String getMessageContent() { + return messageContent; + } + + public void setMessageContent(String messageContent) { + this.messageContent = messageContent; + } + + public Map getMessagePSContent() { + return messagePSContent; + } + + public void setMessagePSContent(Map messagePSContent) { + this.messagePSContent = messagePSContent; + } + + @ServiceActivator(inputChannel = "endDirectChannel") + public void endDirectFlow(Message message) { + setMessageContent(message.getPayload().toString()); + } + + @ServiceActivator(inputChannel = "finalPSResult") + public void endPSFlow(Message message) { + Logger.getAnonymousLogger().info(Thread.currentThread().getName() + " has completed ---------------------------"); + messagePSContent.put(Thread.currentThread().getName(), (String) message.getPayload()); + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java b/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java new file mode 100644 index 0000000000..964a07d7d7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java @@ -0,0 +1,50 @@ +package com.baeldung.si.security; + +import java.util.logging.Logger; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.security.channel.ChannelSecurityInterceptor; +import org.springframework.integration.security.channel.SecuredChannel; +import org.springframework.messaging.Message; +import org.springframework.security.access.AccessDecisionManager; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AuthenticationManager; + +@Configuration +@EnableIntegration +public class SecuredDirectChannel { + + @Bean(name = "startDirectChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = { "ROLE_VIEWER", "jane" }) + public DirectChannel startDirectChannel() { + return new DirectChannel(); + } + + @ServiceActivator(inputChannel = "startDirectChannel", outputChannel = "endDirectChannel") + @PreAuthorize("hasRole('ROLE_LOGGER')") + public Message logMessage(Message message) { + Logger.getAnonymousLogger().info(message.toString()); + return message; + } + + @Bean(name = "endDirectChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = { "ROLE_EDITOR" }) + public DirectChannel endDirectChannel() { + return new DirectChannel(); + } + + @Autowired + @Bean + public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager, AccessDecisionManager customAccessDecisionManager) { + ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(); + channelSecurityInterceptor.setAuthenticationManager(authenticationManager); + channelSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager); + return channelSecurityInterceptor; + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java b/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java new file mode 100644 index 0000000000..9c5b38b909 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java @@ -0,0 +1,46 @@ +package com.baeldung.si.security; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.security.channel.ChannelSecurityInterceptor; +import org.springframework.security.access.AccessDecisionManager; +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.vote.AffirmativeBased; +import org.springframework.security.access.vote.RoleVoter; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; + +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig extends GlobalMethodSecurityConfiguration { + + @Override + @Bean + public AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } + + @Bean + public AccessDecisionManager customAccessDecisionManager() { + List> decisionVoters = new ArrayList<>(); + decisionVoters.add(new RoleVoter()); + decisionVoters.add(new UsernameAccessDecisionVoter()); + AccessDecisionManager accessDecisionManager = new AffirmativeBased(decisionVoters); + return accessDecisionManager; + } + + @Autowired + @Bean + public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager, AccessDecisionManager customAccessDecisionManager) { + ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(); + channelSecurityInterceptor.setAuthenticationManager(authenticationManager); + channelSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager); + return channelSecurityInterceptor; + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java b/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java new file mode 100644 index 0000000000..11409bb89b --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java @@ -0,0 +1,82 @@ +package com.baeldung.si.security; + +import java.util.stream.Collectors; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.channel.PublishSubscribeChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.config.GlobalChannelInterceptor; +import org.springframework.integration.security.channel.SecuredChannel; +import org.springframework.integration.security.channel.SecurityContextPropagationChannelInterceptor; +import org.springframework.integration.support.DefaultMessageBuilderFactory; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +@Configuration +@EnableIntegration +public class SecurityPubSubChannel { + + @Bean(name = "startPSChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = "ROLE_VIEWER") + public PublishSubscribeChannel startChannel() { + return new PublishSubscribeChannel(executor()); + } + + @ServiceActivator(inputChannel = "startPSChannel", outputChannel = "finalPSResult") + @PreAuthorize("hasRole('ROLE_LOGGER')") + public Message changeMessageToRole(Message message) { + return buildNewMessage(getRoles(), message); + } + + @ServiceActivator(inputChannel = "startPSChannel", outputChannel = "finalPSResult") + @PreAuthorize("hasRole('ROLE_VIEWER')") + public Message changeMessageToUserName(Message message) { + return buildNewMessage(getUsername(), message); + } + + @Bean(name = "finalPSResult") + public DirectChannel finalPSResult() { + return new DirectChannel(); + } + + @Bean + @GlobalChannelInterceptor(patterns = { "startPSChannel", "endDirectChannel" }) + public ChannelInterceptor securityContextPropagationInterceptor() { + return new SecurityContextPropagationChannelInterceptor(); + } + + @Bean + public ThreadPoolTaskExecutor executor() { + ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); + pool.setCorePoolSize(10); + pool.setMaxPoolSize(10); + pool.setWaitForTasksToCompleteOnShutdown(true); + return pool; + } + + public String getRoles() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getAuthorities().stream().map(auth -> auth.getAuthority()).collect(Collectors.joining(",")); + } + + public String getUsername() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getName(); + } + + public Message buildNewMessage(String content, Message message) { + DefaultMessageBuilderFactory builderFactory = new DefaultMessageBuilderFactory(); + MessageBuilder messageBuilder = builderFactory.withPayload(content); + messageBuilder.copyHeaders(message.getHeaders()); + return messageBuilder.build(); + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java b/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java new file mode 100644 index 0000000000..052f79ddf7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java @@ -0,0 +1,45 @@ +package com.baeldung.si.security; + +import java.util.Collection; + +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.core.Authentication; + +public class UsernameAccessDecisionVoter implements AccessDecisionVoter { + private String rolePrefix = "ROLE_"; + + @Override + public boolean supports(ConfigAttribute attribute) { + if ((attribute.getAttribute() != null) + && !attribute.getAttribute().startsWith(rolePrefix)) { + return true; + }else { + return false; + } + } + + @Override + public boolean supports(Class clazz) { + return true; + } + + @Override + public int vote(Authentication authentication, Object object, Collection attributes) { + if (authentication == null) { + return ACCESS_DENIED; + } + String name = authentication.getName(); + int result = ACCESS_ABSTAIN; + for (ConfigAttribute attribute : attributes) { + if (this.supports(attribute)) { + result = ACCESS_DENIED; + if (attribute.getAttribute().equals(name)) { + return ACCESS_GRANTED; + } + } + } + return result; + } + +} diff --git a/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java new file mode 100644 index 0000000000..45dcb1e836 --- /dev/null +++ b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java @@ -0,0 +1,81 @@ +package com.baeldung.si; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.SubscribableChannel; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.si.security.MessageConsumer; +import com.baeldung.si.security.SecuredDirectChannel; +import com.baeldung.si.security.SecurityConfig; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SecurityConfig.class, SecuredDirectChannel.class, MessageConsumer.class }) +public class TestSpringIntegrationSecurity { + + @Autowired + SubscribableChannel startDirectChannel; + + @Autowired + MessageConsumer messageConsumer; + + final String DIRECT_CHANNEL_MESSAGE = "Direct channel message"; + + @Test(expected = AuthenticationCredentialsNotFoundException.class) + public void givenNoUser_whenSendToDirectChannel_thenCredentialNotFound() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test(expected = AccessDeniedException.class) + @WithMockUser(username = "jane", roles = { "LOGGER" }) + public void givenRoleLogger_whenSendMessageToDirectChannel_thenAccessDenied() throws Throwable { + try { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } catch (Exception e) { + throw e.getCause(); + } + } + + @Test(expected = AccessDeniedException.class) + @WithMockUser(username = "jane") + public void givenJane_whenSendMessageToDirectChannel_thenAccessDenied() throws Throwable { + try { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } catch (Exception e) { + throw e.getCause(); + } + } + + @Test(expected = AccessDeniedException.class) + @WithMockUser(roles = { "VIEWER" }) + public void givenRoleViewer_whenSendToDirectChannel_thenAccessDenied() throws Throwable { + try { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } catch (Exception e) { + throw e.getCause(); + } + } + + @Test + @WithMockUser(roles = { "LOGGER", "VIEWER", "EDITOR" }) + public void givenRoleLoggerAndUser_whenSendMessageToDirectChannel_thenFlowCompletedSuccessfully() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + assertEquals(DIRECT_CHANNEL_MESSAGE, messageConsumer.getMessageContent()); + } + + @Test + @WithMockUser(username = "jane", roles = { "LOGGER", "EDITOR" }) + public void givenJaneLoggerEditor_whenSendToDirectChannel_thenFlowCompleted() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + assertEquals(DIRECT_CHANNEL_MESSAGE, messageConsumer.getMessageContent()); + } + +} diff --git a/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java new file mode 100644 index 0000000000..b06136a7ca --- /dev/null +++ b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java @@ -0,0 +1,68 @@ +package com.baeldung.si; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.SubscribableChannel; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.si.security.MessageConsumer; +import com.baeldung.si.security.SecurityConfig; +import com.baeldung.si.security.SecurityPubSubChannel; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SecurityPubSubChannel.class, MessageConsumer.class, SecurityConfig.class }) +public class TestSpringIntegrationSecurityExecutor { + + @Autowired + SubscribableChannel startPSChannel; + + @Autowired + MessageConsumer messageConsumer; + + @Autowired + ThreadPoolTaskExecutor executor; + + final String DIRECT_CHANNEL_MESSAGE = "Direct channel message"; + + @Before + public void clearData() { + messageConsumer.setMessagePSContent(new ConcurrentHashMap<>()); + executor.setWaitForTasksToCompleteOnShutdown(true); + } + + @Test + @WithMockUser(username = "user", roles = { "VIEWER" }) + public void givenRoleUser_whenSendMessageToPSChannel_thenNoMessageArrived() throws IllegalStateException, InterruptedException { + startPSChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + + assertEquals(1, messageConsumer.getMessagePSContent().size()); + assertTrue(messageConsumer.getMessagePSContent().values().contains("user")); + } + + @Test + @WithMockUser(username = "user", roles = { "LOGGER", "VIEWER" }) + public void givenRoleUserAndLogger_whenSendMessageToPSChannel_then2GetMessages() throws IllegalStateException, InterruptedException { + startPSChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + + assertEquals(2, messageConsumer.getMessagePSContent().size()); + assertTrue(messageConsumer.getMessagePSContent().values().contains("user")); + assertTrue(messageConsumer.getMessagePSContent().values().contains("ROLE_LOGGER,ROLE_VIEWER")); + } + +} From 5a34de448edd30514b3454dddcb30f9ce5ea749e Mon Sep 17 00:00:00 2001 From: Orry Date: Tue, 6 Feb 2018 21:47:26 +0200 Subject: [PATCH 26/48] AssertJ Exception Assertions (#3600) * Add XML, JavaConfig and Autowired examples. * BAEL-1517: Added Java7 style assertions * BAEL-1517: Upgrade AssertJ to 3.9.0; add Java 8 style assertion tests * Revert "Add XML, JavaConfig and Autowired examples." This reverts commit 8f4df6b903866dac1725832d06ee7382fc89d0ce. --- testing-modules/testing/pom.xml | 2 +- .../exceptions/Java7StyleAssertions.java | 24 +++++++++++ .../exceptions/Java8StyleAssertions.java | 42 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java create mode 100644 testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java diff --git a/testing-modules/testing/pom.xml b/testing-modules/testing/pom.xml index c76045380b..91792a4681 100644 --- a/testing-modules/testing/pom.xml +++ b/testing-modules/testing/pom.xml @@ -173,7 +173,7 @@ 0.7.7.201606060606 21.0 3.1.0 - 3.6.1 + 3.9.0 2.1.0 0.32 1.1.0 diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java new file mode 100644 index 0000000000..07a5be1118 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java @@ -0,0 +1,24 @@ +package com.baeldung.testing.assertj.exceptions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; + +import org.junit.Test; + +public class Java7StyleAssertions { + + @Test + public void whenDividingByZero_thenArithmeticException() { + try { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + fail("ArithmeticException expected because dividing by zero yields an ArithmeticException."); + failBecauseExceptionWasNotThrown(ArithmeticException.class); + } catch (Exception e) { + assertThat(e).hasMessage("/ by zero"); + assertThat(e).isInstanceOf(ArithmeticException.class); + } + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java new file mode 100644 index 0000000000..53f192bb2f --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java @@ -0,0 +1,42 @@ +package com.baeldung.testing.assertj.exceptions; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.catchThrowable; + +import org.junit.Test; + +public class Java8StyleAssertions { + + @Test + public void whenDividingByZero_thenArithmeticException() { + assertThatThrownBy(() -> { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + }).isInstanceOf(ArithmeticException.class) + .hasMessageContaining("/ by zero"); + + assertThatExceptionOfType(ArithmeticException.class).isThrownBy(() -> { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + }) + .withMessageContaining("/ by zero"); + + // BDD style: + + // when + Throwable thrown = catchThrowable(() -> { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + }); + + // then + assertThat(thrown).isInstanceOf(ArithmeticException.class) + .hasMessageContaining("/ by zero"); + + } +} From efb66e300108383c5c72b304dc81429dba1a7acf Mon Sep 17 00:00:00 2001 From: deep20jain Date: Wed, 7 Feb 2018 01:37:38 +0530 Subject: [PATCH 27/48] Bael 1299 - Maze Solver - deep20jain@gmail.com (#3537) * Maze solver using DFS * Adding BFS maze solver * Fixing formatting --- .../algorithms/maze/solver/BFSMazeSolver.java | 52 +++++++ .../algorithms/maze/solver/Coordinate.java | 31 ++++ .../algorithms/maze/solver/DFSMazeSolver.java | 48 ++++++ .../baeldung/algorithms/maze/solver/Maze.java | 141 ++++++++++++++++++ .../algorithms/maze/solver/MazeDriver.java | 34 +++++ algorithms/src/main/resources/maze/maze1.txt | 12 ++ algorithms/src/main/resources/maze/maze2.txt | 22 +++ 7 files changed, 340 insertions(+) create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java create mode 100644 algorithms/src/main/resources/maze/maze1.txt create mode 100644 algorithms/src/main/resources/maze/maze2.txt diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java new file mode 100644 index 0000000000..08972251b8 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java @@ -0,0 +1,52 @@ +package com.baeldung.algorithms.maze.solver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class BFSMazeSolver { + private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; + + public List solve(Maze maze) { + LinkedList nextToVisit = new LinkedList<>(); + Coordinate start = maze.getEntry(); + nextToVisit.add(start); + + while (!nextToVisit.isEmpty()) { + Coordinate cur = nextToVisit.remove(); + + if (!maze.isValidLocation(cur.getX(), cur.getY()) || maze.isExplored(cur.getX(), cur.getY())) { + continue; + } + + if (maze.isWall(cur.getX(), cur.getY())) { + maze.setVisited(cur.getX(), cur.getY(), true); + continue; + } + + if (maze.isExit(cur.getX(), cur.getY())) { + return backtrackPath(cur); + } + + for (int[] direction : DIRECTIONS) { + Coordinate coordinate = new Coordinate(cur.getX() + direction[0], cur.getY() + direction[1], cur); + nextToVisit.add(coordinate); + maze.setVisited(cur.getX(), cur.getY(), true); + } + } + return Collections.emptyList(); + } + + private List backtrackPath(Coordinate cur) { + List path = new ArrayList<>(); + Coordinate iter = cur; + + while (iter != null) { + path.add(iter); + iter = iter.parent; + } + + return path; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java new file mode 100644 index 0000000000..09b2ced5e6 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java @@ -0,0 +1,31 @@ +package com.baeldung.algorithms.maze.solver; + +public class Coordinate { + int x; + int y; + Coordinate parent; + + public Coordinate(int x, int y) { + this.x = x; + this.y = y; + this.parent = null; + } + + public Coordinate(int x, int y, Coordinate parent) { + this.x = x; + this.y = y; + this.parent = parent; + } + + int getX() { + return x; + } + + int getY() { + return y; + } + + Coordinate getParent() { + return parent; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java new file mode 100644 index 0000000000..f9640066b9 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java @@ -0,0 +1,48 @@ +package com.baeldung.algorithms.maze.solver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class DFSMazeSolver { + private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; + + public List solve(Maze maze) { + List path = new ArrayList<>(); + if (explore(maze, maze.getEntry() + .getX(), + maze.getEntry() + .getY(), + path)) { + return path; + } + return Collections.emptyList(); + } + + private boolean explore(Maze maze, int row, int col, List path) { + if (!maze.isValidLocation(row, col) || maze.isWall(row, col) || maze.isExplored(row, col)) { + return false; + } + + path.add(new Coordinate(row, col)); + maze.setVisited(row, col, true); + + if (maze.isExit(row, col)) { + return true; + } + + for (int[] direction : DIRECTIONS) { + Coordinate coordinate = getNextCoordinate(row, col, direction[0], direction[1]); + if (explore(maze, coordinate.getX(), coordinate.getY(), path)) { + return true; + } + } + + path.remove(path.size() - 1); + return false; + } + + private Coordinate getNextCoordinate(int row, int col, int i, int j) { + return new Coordinate(row + i, col + j); + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java new file mode 100644 index 0000000000..8aaa44d9b1 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java @@ -0,0 +1,141 @@ +package com.baeldung.algorithms.maze.solver; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +public class Maze { + private static final int ROAD = 0; + private static final int WALL = 1; + private static final int START = 2; + private static final int EXIT = 3; + private static final int PATH = 4; + + private int[][] maze; + private boolean[][] visited; + private Coordinate start; + private Coordinate end; + + public Maze(File maze) throws FileNotFoundException { + String fileText = ""; + try (Scanner input = new Scanner(maze)) { + while (input.hasNextLine()) { + fileText += input.nextLine() + "\n"; + } + } + initializeMaze(fileText); + } + + private void initializeMaze(String text) { + if (text == null || (text = text.trim()).length() == 0) { + throw new IllegalArgumentException("empty lines data"); + } + + String[] lines = text.split("[\r]?\n"); + maze = new int[lines.length][lines[0].length()]; + visited = new boolean[lines.length][lines[0].length()]; + + for (int row = 0; row < getHeight(); row++) { + if (lines[row].length() != getWidth()) { + throw new IllegalArgumentException("line " + (row + 1) + " wrong length (was " + lines[row].length() + " but should be " + getWidth() + ")"); + } + + for (int col = 0; col < getWidth(); col++) { + if (lines[row].charAt(col) == '#') + maze[row][col] = WALL; + else if (lines[row].charAt(col) == 'S') { + maze[row][col] = START; + start = new Coordinate(row, col); + } else if (lines[row].charAt(col) == 'E') { + maze[row][col] = EXIT; + end = new Coordinate(row, col); + } else + maze[row][col] = ROAD; + } + } + } + + public int getHeight() { + return maze.length; + } + + public int getWidth() { + return maze[0].length; + } + + public Coordinate getEntry() { + return start; + } + + public Coordinate getExit() { + return end; + } + + public boolean isExit(int x, int y) { + return x == end.getX() && y == end.getY(); + } + + public boolean isStart(int x, int y) { + return x == start.getX() && y == start.getY(); + } + + public boolean isExplored(int row, int col) { + return visited[row][col]; + } + + public boolean isWall(int row, int col) { + return maze[row][col] == WALL; + } + + public void setVisited(int row, int col, boolean value) { + visited[row][col] = value; + } + + public boolean isValidLocation(int row, int col) { + if (row < 0 || row >= getHeight() || col < 0 || col >= getWidth()) { + return false; + } + return true; + } + + public void printPath(List path) { + int[][] tempMaze = Arrays.stream(maze) + .map(int[]::clone) + .toArray(int[][]::new); + for (Coordinate coordinate : path) { + if (isStart(coordinate.getX(), coordinate.getY()) || isExit(coordinate.getX(), coordinate.getY())) { + continue; + } + tempMaze[coordinate.getX()][coordinate.getY()] = PATH; + } + System.out.println(toString(tempMaze)); + } + + public String toString(int[][] maze) { + StringBuilder result = new StringBuilder(getWidth() * (getHeight() + 1)); + for (int row = 0; row < getHeight(); row++) { + for (int col = 0; col < getWidth(); col++) { + if (maze[row][col] == ROAD) { + result.append(' '); + } else if (maze[row][col] == WALL) { + result.append('#'); + } else if (maze[row][col] == START) { + result.append('S'); + } else if (maze[row][col] == EXIT) { + result.append('E'); + } else { + result.append('.'); + } + } + result.append('\n'); + } + return result.toString(); + } + + public void reset() { + for (int i = 0; i < visited.length; i++) + Arrays.fill(visited[i], false); + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java new file mode 100644 index 0000000000..60263deba3 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java @@ -0,0 +1,34 @@ +package com.baeldung.algorithms.maze.solver; + +import java.io.File; +import java.util.List; + +public class MazeDriver { + public static void main(String[] args) throws Exception { + File maze1 = new File("src/main/resources/maze/maze1.txt"); + File maze2 = new File("src/main/resources/maze/maze2.txt"); + + execute(maze1); + execute(maze2); + } + + private static void execute(File file) throws Exception { + Maze maze = new Maze(file); + dfs(maze); + bfs(maze); + } + + private static void bfs(Maze maze) { + BFSMazeSolver bfs = new BFSMazeSolver(); + List path = bfs.solve(maze); + maze.printPath(path); + maze.reset(); + } + + private static void dfs(Maze maze) { + DFSMazeSolver dfs = new DFSMazeSolver(); + List path = dfs.solve(maze); + maze.printPath(path); + maze.reset(); + } +} diff --git a/algorithms/src/main/resources/maze/maze1.txt b/algorithms/src/main/resources/maze/maze1.txt new file mode 100644 index 0000000000..0a6309d25b --- /dev/null +++ b/algorithms/src/main/resources/maze/maze1.txt @@ -0,0 +1,12 @@ +S ######## +# # +# ### ## # +# # # # +# # # # # +# ## ##### +# # # +# # # # # +##### #### +# # E +# # # # +########## \ No newline at end of file diff --git a/algorithms/src/main/resources/maze/maze2.txt b/algorithms/src/main/resources/maze/maze2.txt new file mode 100644 index 0000000000..22e6d0382a --- /dev/null +++ b/algorithms/src/main/resources/maze/maze2.txt @@ -0,0 +1,22 @@ +S ########################## +# # # # +# # #### ############### # +# # # # # # +# # #### # # ############### +# # # # # # # +# # # #### ### ########### # +# # # # # # +# ################## # +######### # # # # # +# # #### # ####### # # +# # ### ### # # # # # +# # ## # ##### # # +##### ####### # # # # # +# # ## ## #### # # +# ##### ####### # # +# # ############ +####### ######### # # +# # ######## # +# ####### ###### ## # E +# # # ## # +############################ \ No newline at end of file From 596efe3042c68eb91cc048356ab71a9ae95ce1d7 Mon Sep 17 00:00:00 2001 From: Nikhil Khatwani Date: Wed, 7 Feb 2018 19:45:04 +0530 Subject: [PATCH 28/48] Changes for BAEL-1472 --- persistence-modules/spring-data-redis/pom.xml | 12 ++++- .../spring/data/redis/config/RedisConfig.java | 9 ++-- .../spring/data/redis/model/Student.java | 3 ++ .../data/redis/repo/StudentRepository.java | 19 ++----- .../redis/repo/StudentRepositoryImpl.java | 49 ------------------- .../StudentRepositoryIntegrationTest.java | 40 ++++++++------- 6 files changed, 46 insertions(+), 86 deletions(-) delete mode 100644 persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java diff --git a/persistence-modules/spring-data-redis/pom.xml b/persistence-modules/spring-data-redis/pom.xml index 6cb49f11cf..0dc51e790e 100644 --- a/persistence-modules/spring-data-redis/pom.xml +++ b/persistence-modules/spring-data-redis/pom.xml @@ -16,11 +16,13 @@ UTF-8 - 4.3.7.RELEASE - 1.8.1.RELEASE + 5.0.3.RELEASE + 2.0.3.RELEASE 3.2.4 2.9.0 0.10.0 + 2.0.3.RELEASE + @@ -73,6 +75,12 @@ nosqlunit-redis ${nosqlunit.version} + + + org.springframework.data + spring-data-commons + 2.0.3.RELEASE + diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java index 4fd83a2bb6..4ea8bb4bc0 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java @@ -1,8 +1,5 @@ package com.baeldung.spring.data.redis.config; -import com.baeldung.spring.data.redis.queue.MessagePublisher; -import com.baeldung.spring.data.redis.queue.RedisMessagePublisher; -import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -11,10 +8,16 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; import org.springframework.data.redis.serializer.GenericToStringSerializer; +import com.baeldung.spring.data.redis.queue.MessagePublisher; +import com.baeldung.spring.data.redis.queue.RedisMessagePublisher; +import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber; + @Configuration @ComponentScan("com.baeldung.spring.data.redis") +@EnableRedisRepositories(basePackages = "com.baeldung.spring.data.redis.repo") public class RedisConfig { @Bean diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java index 10ba0f5ef4..b97ed23387 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java @@ -2,6 +2,9 @@ package com.baeldung.spring.data.redis.model; import java.io.Serializable; +import org.springframework.data.redis.core.RedisHash; + +@RedisHash("Student") public class Student implements Serializable { public enum Gender { diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java index 250c227f00..39f13bb6a7 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java @@ -1,18 +1,9 @@ package com.baeldung.spring.data.redis.repo; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + import com.baeldung.spring.data.redis.model.Student; -import java.util.Map; - -public interface StudentRepository { - - void saveStudent(Student person); - - void updateStudent(Student student); - - Student findStudent(String id); - - Map findAllStudents(); - - void deleteStudent(String id); -} +@Repository +public interface StudentRepository extends CrudRepository {} diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java deleted file mode 100644 index f13bef0f54..0000000000 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.spring.data.redis.repo; - -import com.baeldung.spring.data.redis.model.Student; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.HashOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Repository; - -import javax.annotation.PostConstruct; -import java.util.Map; - -@Repository -public class StudentRepositoryImpl implements StudentRepository { - - private static final String KEY = "Student"; - - private RedisTemplate redisTemplate; - private HashOperations hashOperations; - - @Autowired - public StudentRepositoryImpl(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - - @PostConstruct - private void init() { - hashOperations = redisTemplate.opsForHash(); - } - - public void saveStudent(final Student student) { - hashOperations.put(KEY, student.getId(), student); - } - - public void updateStudent(final Student student) { - hashOperations.put(KEY, student.getId(), student); - } - - public Student findStudent(final String id) { - return (Student) hashOperations.get(KEY, id); - } - - public Map findAllStudents() { - return hashOperations.entries(KEY); - } - - public void deleteStudent(final String id) { - hashOperations.delete(KEY, id); - } -} diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java index 1028c0bc24..66ef3c21b2 100644 --- a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java @@ -1,17 +1,20 @@ package com.baeldung.spring.data.redis.repo; -import com.baeldung.spring.data.redis.config.RedisConfig; -import com.baeldung.spring.data.redis.model.Student; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import com.baeldung.spring.data.redis.config.RedisConfig; +import com.baeldung.spring.data.redis.model.Student; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = RedisConfig.class) @@ -23,18 +26,18 @@ public class StudentRepositoryIntegrationTest { @Test public void whenSavingStudent_thenAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + final Student retrievedStudent = studentRepository.findById(student.getId()).get(); assertEquals(student.getId(), retrievedStudent.getId()); } @Test public void whenUpdatingStudent_thenAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); + studentRepository.save(student); student.setName("Richard Watson"); - studentRepository.saveStudent(student); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + final Student retrievedStudent = studentRepository.findById(student.getId()).get(); assertEquals(student.getName(), retrievedStudent.getName()); } @@ -42,18 +45,19 @@ public class StudentRepositoryIntegrationTest { public void whenSavingStudents_thenAllShouldAvailableOnRetrieval() throws Exception { final Student engStudent = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); final Student medStudent = new Student("Med2015001", "Gareth Houston", Student.Gender.MALE, 2); - studentRepository.saveStudent(engStudent); - studentRepository.saveStudent(medStudent); - final Map retrievedStudent = studentRepository.findAllStudents(); - assertEquals(retrievedStudent.size(), 2); + studentRepository.save(engStudent); + studentRepository.save(medStudent); + List students = new ArrayList<>(); + studentRepository.findAll().forEach(students::add); + assertEquals(students.size(), 2); } @Test public void whenDeletingStudent_thenNotAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); - studentRepository.deleteStudent(student.getId()); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + studentRepository.deleteById(student.getId()); + final Student retrievedStudent = studentRepository.findById(student.getId()).orElse(null); assertNull(retrievedStudent); } } \ No newline at end of file From b2372b50061766aa27e203d6a1f84a2e04fb4198 Mon Sep 17 00:00:00 2001 From: Nikhil Khatwani Date: Wed, 7 Feb 2018 19:46:42 +0530 Subject: [PATCH 29/48] Changes for BAEL-1472 --- persistence-modules/spring-data-redis/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-modules/spring-data-redis/pom.xml b/persistence-modules/spring-data-redis/pom.xml index 0dc51e790e..0b9075147d 100644 --- a/persistence-modules/spring-data-redis/pom.xml +++ b/persistence-modules/spring-data-redis/pom.xml @@ -79,7 +79,7 @@ org.springframework.data spring-data-commons - 2.0.3.RELEASE + ${spring-data-commons.version} From 6887bc10d1a3aa1d8b5778917c77c9047ef97dee Mon Sep 17 00:00:00 2001 From: shouvikbhattacharya Date: Wed, 7 Feb 2018 20:29:35 +0530 Subject: [PATCH 30/48] BAEL-1525: More changes. --- .../java/com/baeldung/string/Palindrome.java | 28 ++++++++++++++- .../string/WhenCheckingPalindrome.java | 36 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/core-java/src/main/java/com/baeldung/string/Palindrome.java b/core-java/src/main/java/com/baeldung/string/Palindrome.java index e339d92447..37284a5424 100644 --- a/core-java/src/main/java/com/baeldung/string/Palindrome.java +++ b/core-java/src/main/java/com/baeldung/string/Palindrome.java @@ -8,7 +8,33 @@ public class Palindrome { int forward = 0; int backward = length - 1; boolean palindrome = true; - while ((backward > forward)?(palindrome=(text.charAt(forward++) == text.charAt(backward--))):false); + while (backward > forward) { + char forwardChar = text.charAt(forward++); + char backwardChar = text.charAt(backward--); + if (forwardChar != backwardChar) + return false; + } return palindrome; } + + public boolean isPalindromeReverseTheString(String text) { + String reverse = ""; + text = text.toLowerCase(); + char[] plain = text.toCharArray(); + for (int i = plain.length - 1; i >= 0; i--) + reverse += plain[i]; + return reverse.equals(text); + } + + public boolean isPalindromeUsingStringBuilder(String text) { + StringBuilder plain = new StringBuilder(text); + StringBuilder reverse = plain.reverse(); + return reverse.equals(plain); + } + + public boolean isPalindromeUsingStringBuffer(String text) { + StringBuffer plain = new StringBuffer(text); + StringBuffer reverse = plain.reverse(); + return reverse.equals(plain); + } } diff --git a/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java b/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java index 691d74c751..eeaed09fff 100644 --- a/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java +++ b/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java @@ -34,4 +34,40 @@ public class WhenCheckingPalindrome { for(String sentence:sentences) Assert.assertTrue(palindrome.isPalindrome(sentence)); } + + @Test + public void whenReverseWord_shouldBePalindrome() { + for(String word:words) + Assert.assertTrue(palindrome.isPalindromeReverseTheString(word)); + } + + @Test + public void whenReverseSentence_shouldBePalindrome() { + for(String sentence:sentences) + Assert.assertTrue(palindrome.isPalindromeReverseTheString(sentence)); + } + + @Test + public void whenStringBuilderWord_shouldBePalindrome() { + for(String word:words) + Assert.assertTrue(palindrome.isPalindromeUsingStringBuilder(word)); + } + + @Test + public void whenStringBuilderSentence_shouldBePalindrome() { + for(String sentence:sentences) + Assert.assertTrue(palindrome.isPalindromeUsingStringBuilder(sentence)); + } + + @Test + public void whenStringBufferWord_shouldBePalindrome() { + for(String word:words) + Assert.assertTrue(palindrome.isPalindromeUsingStringBuffer(word)); + } + + @Test + public void whenStringBufferSentence_shouldBePalindrome() { + for(String sentence:sentences) + Assert.assertTrue(palindrome.isPalindromeUsingStringBuffer(sentence)); + } } From 0743dec07c59c0fecb8ac3ad0052457d5e6feaf6 Mon Sep 17 00:00:00 2001 From: iaforek Date: Thu, 8 Feb 2018 06:26:42 +0000 Subject: [PATCH 31/48] Extracted 'constraints' methods and renamed variables (#3580) * Code for Dependency Injection Article. * Added Java based configuration. Downloaded formatter.xml and reformatted all changed files. Manually changed tab into 4 spaces in XML configuration files. * BAEL-434 - Spring Roo project files generated by Spring Roo. No formatting applied. Added POM, java and resources folders. * Moved project from roo to spring-roo folder. * BAEL-838 Initial code showing how to remove last char - helper class and tests. * BAEL-838 Corrected Helper class and associated empty string test case. Added StringUtils.substing tests. * BAEL-838 Refromatted code using formatter.xml. Added Assert.assertEquals import. Renamed test to follow convention. Reordered tests. * BAEL-838 - Added regex method and updated tests. * BAEL-838 Added new line examples. * BAEL-838 Renamed RemoveLastChar class to StringHelper and added Java8 examples. Refactord code. * BAEL-838 Changed method names * BAEL-838 Tiny change to keep code consistant. Return null or empty. * BAEL-838 Removed unresolved conflict. * BAEL-821 New class that shows different rounding techniques. Updated POM. * BAEL-821 - Added unit test for different round methods. * BAEL-821 Changed test method name to follow the convention * BAEL-821 Added more test and updated round methods. * BAEL-837 - initial commit. A few examples of adding doubles. * BAEL-837 - Couple of smaller changes * BAEL-837 - Added jUnit test. * BAEL-579 Updated Spring Cloud Version I was getting error: java.lang.NoSuchMethodError: org.springframework.cloud.config.environment.Environment After version update, all is okay. * BAEL-579 Added actuator to Cloud Config Client. * BAEL-579 Enabled cloud bus and updated dependencies. * BAEL-579 Config Client using Spring Cloud Bus. * BAEL-579 Recreated Basic Config Server. * BAEL-579 Recreated Config Client. * BAEL-579 Removed test Git URL. * BAEL-579 Added Actuator to Config Client * BAEL-579 Added Spring Cloud Bus to Client. * BAEL-579 Server changes for Spring Cloud Bus Added dependencies and removed git.clone-on-start as this was causing server to throw errors after git properties change. * BAEL-579 Removed Git URL. * Revert "BAEL-579 Updated Spring Cloud Version" This reverts commit f775bf91e53a1ecfb9b70596688d7c8202bf495f. * Revert "BAEL-579 Config Client using Spring Cloud Bus." This reverts commit 1d96bc5761994a33af9a7a9aa5ab68604a5b44dc. * Revert "BAEL-579 Enabled cloud bus and updated dependencies." This reverts commit 7845da922d89d53506dd0fff387ea13694c50bc1. * Revert "BAEL-579 Added actuator to Cloud Config Client." This reverts commit 076657a26a57e0aa676989a4d97966a3b9d53e1c. * BAEL-579 Added missing dependency versions. * BAEL-579 Added missing dependency versions. * Updated gitignore * BAEL-1065 Simple performance check StringBuffer vs StringBuilder. * BAEL-1065 Added JMH benchmarks * BAEL-1298 Sudoku - Backtracking Algorithm * BAEL-1298 Sudoku - Backtracking Algorithm * BAEL-1298 Dancing Links Algorithm. Smaller changes to Backtracking * BAEL-1298 Resolve conflict - use most up-to-date POM * Updated code - mostly with CONSTANTS. Extracted methods. * Removed pointless Java8 code. Renamed constant * Extracted 'constraints' methods and renamed coverBoard variable * Extracted 'constraints' methods and renamed coverBoard variable --- .../sudoku/BacktrackingAlgorithm.java | 2 +- .../algorithms/sudoku/DancingLinks.java | 4 +- .../sudoku/DancingLinksAlgorithm.java | 87 +++++++++++-------- 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/BacktrackingAlgorithm.java b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/BacktrackingAlgorithm.java index dc2a324c12..ff426cbe68 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/BacktrackingAlgorithm.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/BacktrackingAlgorithm.java @@ -101,4 +101,4 @@ public class BacktrackingAlgorithm { } return true; } -} \ No newline at end of file +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinks.java b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinks.java index e5a02b7c91..d3cbb2bd02 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinks.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinks.java @@ -120,10 +120,10 @@ public class DancingLinks { } private static void printSolution(int[][] result) { - int N = result.length; + int size = result.length; for (int[] aResult : result) { StringBuilder ret = new StringBuilder(); - for (int j = 0; j < N; j++) { + for (int j = 0; j < size; j++) { ret.append(aResult[j]).append(" "); } System.out.println(ret); diff --git a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinksAlgorithm.java b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinksAlgorithm.java index 6b0f57a075..76b686afa6 100644 --- a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinksAlgorithm.java +++ b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinksAlgorithm.java @@ -39,70 +39,83 @@ public class DancingLinksAlgorithm { } private boolean[][] createExactCoverBoard() { - boolean[][] R = new boolean[BOARD_SIZE * BOARD_SIZE * MAX_VALUE][BOARD_SIZE * BOARD_SIZE * CONSTRAINTS]; + boolean[][] coverBoard = new boolean[BOARD_SIZE * BOARD_SIZE * MAX_VALUE][BOARD_SIZE * BOARD_SIZE * CONSTRAINTS]; int hBase = 0; + hBase = checkCellConstraint(coverBoard, hBase); + hBase = checkRowConstraint(coverBoard, hBase); + hBase = checkColumnConstraint(coverBoard, hBase); + checkSubsectionConstraint(coverBoard, hBase); + + return coverBoard; + } - // Cell constraint. - for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { - for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++, hBase++) { - for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++) { - int index = getIndex(r, c, n); - R[index][hBase] = true; - } - } - } - - // Row constrain. - for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { - for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { - for (int c1 = COVER_START_INDEX; c1 <= BOARD_SIZE; c1++) { - int index = getIndex(r, c1, n); - R[index][hBase] = true; - } - } - } - - // Column constraint. - for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++) { - for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { - for (int r1 = COVER_START_INDEX; r1 <= BOARD_SIZE; r1++) { - int index = getIndex(r1, c, n); - R[index][hBase] = true; - } - } - } - - // Subsection constraint + private int checkSubsectionConstraint(boolean[][] coverBoard, int hBase) { for (int br = COVER_START_INDEX; br <= BOARD_SIZE; br += SUBSECTION_SIZE) { for (int bc = COVER_START_INDEX; bc <= BOARD_SIZE; bc += SUBSECTION_SIZE) { for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { for (int rDelta = 0; rDelta < SUBSECTION_SIZE; rDelta++) { for (int cDelta = 0; cDelta < SUBSECTION_SIZE; cDelta++) { int index = getIndex(br + rDelta, bc + cDelta, n); - R[index][hBase] = true; + coverBoard[index][hBase] = true; } } } } } - return R; + return hBase; + } + + private int checkColumnConstraint(boolean[][] coverBoard, int hBase) { + for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++) { + for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { + for (int r1 = COVER_START_INDEX; r1 <= BOARD_SIZE; r1++) { + int index = getIndex(r1, c, n); + coverBoard[index][hBase] = true; + } + } + } + return hBase; + } + + private int checkRowConstraint(boolean[][] coverBoard, int hBase) { + for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { + for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { + for (int c1 = COVER_START_INDEX; c1 <= BOARD_SIZE; c1++) { + int index = getIndex(r, c1, n); + coverBoard[index][hBase] = true; + } + } + } + return hBase; + } + + private int checkCellConstraint(boolean[][] coverBoard, int hBase) { + for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { + for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++, hBase++) { + for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++) { + int index = getIndex(r, c, n); + coverBoard[index][hBase] = true; + } + } + } + return hBase; } private boolean[][] initializeExactCoverBoard(int[][] board) { - boolean[][] R = createExactCoverBoard(); + boolean[][] coverBoard = createExactCoverBoard(); for (int i = COVER_START_INDEX; i <= BOARD_SIZE; i++) { for (int j = COVER_START_INDEX; j <= BOARD_SIZE; j++) { int n = board[i - 1][j - 1]; if (n != NO_VALUE) { for (int num = MIN_VALUE; num <= MAX_VALUE; num++) { if (num != n) { - Arrays.fill(R[getIndex(i, j, num)], false); + Arrays.fill(coverBoard[getIndex(i, j, num)], false); } } } } } - return R; + return coverBoard; } } \ No newline at end of file From 2b2b78cbf28072ed643c1b37cfd5929bada148b3 Mon Sep 17 00:00:00 2001 From: felipeazv Date: Thu, 8 Feb 2018 10:24:21 +0100 Subject: [PATCH 32/48] [BAEL-1449]-Combining Publishers (Project Reactor) --- .../reactor/core/CombiningPublishersTest.java | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java diff --git a/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java new file mode 100644 index 0000000000..f33f911274 --- /dev/null +++ b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java @@ -0,0 +1,107 @@ +package com.baeldung.reactor.core; + +import java.time.Duration; + +import org.junit.Test; + +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +public class CombiningPublishersTest { + + private static Integer min = 1; + private static Integer max = 5; + + private static Flux evenNumbers = Flux.range(min, max).filter(x -> x % 2 == 0); + private static Flux oddNumbers = Flux.range(min, max).filter(x -> x % 2 > 0); + + + @Test + public void testMerge() { + Flux fluxOfIntegers = Flux.merge( + evenNumbers, + oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void testMergeWithDelayedElements() { + Flux fluxOfIntegers = Flux.merge( + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(1) + .expectNext(2) + .expectNext(3) + .expectNext(5) + .expectNext(4) + .expectComplete() + .verify(); + } + + @Test + public void testConcat() { + Flux fluxOfIntegers = Flux.concat( + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void testConcatWith() { + Flux fluxOfIntegers = evenNumbers + .concatWith(oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void testCombineLatest() { + Flux fluxOfIntegers = Flux.combineLatest( + evenNumbers, + oddNumbers, + (a, b) -> a + b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(5) + .expectNext(7) + .expectNext(9) + .expectComplete() + .verify(); + + } + + @Test + public void testCombineLatest1() { + StepVerifier.create(Flux.combineLatest(obj -> (int) obj[1], evenNumbers, oddNumbers)) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .verifyComplete(); + } + +} From 19ef04d07cb25d48f7c6b8ab6e8f0ea24556d46d Mon Sep 17 00:00:00 2001 From: felipeazv Date: Thu, 8 Feb 2018 10:30:46 +0100 Subject: [PATCH 33/48] [BAEL-1449]-Combining Publishers (Project Reactor) --- reactor-core/pom.xml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/reactor-core/pom.xml b/reactor-core/pom.xml index 12f481c96f..d387471d56 100644 --- a/reactor-core/pom.xml +++ b/reactor-core/pom.xml @@ -26,11 +26,17 @@ ${assertj.version} test - + + + io.projectreactor + reactor-test + ${reactor-core.version} + test + - 3.0.5.RELEASE + 3.1.3.RELEASE 3.6.1 From 5ce6ad7d8f42af90c131f2efe107be303b143f2c Mon Sep 17 00:00:00 2001 From: felipeazv Date: Thu, 8 Feb 2018 11:39:09 +0100 Subject: [PATCH 34/48] [BAEL-1449]-Combining Publishers (Project Reactor) --- .../reactor/core/CombiningPublishersTest.java | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java index f33f911274..9d5d094875 100644 --- a/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java +++ b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java @@ -103,5 +103,80 @@ public class CombiningPublishersTest { .expectNext(5) .verifyComplete(); } - + + @Test + public void testMergeSequential() { + Flux fluxOfIntegers = Flux.mergeSequential( + evenNumbers, + oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + + @Test + public void testMergeDelayError() { + Flux fluxOfIntegers = Flux.mergeDelayError(1, + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(1) + .expectNext(2) + .expectNext(3) + .expectNext(5) + .expectNext(4) + .expectComplete() + .verify(); + } + + @Test + public void testMergeWith() { + Flux fluxOfIntegers = evenNumbers.mergeWith(oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void testZip() { + Flux fluxOfIntegers = Flux.zip( + evenNumbers, + oddNumbers, + (a, b) -> a + b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(3) + .expectNext(7) + .expectComplete() + .verify(); + } + + @Test + public void testZipWith() { + Flux fluxOfIntegers = evenNumbers + .zipWith(oddNumbers, + (a, b) -> a * b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(12) + .expectComplete() + .verify(); + } + + } From 9d9045f130e647ccc48f78c11a3b7980880c2a72 Mon Sep 17 00:00:00 2001 From: shouvikbhattacharya Date: Thu, 8 Feb 2018 21:04:46 +0530 Subject: [PATCH 35/48] BAEL-1525: New changes added. --- .../java/com/baeldung/string/Palindrome.java | 17 +++++++- .../string/WhenCheckingPalindrome.java | 41 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/core-java/src/main/java/com/baeldung/string/Palindrome.java b/core-java/src/main/java/com/baeldung/string/Palindrome.java index 37284a5424..03b65d1a84 100644 --- a/core-java/src/main/java/com/baeldung/string/Palindrome.java +++ b/core-java/src/main/java/com/baeldung/string/Palindrome.java @@ -3,7 +3,8 @@ package com.baeldung.string; public class Palindrome { public boolean isPalindrome(String text) { - text = text.replaceAll("\\s+", "").toLowerCase(); + text = text.replaceAll("\\s+", "") + .toLowerCase(); int length = text.length(); int forward = 0; int backward = length - 1; @@ -19,7 +20,7 @@ public class Palindrome { public boolean isPalindromeReverseTheString(String text) { String reverse = ""; - text = text.toLowerCase(); + text = text.replaceAll("\\s+", "").toLowerCase(); char[] plain = text.toCharArray(); for (int i = plain.length - 1; i >= 0; i--) reverse += plain[i]; @@ -37,4 +38,16 @@ public class Palindrome { StringBuffer reverse = plain.reverse(); return reverse.equals(plain); } + + public boolean isPalindromeRecursive(String text, int forward, int backward) { + if (forward == backward) + return true; + if ((text.charAt(forward)) != (text.charAt(backward))) + return false; + if (forward < backward + 1) { + return isPalindromeRecursive(text, forward + 1, backward - 1); + } + + return true; + } } diff --git a/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java b/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java index eeaed09fff..e3655a3140 100644 --- a/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java +++ b/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java @@ -1,5 +1,7 @@ package com.baeldung.string; +import java.util.Arrays; + import org.junit.Assert; import org.junit.Test; @@ -68,6 +70,45 @@ public class WhenCheckingPalindrome { @Test public void whenStringBufferSentence_shouldBePalindrome() { for(String sentence:sentences) + Assert.assertTrue(palindrome.isPalindromeUsingStringBuffer(sentence)); } + + @Test + public void whenPalindromeRecursive_wordShouldBePalindrome() { + for(String word:words) { + word = word.replaceAll("\\s+", "").toLowerCase(); + int backward = word.length()-1; + + Assert.assertTrue(palindrome.isPalindromeRecursive(word,0,backward)); + } + } + + @Test + public void whenPalindromeRecursive_sentenceShouldBePalindrome() { + for(String sentence:sentences) { + sentence = sentence.replaceAll("\\s+", "").toLowerCase(); + int backward = sentence.length()-1; + + Assert.assertTrue(palindrome.isPalindromeRecursive(sentence,0,backward)); + } + } + + @Test + public void whenPalindromeStreams_wordShouldBePalindrome() { + String[] expected = Arrays.stream(words) + .filter(palindrome::isPalindrome) + .toArray(String[]::new); + + Assert.assertArrayEquals(expected, words); + } + + @Test + public void whenPalindromeStreams_sentenceShouldBePalindrome() { + String[] expected = Arrays.stream(sentences) + .filter(palindrome::isPalindrome) + .toArray(String[]::new); + + Assert.assertArrayEquals(expected, sentences); + } } From 8b279673c493f43ea821c90ab9fe3f4995276b49 Mon Sep 17 00:00:00 2001 From: Alessio Stalla Date: Thu, 8 Feb 2018 23:05:13 +0100 Subject: [PATCH 36/48] Code for BAEL-894 - regular expressions in Kotlin (#3618) --- .../com/baeldung/kotlin/stdlib/RegexTest.kt | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt new file mode 100644 index 0000000000..eeb587ee22 --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt @@ -0,0 +1,128 @@ +package com.baeldung.kotlin.stdlib + +import org.junit.Test +import java.beans.ExceptionListener +import java.beans.XMLEncoder +import java.io.* +import java.lang.Exception +import kotlin.test.* +import kotlin.text.RegexOption.* + +class RegexTest { + + @Test + fun whenRegexIsInstantiated_thenIsEqualToToRegexMethod() { + val pattern = """a([bc]+)d?\\""" + + assertEquals(Regex.fromLiteral(pattern).pattern, pattern) + assertEquals(pattern, Regex(pattern).pattern) + assertEquals(pattern, pattern.toRegex().pattern) + } + + @Test + fun whenRegexMatches_thenResultIsTrue() { + val regex = """a([bc]+)d?""".toRegex() + + assertTrue(regex.containsMatchIn("xabcdy")) + assertTrue(regex.matches("abcd")) + assertFalse(regex matches "xabcdy") + } + + @Test + fun givenCompletelyMatchingRegex_whenMatchResult_thenDestructuring() { + val regex = """a([bc]+)d?""".toRegex() + + assertNull(regex.matchEntire("xabcdy")) + + val matchResult = regex.matchEntire("abbccbbd") + + assertNotNull(matchResult) + assertEquals(matchResult!!.value, matchResult.groupValues[0]) + assertEquals(matchResult.destructured.toList(), matchResult.groupValues.drop(1)) + assertEquals("bbccbb", matchResult.destructured.component1()) + assertNull(matchResult.next()) + } + + @Test + fun givenPartiallyMatchingRegex_whenMatchResult_thenGroups() { + val regex = """a([bc]+)d?""".toRegex() + var matchResult = regex.find("abcb abbd") + + assertNotNull(matchResult) + assertEquals(matchResult!!.value, matchResult.groupValues[0]) + assertEquals("abcb", matchResult.value) + assertEquals(IntRange(0, 3), matchResult.range) + assertEquals(listOf("abcb", "bcb"), matchResult.groupValues) + assertEquals(matchResult.destructured.toList(), matchResult.groupValues.drop(1)) + + matchResult = matchResult.next() + + assertNotNull(matchResult) + assertEquals("abbd", matchResult!!.value) + assertEquals("bb", matchResult.groupValues[1]) + + matchResult = matchResult.next() + + assertNull(matchResult) + } + + @Test + fun givenPartiallyMatchingRegex_whenMatchResult_thenDestructuring() { + val regex = """([\w\s]+) is (\d+) years old""".toRegex() + val matchResult = regex.find("Mickey Mouse is 95 years old") + val (name, age) = matchResult!!.destructured + + assertEquals("Mickey Mouse", name) + assertEquals("95", age) + } + + @Test + fun givenNonMatchingRegex_whenFindCalled_thenNull() { + val regex = """a([bc]+)d?""".toRegex() + val matchResult = regex.find("foo") + + assertNull(matchResult) + } + + @Test + fun givenNonMatchingRegex_whenFindAllCalled_thenEmptySet() { + val regex = """a([bc]+)d?""".toRegex() + val matchResults = regex.findAll("foo") + + assertNotNull(matchResults) + assertTrue(matchResults.none()) + } + + @Test + fun whenReplace_thenReplacement() { + val regex = """(red|green|blue)""".toRegex() + val beautiful = "Roses are red, Violets are blue" + val grim = regex.replace(beautiful, "dark") + val shiny = regex.replaceFirst(beautiful, "rainbow") + + assertEquals("Roses are dark, Violets are dark", grim) + assertEquals("Roses are rainbow, Violets are blue", shiny) + } + + @Test + fun whenComplexReplace_thenReplacement() { + val regex = """(red|green|blue)""".toRegex() + val beautiful = "Roses are red, Violets are blue" + val reallyBeautiful = regex.replace(beautiful) { + matchResult -> matchResult.value.toUpperCase() + "!" + } + + assertEquals("Roses are RED!, Violets are BLUE!", reallyBeautiful) + } + + @Test + fun whenSplit_thenList() { + val regex = """\W+""".toRegex() + val beautiful = "Roses are red, Violets are blue" + + assertEquals(listOf("Roses", "are", "red", "Violets", "are", "blue"), regex.split(beautiful)) + assertEquals(listOf("Roses", "are", "red", "Violets are blue"), regex.split(beautiful, 4)) + assertEquals(regex.toPattern().split(beautiful).asList(), regex.split(beautiful)) + } + +} \ No newline at end of file From 65267041c31b198960404408a45d872f9476656c Mon Sep 17 00:00:00 2001 From: Graham Cox Date: Fri, 9 Feb 2018 12:11:19 +0000 Subject: [PATCH 37/48] Examples for Infix Functions article (#3606) --- .../com/baeldung/kotlin/InfixFunctionsTest.kt | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt new file mode 100644 index 0000000000..fc4286460a --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt @@ -0,0 +1,51 @@ +package com.baeldung.kotlin + +import org.junit.Assert +import org.junit.Test + +class InfixFunctionsTest { + @Test + fun testColours() { + val color = 0x123456 + val red = (color and 0xff0000) shr 16 + val green = (color and 0x00ff00) shr 8 + val blue = (color and 0x0000ff) shr 0 + + Assert.assertEquals(0x12, red) + Assert.assertEquals(0x34, green) + Assert.assertEquals(0x56, blue) + } + + @Test + fun testNewAssertions() { + class Assertion(private val target: T) { + infix fun isEqualTo(other: T) { + Assert.assertEquals(other, target) + } + + infix fun isDifferentFrom(other: T) { + Assert.assertNotEquals(other, target) + } + } + + val result = Assertion(5) + + result isEqualTo 5 + + // The following two lines are expected to fail + // result isEqualTo 6 + // result isDifferentFrom 5 + } + + @Test + fun testNewStringMethod() { + infix fun String.substringMatches(r: Regex) : List { + return r.findAll(this) + .map { it.value } + .toList() + } + + val matches = "a bc def" substringMatches ".*? ".toRegex() + Assert.assertEquals(listOf("a ", "bc "), matches) + } +} From d4522c7c16acc1c0f0c0e4eddd4e4e6165857b5c Mon Sep 17 00:00:00 2001 From: Dassi orleando Date: Fri, 9 Feb 2018 22:25:13 +0100 Subject: [PATCH 38/48] BAEL-1285: Update Jackson articles (#3623) * BAEL-1216: improve tests * BAEL-1448: Update Spring 5 articles to use the release version * Setting up the Maven Wrapper on a maven project * Add Maven Wrapper on spring-boot module * simple add * BAEL-976: Update spring version * BAEL-1273: Display RSS feed with spring mvc (AbstractRssFeedView) * Move RSS feed with Spring MVC from spring-boot to spring-mvc-simple * BAEL-1285: Update Jackson articles * BAEL-1273: implement both MVC and Rest approach to serve RSS content --- .gitignore | 1 + jackson/pom.xml | 2 +- spring-mvc-java/pom.xml | 2 +- .../ApplicationConfiguration.java | 25 ++++++++-- .../controller/rss/ArticleRssController.java | 49 ++++++++++++++++++- .../rss/ArticleRssFeedViewResolver.java | 15 ++++++ 6 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java diff --git a/.gitignore b/.gitignore index 08f570ad06..693a35c176 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ spring-call-getters-using-reflection/.mvn/wrapper/maven-wrapper.properties spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties *.springBeans +20171220-JMeter.csv diff --git a/jackson/pom.xml b/jackson/pom.xml index 001fde5021..2587e61ac1 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -129,7 +129,7 @@ - 2.9.2 + 2.9.4 19.0 diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index b939f0496d..9d90ba2dbf 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -297,7 +297,7 @@ 4.3.4.RELEASE 4.2.0.RELEASE 2.1.5.RELEASE - 2.8.5 + 2.9.4 5.2.5.Final diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java index b9a8336bf2..69c45d90b3 100644 --- a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java @@ -1,14 +1,21 @@ package com.baeldung.spring.configuration; +import com.baeldung.spring.controller.rss.ArticleRssFeedViewResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.accept.ContentNegotiationManager; + +import java.util.List; +import java.util.ArrayList; @Configuration @EnableWebMvc @@ -21,11 +28,19 @@ class ApplicationConfiguration implements WebMvcConfigurer { } @Bean - public InternalResourceViewResolver jspViewResolver() { - InternalResourceViewResolver bean = new InternalResourceViewResolver(); - bean.setPrefix("/WEB-INF/views/"); - bean.setSuffix(".jsp"); - return bean; + public ContentNegotiatingViewResolver viewResolver(ContentNegotiationManager cnManager) { + ContentNegotiatingViewResolver cnvResolver = new ContentNegotiatingViewResolver(); + cnvResolver.setContentNegotiationManager(cnManager); + List resolvers = new ArrayList<>(); + + InternalResourceViewResolver bean = new InternalResourceViewResolver("/WEB-INF/views/",".jsp"); + ArticleRssFeedViewResolver articleRssFeedViewResolver = new ArticleRssFeedViewResolver(); + + resolvers.add(bean); + resolvers.add(articleRssFeedViewResolver); + + cnvResolver.setViewResolvers(resolvers); + return cnvResolver; } @Bean diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java index 1f51b238ac..8f23076e8e 100644 --- a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java @@ -1,14 +1,59 @@ package com.baeldung.spring.controller.rss; +import com.rometools.rome.feed.synd.*; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedOutput; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; @Controller public class ArticleRssController { - @GetMapping(value = "/rss", produces = "application/*") - public String articleFeed() { + @GetMapping(value = "/rssMvc") + public String articleMvcFeed() { return "articleFeedView"; } + @GetMapping(value = "/rssRest", produces = "application/rss+xml") + @ResponseBody + public String articleRestFeed() throws FeedException { + SyndFeed feed = new SyndFeedImpl(); + feed.setFeedType("rss_2.0"); + feed.setLink("http://localhost:8080/spring-mvc-simple/rss"); + feed.setTitle("Article Feed"); + feed.setDescription("Article Feed Description"); + feed.setPublishedDate(new Date()); + + List list = new ArrayList(); + + SyndEntry item1 = new SyndEntryImpl(); + item1.setLink("http://www.baeldung.com/netty-exception-handling"); + item1.setTitle("Exceptions in Netty"); + SyndContent description1 = new SyndContentImpl(); + description1.setValue("In this quick article, we’ll be looking at exception handling in Netty."); + item1.setDescription(description1); + item1.setPublishedDate(new Date()); + item1.setAuthor("Carlos"); + + SyndEntry item2 = new SyndEntryImpl(); + item2.setLink("http://www.baeldung.com/cockroachdb-java"); + item2.setTitle("Guide to CockroachDB in Java"); + SyndContent description2 = new SyndContentImpl(); + description2.setValue("This tutorial is an introductory guide to using CockroachDB with Java."); + item2.setDescription(description2); + item2.setPublishedDate(new Date()); + item2.setAuthor("Baeldung"); + + list.add(item1); + list.add(item2); + feed.setEntries(list); + + return new SyndFeedOutput().outputString(feed); + } + } diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java new file mode 100644 index 0000000000..6be06c4812 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.controller.rss; + +import org.springframework.web.servlet.View; +import org.springframework.web.servlet.ViewResolver; + +import java.util.Locale; + +public class ArticleRssFeedViewResolver implements ViewResolver { + + @Override + public View resolveViewName(String s, Locale locale) throws Exception { + ArticleFeedView articleFeedView = new ArticleFeedView(); + return articleFeedView; + } +} From c67eca5faa952fa1aaa33fc92ac4a1915efc36bc Mon Sep 17 00:00:00 2001 From: Adam InTae Gerard Date: Fri, 9 Feb 2018 22:55:34 -0800 Subject: [PATCH 39/48] Issue #3628 - Closed unclosed input stream --- .../controller/MultipartController.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java index 1cc8261f7c..a693bf039f 100644 --- a/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java +++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java @@ -25,14 +25,20 @@ public class MultipartController { try { InputStream in = file.getInputStream(); String path = new File(".").getAbsolutePath(); - FileOutputStream f = new FileOutputStream(path.substring(0, path.length()-1)+ "/uploads/" + file.getOriginalFilename()); - int ch; - while ((ch = in.read()) != -1) { - f.write(ch); + FileOutputStream f = new FileOutputStream(path.substring(0, path.length() - 1) + "/uploads/" + file.getOriginalFilename()); + try { + int ch; + while ((ch = in.read()) != -1) { + f.write(ch); + } + modelAndView.getModel().put("message", "File uploaded successfully!"); + } catch (Exception e) { + System.out.println("Exception uploading multipart: " + e); + } finally { + f.flush(); + f.close(); + in.close(); } - f.flush(); - f.close(); - modelAndView.getModel().put("message", "File uploaded successfully!"); } catch (Exception e) { System.out.println("Exception uploading multipart: " + e); } From 50deec5b5cb8c1ae7d732ffd5726933c1e98f956 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 10 Feb 2018 17:42:52 +0200 Subject: [PATCH 40/48] refactor streams ex --- .../java/com/baeldung/string/Palindrome.java | 8 ++++ ...ingPalindrome.java => PalindromeTest.java} | 40 +++++++++---------- 2 files changed, 26 insertions(+), 22 deletions(-) rename core-java/src/test/java/com/baeldung/string/{WhenCheckingPalindrome.java => PalindromeTest.java} (63%) diff --git a/core-java/src/main/java/com/baeldung/string/Palindrome.java b/core-java/src/main/java/com/baeldung/string/Palindrome.java index 03b65d1a84..d70a89525a 100644 --- a/core-java/src/main/java/com/baeldung/string/Palindrome.java +++ b/core-java/src/main/java/com/baeldung/string/Palindrome.java @@ -1,5 +1,7 @@ package com.baeldung.string; +import java.util.stream.IntStream; + public class Palindrome { public boolean isPalindrome(String text) { @@ -50,4 +52,10 @@ public class Palindrome { return true; } + + public boolean isPalindromeUsingIntStream(String text) { + String temp = text.replaceAll("\\s+", "").toLowerCase(); + return IntStream.range(0, temp.length() / 2) + .noneMatch(i -> temp.charAt(i) != temp.charAt(temp.length() - i - 1)); + } } diff --git a/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java b/core-java/src/test/java/com/baeldung/string/PalindromeTest.java similarity index 63% rename from core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java rename to core-java/src/test/java/com/baeldung/string/PalindromeTest.java index e3655a3140..ef78a2d840 100644 --- a/core-java/src/test/java/com/baeldung/string/WhenCheckingPalindrome.java +++ b/core-java/src/test/java/com/baeldung/string/PalindromeTest.java @@ -2,10 +2,10 @@ package com.baeldung.string; import java.util.Arrays; -import org.junit.Assert; +import static org.junit.Assert.*; import org.junit.Test; -public class WhenCheckingPalindrome { +public class PalindromeTest { private String[] words = { "Anna", @@ -28,50 +28,50 @@ public class WhenCheckingPalindrome { @Test public void whenWord_shouldBePalindrome() { for(String word:words) - Assert.assertTrue(palindrome.isPalindrome(word)); + assertTrue(palindrome.isPalindrome(word)); } @Test public void whenSentence_shouldBePalindrome() { for(String sentence:sentences) - Assert.assertTrue(palindrome.isPalindrome(sentence)); + assertTrue(palindrome.isPalindrome(sentence)); } @Test public void whenReverseWord_shouldBePalindrome() { for(String word:words) - Assert.assertTrue(palindrome.isPalindromeReverseTheString(word)); + assertTrue(palindrome.isPalindromeReverseTheString(word)); } @Test public void whenReverseSentence_shouldBePalindrome() { for(String sentence:sentences) - Assert.assertTrue(palindrome.isPalindromeReverseTheString(sentence)); + assertTrue(palindrome.isPalindromeReverseTheString(sentence)); } @Test public void whenStringBuilderWord_shouldBePalindrome() { for(String word:words) - Assert.assertTrue(palindrome.isPalindromeUsingStringBuilder(word)); + assertTrue(palindrome.isPalindromeUsingStringBuilder(word)); } @Test public void whenStringBuilderSentence_shouldBePalindrome() { for(String sentence:sentences) - Assert.assertTrue(palindrome.isPalindromeUsingStringBuilder(sentence)); + assertTrue(palindrome.isPalindromeUsingStringBuilder(sentence)); } @Test public void whenStringBufferWord_shouldBePalindrome() { for(String word:words) - Assert.assertTrue(palindrome.isPalindromeUsingStringBuffer(word)); + assertTrue(palindrome.isPalindromeUsingStringBuffer(word)); } @Test public void whenStringBufferSentence_shouldBePalindrome() { for(String sentence:sentences) - Assert.assertTrue(palindrome.isPalindromeUsingStringBuffer(sentence)); + assertTrue(palindrome.isPalindromeUsingStringBuffer(sentence)); } @Test @@ -80,7 +80,7 @@ public class WhenCheckingPalindrome { word = word.replaceAll("\\s+", "").toLowerCase(); int backward = word.length()-1; - Assert.assertTrue(palindrome.isPalindromeRecursive(word,0,backward)); + assertTrue(palindrome.isPalindromeRecursive(word,0,backward)); } } @@ -90,25 +90,21 @@ public class WhenCheckingPalindrome { sentence = sentence.replaceAll("\\s+", "").toLowerCase(); int backward = sentence.length()-1; - Assert.assertTrue(palindrome.isPalindromeRecursive(sentence,0,backward)); + assertTrue(palindrome.isPalindromeRecursive(sentence,0,backward)); } } @Test public void whenPalindromeStreams_wordShouldBePalindrome() { - String[] expected = Arrays.stream(words) - .filter(palindrome::isPalindrome) - .toArray(String[]::new); - - Assert.assertArrayEquals(expected, words); + for(String word:words) { + assertTrue(palindrome.isPalindromeUsingIntStream(word)); + } } @Test public void whenPalindromeStreams_sentenceShouldBePalindrome() { - String[] expected = Arrays.stream(sentences) - .filter(palindrome::isPalindrome) - .toArray(String[]::new); - - Assert.assertArrayEquals(expected, sentences); + for(String sentence:sentences) { + assertTrue(palindrome.isPalindromeUsingIntStream(sentence)); + } } } From 4c044fcaeec33a3b68637f751672a8f48de74c83 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 10 Feb 2018 17:45:01 +0200 Subject: [PATCH 41/48] remove imports --- core-java/src/test/java/com/baeldung/string/PalindromeTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core-java/src/test/java/com/baeldung/string/PalindromeTest.java b/core-java/src/test/java/com/baeldung/string/PalindromeTest.java index ef78a2d840..d1a05b6617 100644 --- a/core-java/src/test/java/com/baeldung/string/PalindromeTest.java +++ b/core-java/src/test/java/com/baeldung/string/PalindromeTest.java @@ -1,7 +1,5 @@ package com.baeldung.string; -import java.util.Arrays; - import static org.junit.Assert.*; import org.junit.Test; From 7c6a4b0b4dc5250faf6b17cac8a69fece05f58d1 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 10 Feb 2018 18:48:41 +0200 Subject: [PATCH 42/48] Update Palindrome.java --- core-java/src/main/java/com/baeldung/string/Palindrome.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core-java/src/main/java/com/baeldung/string/Palindrome.java b/core-java/src/main/java/com/baeldung/string/Palindrome.java index d70a89525a..0759787249 100644 --- a/core-java/src/main/java/com/baeldung/string/Palindrome.java +++ b/core-java/src/main/java/com/baeldung/string/Palindrome.java @@ -58,4 +58,5 @@ public class Palindrome { return IntStream.range(0, temp.length() / 2) .noneMatch(i -> temp.charAt(i) != temp.charAt(temp.length() - i - 1)); } + } From 3c371bea4587ed754e2e28b42873fead3af75695 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 10 Feb 2018 19:04:31 +0200 Subject: [PATCH 43/48] rename projects (#3604) --- .../{oauth2client => auth-client}/pom.xml | 4 ++-- .../src/main/java/com/baeldung/CloudSite.java | 0 .../com/baeldung/config/SiteSecurityConfigurer.java | 0 .../baeldung/controller/CloudSiteController.java | 0 .../java/com/baeldung/filters/SimpleFilter.java | 0 .../src/main/resources/application.properties | 0 .../src/main/resources/application.yml | 0 .../src/main/resources/templates/personinfo.html | 0 .../springoath2/Springoath2ApplicationTests.java | 0 .../{personresource => auth-resource}/pom.xml | 4 ++-- .../src/main/java/com/baeldung/Application.java | 0 .../com/baeldung/config/ResourceConfigurer.java | 0 .../baeldung/controller/PersonInfoController.java | 0 .../src/main/java/com/baeldung/model/Person.java | 0 .../src/main/resources/application.yml | 0 .../PersonserviceApplicationTests.java | 0 .../{authserver => auth-server}/pom.xml | 2 +- .../src/main/java/com/baeldung/AuthServer.java | 0 .../com/baeldung/config/AuthServerConfigurer.java | 0 .../baeldung/config/ResourceServerConfigurer.java | 0 .../java/com/baeldung/config/WebMvcConfigurer.java | 0 .../com/baeldung/config/WebSecurityConfigurer.java | 0 .../com/baeldung/controller/ResourceController.java | 0 .../src/main/resources/application.yml | 0 .../src/main/resources/certificate/mykeystore.jks | Bin .../src/main/resources/templates/login.html | 0 26 files changed, 5 insertions(+), 5 deletions(-) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/pom.xml (97%) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/src/main/java/com/baeldung/CloudSite.java (100%) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java (100%) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/src/main/java/com/baeldung/controller/CloudSiteController.java (100%) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/src/main/java/com/baeldung/filters/SimpleFilter.java (100%) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/src/main/resources/application.properties (100%) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/src/main/resources/application.yml (100%) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/src/main/resources/templates/personinfo.html (100%) rename spring-cloud/spring-cloud-security/{oauth2client => auth-client}/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java (100%) rename spring-cloud/spring-cloud-security/{personresource => auth-resource}/pom.xml (96%) rename spring-cloud/spring-cloud-security/{personresource => auth-resource}/src/main/java/com/baeldung/Application.java (100%) rename spring-cloud/spring-cloud-security/{personresource => auth-resource}/src/main/java/com/baeldung/config/ResourceConfigurer.java (100%) rename spring-cloud/spring-cloud-security/{personresource => auth-resource}/src/main/java/com/baeldung/controller/PersonInfoController.java (100%) rename spring-cloud/spring-cloud-security/{personresource => auth-resource}/src/main/java/com/baeldung/model/Person.java (100%) rename spring-cloud/spring-cloud-security/{personresource => auth-resource}/src/main/resources/application.yml (100%) rename spring-cloud/spring-cloud-security/{personresource => auth-resource}/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/pom.xml (96%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/java/com/baeldung/AuthServer.java (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/java/com/baeldung/config/AuthServerConfigurer.java (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/java/com/baeldung/config/ResourceServerConfigurer.java (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/java/com/baeldung/config/WebMvcConfigurer.java (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/java/com/baeldung/config/WebSecurityConfigurer.java (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/java/com/baeldung/controller/ResourceController.java (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/resources/application.yml (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/resources/certificate/mykeystore.jks (100%) rename spring-cloud/spring-cloud-security/{authserver => auth-server}/src/main/resources/templates/login.html (100%) diff --git a/spring-cloud/spring-cloud-security/oauth2client/pom.xml b/spring-cloud/spring-cloud-security/auth-client/pom.xml similarity index 97% rename from spring-cloud/spring-cloud-security/oauth2client/pom.xml rename to spring-cloud/spring-cloud-security/auth-client/pom.xml index fd1c6964e1..5213b93f9a 100644 --- a/spring-cloud/spring-cloud-security/oauth2client/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-client/pom.xml @@ -3,11 +3,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung - oauth2client + auth-client 0.0.1-SNAPSHOT jar - oauth2client + auth-client Demo project for Spring Boot diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/CloudSite.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/CloudSite.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/CloudSite.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/CloudSite.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/controller/CloudSiteController.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/controller/CloudSiteController.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/controller/CloudSiteController.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/controller/CloudSiteController.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/filters/SimpleFilter.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/filters/SimpleFilter.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.properties b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.properties rename to spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/templates/personinfo.html b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/templates/personinfo.html similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/templates/personinfo.html rename to spring-cloud/spring-cloud-security/auth-client/src/main/resources/templates/personinfo.html diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java b/spring-cloud/spring-cloud-security/auth-client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java rename to spring-cloud/spring-cloud-security/auth-client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java diff --git a/spring-cloud/spring-cloud-security/personresource/pom.xml b/spring-cloud/spring-cloud-security/auth-resource/pom.xml similarity index 96% rename from spring-cloud/spring-cloud-security/personresource/pom.xml rename to spring-cloud/spring-cloud-security/auth-resource/pom.xml index ca1ff82515..2c54d24e7d 100644 --- a/spring-cloud/spring-cloud-security/personresource/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-resource/pom.xml @@ -4,11 +4,11 @@ 4.0.0 com.baeldung - personresource + auth-resource 0.0.1-SNAPSHOT jar - personresource + auth-resource Demo project for Spring Boot diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/Application.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/Application.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/Application.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/Application.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/config/ResourceConfigurer.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/config/ResourceConfigurer.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/controller/PersonInfoController.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/controller/PersonInfoController.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/model/Person.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/model/Person.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/model/Person.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/model/Person.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/personresource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java b/spring-cloud/spring-cloud-security/auth-resource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java rename to spring-cloud/spring-cloud-security/auth-resource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java diff --git a/spring-cloud/spring-cloud-security/authserver/pom.xml b/spring-cloud/spring-cloud-security/auth-server/pom.xml similarity index 96% rename from spring-cloud/spring-cloud-security/authserver/pom.xml rename to spring-cloud/spring-cloud-security/auth-server/pom.xml index ed88ac046b..ab30f3f2ec 100644 --- a/spring-cloud/spring-cloud-security/authserver/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-server/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.baeldung - authserver + auth-server 0.0.1-SNAPSHOT diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/AuthServer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/AuthServer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/AuthServer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/AuthServer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/AuthServerConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/AuthServerConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/ResourceServerConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/ResourceServerConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/ResourceServerConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/ResourceServerConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebMvcConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebMvcConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebSecurityConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebSecurityConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/controller/ResourceController.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/controller/ResourceController.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/controller/ResourceController.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/controller/ResourceController.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/certificate/mykeystore.jks b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/certificate/mykeystore.jks similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/certificate/mykeystore.jks rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/certificate/mykeystore.jks diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/templates/login.html b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/templates/login.html similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/templates/login.html rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/templates/login.html From ef8276dd1a62e528a35696f6e334285ed0c3c5e8 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sat, 10 Feb 2018 19:11:06 +0200 Subject: [PATCH 44/48] remove project from build --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index ca6d4afe82..fc0c8f8ba7 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,9 @@ core-java core-java-io core-java-8 + couchbase deltaspike From d488e693017a7eba978c5cf9ce4cf81e12122f39 Mon Sep 17 00:00:00 2001 From: linhvovn Date: Sun, 11 Feb 2018 01:28:00 +0800 Subject: [PATCH 45/48] [BAEL 1382] Update Unit Test (#3630) * [tlinh2110-BAEL1382] Add Security in SI * [tlinh2110-BAEL1382] Upgrade to Spring 5 & add Logger * [tlinh2110-BAEL-1382] Update Unit Test --- .../si/TestSpringIntegrationSecurity.java | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java index 45dcb1e836..9ae82af2dc 100644 --- a/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java +++ b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java @@ -1,8 +1,11 @@ package com.baeldung.si; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import org.hamcrest.core.IsInstanceOf; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.SubscribableChannel; @@ -21,6 +24,9 @@ import com.baeldung.si.security.SecurityConfig; @ContextConfiguration(classes = { SecurityConfig.class, SecuredDirectChannel.class, MessageConsumer.class }) public class TestSpringIntegrationSecurity { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Autowired SubscribableChannel startDirectChannel; @@ -34,34 +40,28 @@ public class TestSpringIntegrationSecurity { startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); } - @Test(expected = AccessDeniedException.class) + @Test @WithMockUser(username = "jane", roles = { "LOGGER" }) - public void givenRoleLogger_whenSendMessageToDirectChannel_thenAccessDenied() throws Throwable { - try { - startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); - } catch (Exception e) { - throw e.getCause(); - } + public void givenRoleLogger_whenSendMessageToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); } - @Test(expected = AccessDeniedException.class) + @Test @WithMockUser(username = "jane") - public void givenJane_whenSendMessageToDirectChannel_thenAccessDenied() throws Throwable { - try { - startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); - } catch (Exception e) { - throw e.getCause(); - } + public void givenJane_whenSendMessageToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); } - @Test(expected = AccessDeniedException.class) + @Test @WithMockUser(roles = { "VIEWER" }) - public void givenRoleViewer_whenSendToDirectChannel_thenAccessDenied() throws Throwable { - try { - startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); - } catch (Exception e) { - throw e.getCause(); - } + public void givenRoleViewer_whenSendToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); } @Test @@ -78,4 +78,4 @@ public class TestSpringIntegrationSecurity { assertEquals(DIRECT_CHANNEL_MESSAGE, messageConsumer.getMessageContent()); } -} +} \ No newline at end of file From d935985ec1b541558864f146c4dd530571f09df4 Mon Sep 17 00:00:00 2001 From: Ganesh Date: Sun, 11 Feb 2018 13:29:30 +0530 Subject: [PATCH 46/48] Priorityjobscheduler (#3583) * priority based job execution in java * minor fixes * updated to use java 8 features * fix need for type inference * handle exception * indentation * handling exception generated during terminal of normal flow * handling exception generated during terminal of normal flow * added comment --- .../concurrent/prioritytaskexecution/Job.java | 3 ++- .../prioritytaskexecution/PriorityJobScheduler.java | 12 ++++++------ .../PriorityJobSchedulerUnitTest.java | 4 +++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java index a70041ed7d..9900d1c63d 100644 --- a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java @@ -16,7 +16,8 @@ public class Job implements Runnable { @Override public void run() { try { - System.out.println("Job:" + jobName + " Priority:" + jobPriority); + System.out.println("Job:" + jobName + + " Priority:" + jobPriority); Thread.sleep(1000); } catch (InterruptedException ignored) { } diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java index 70fd1710c0..ba55696d5a 100644 --- a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java @@ -9,21 +9,21 @@ import java.util.concurrent.TimeUnit; public class PriorityJobScheduler { private ExecutorService priorityJobPoolExecutor; - private ExecutorService priorityJobScheduler; - private PriorityBlockingQueue priorityQueue; + private ExecutorService priorityJobScheduler = + Executors.newSingleThreadExecutor(); + private PriorityBlockingQueue priorityQueue; public PriorityJobScheduler(Integer poolSize, Integer queueSize) { priorityJobPoolExecutor = Executors.newFixedThreadPool(poolSize); - Comparator jobComparator = Comparator.comparing(Job::getJobPriority); - priorityQueue = new PriorityBlockingQueue(queueSize, - (Comparator) jobComparator); + priorityQueue = new PriorityBlockingQueue(queueSize, + Comparator.comparing(Job::getJobPriority)); - priorityJobScheduler = Executors.newSingleThreadExecutor(); priorityJobScheduler.execute(()->{ while (true) { try { priorityJobPoolExecutor.execute(priorityQueue.take()); } catch (InterruptedException e) { + // exception needs special handling break; } } diff --git a/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java b/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java index 902bada3a2..1e67fe45c1 100644 --- a/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java +++ b/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java @@ -30,7 +30,9 @@ public class PriorityJobSchedulerUnitTest { // delay to avoid job sleep (added for demo) being interrupted try { Thread.sleep(2000); - } catch (InterruptedException ignored) { + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); } pjs.closeScheduler(); From 1c043dc20287524d91562e81aab5a64bcbb3d2f5 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sun, 11 Feb 2018 12:34:49 +0200 Subject: [PATCH 47/48] custom dsl ex (#3577) * custom dsl ex * Update application.properties --- .../baeldung/dsl/ClientErrorLoggingDsl.java | 32 +++++++++++ .../dsl/ClientErrorLoggingFilter.java | 54 +++++++++++++++++++ .../baeldung/dsl/CustomDslApplication.java | 13 +++++ .../java/com/baeldung/dsl/MyController.java | 14 +++++ .../java/com/baeldung/dsl/SecurityConfig.java | 50 +++++++++++++++++ .../src/main/resources/application.properties | 4 +- 6 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingDsl.java create mode 100644 spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java create mode 100644 spring-5-security/src/main/java/com/baeldung/dsl/CustomDslApplication.java create mode 100644 spring-5-security/src/main/java/com/baeldung/dsl/MyController.java create mode 100644 spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingDsl.java b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingDsl.java new file mode 100644 index 0000000000..6c7c0d2717 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingDsl.java @@ -0,0 +1,32 @@ +package com.baeldung.dsl; + +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; + +public class ClientErrorLoggingDsl extends AbstractHttpConfigurer { + + private List errorCodes; + + public ClientErrorLoggingDsl(List errorCodes) { + this.errorCodes = errorCodes; + } + + public ClientErrorLoggingDsl() { + + } + + @Override + public void init(HttpSecurity http) throws Exception { + // initialization code + } + + @Override + public void configure(HttpSecurity http) throws Exception { + http.addFilterAfter(new ClientErrorLoggingFilter(errorCodes), FilterSecurityInterceptor.class); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java new file mode 100644 index 0000000000..56f7cea3b8 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java @@ -0,0 +1,54 @@ +package com.baeldung.dsl; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.GenericFilterBean; + +public class ClientErrorLoggingFilter extends GenericFilterBean { + + private static final Logger logger = LogManager.getLogger(ClientErrorLoggingFilter.class); + + private List errorCodes; + + public ClientErrorLoggingFilter(List errorCodes) { + this.errorCodes = errorCodes; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + Authentication auth = SecurityContextHolder.getContext() + .getAuthentication(); + + if (auth != null) { + int status = ((HttpServletResponse) response).getStatus(); + if (status >= 400 && status < 500) { + if (errorCodes == null) { + logger.debug("User " + auth.getName() + " encountered error " + status); + } else { + if (errorCodes.stream() + .filter(s -> s.value() == status) + .findFirst() + .isPresent()) { + logger.debug("User " + auth.getName() + " encountered error " + status); + } + } + } + } + + chain.doFilter(request, response); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/CustomDslApplication.java b/spring-5-security/src/main/java/com/baeldung/dsl/CustomDslApplication.java new file mode 100644 index 0000000000..3e58bccaf4 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/CustomDslApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.dsl; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CustomDslApplication { + + public static void main(String[] args) { + SpringApplication.run(CustomDslApplication.class, args); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java b/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java new file mode 100644 index 0000000000..c69046afb5 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java @@ -0,0 +1,14 @@ +package com.baeldung.dsl; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class MyController { + + @GetMapping("/admin") + public String getAdminPage() { + return "Hello Admin"; + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java b/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java new file mode 100644 index 0000000000..4494aaa131 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java @@ -0,0 +1,50 @@ +package com.baeldung.dsl; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/admin*") + .hasAnyRole("ADMIN") + .anyRequest() + .authenticated() + .and() + .formLogin() + .and() + .apply(clientErrorLogging()); + } + + @Bean + public ClientErrorLoggingDsl clientErrorLogging() { + return new ClientErrorLoggingDsl(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication() + .passwordEncoder(passwordEncoder()) + .withUser("user1") + .password(passwordEncoder().encode("user")) + .roles("USER") + .and() + .withUser("admin") + .password(passwordEncoder().encode("admin")) + .roles("ADMIN"); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + +} diff --git a/spring-5-security/src/main/resources/application.properties b/spring-5-security/src/main/resources/application.properties index ccec014c2b..781ee76826 100644 --- a/spring-5-security/src/main/resources/application.properties +++ b/spring-5-security/src/main/resources/application.properties @@ -1,3 +1,5 @@ server.port=8081 -logging.level.root=INFO \ No newline at end of file +logging.level.root=INFO + +logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG From 6eeff13c459a3661c9151086ce2cf70e0faf31f1 Mon Sep 17 00:00:00 2001 From: Allan Vital Date: Sun, 11 Feb 2018 11:36:33 -0200 Subject: [PATCH 48/48] BAEL-1368: infinispan article (#3633) --- libraries/pom.xml | 8 +- .../infinispan/CacheConfiguration.java | 85 ++++++++++++++ .../infinispan/listener/CacheListener.java | 55 +++++++++ .../repository/HelloWorldRepository.java | 15 +++ .../infinispan/service/HelloWorldService.java | 90 +++++++++++++++ .../service/TransactionalService.java | 57 ++++++++++ .../infinispan/ConfigurationTest.java | 56 ++++++++++ .../service/HelloWorldServiceUnitTest.java | 105 ++++++++++++++++++ .../service/TransactionalServiceUnitTest.java | 24 ++++ 9 files changed, 494 insertions(+), 1 deletion(-) create mode 100644 libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java create mode 100644 libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java create mode 100644 libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java create mode 100644 libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java create mode 100644 libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java create mode 100644 libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java create mode 100644 libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java create mode 100644 libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java diff --git a/libraries/pom.xml b/libraries/pom.xml index fa1839010c..64cc9c6a84 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -649,6 +649,11 @@ google-http-client-gson ${googleclient.version} + + org.infinispan + infinispan-core + ${infinispan.version} + @@ -811,5 +816,6 @@ 3.0.14 8.5.24 2.2.0 + 9.1.5.Final - \ No newline at end of file + diff --git a/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java b/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java new file mode 100644 index 0000000000..bf214458f3 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java @@ -0,0 +1,85 @@ +package com.baeldung.infinispan; + +import com.baeldung.infinispan.listener.CacheListener; +import org.infinispan.Cache; +import org.infinispan.configuration.cache.Configuration; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.eviction.EvictionType; +import org.infinispan.manager.DefaultCacheManager; +import org.infinispan.transaction.LockingMode; +import org.infinispan.transaction.TransactionMode; + +import java.util.concurrent.TimeUnit; + +public class CacheConfiguration { + + public static final String SIMPLE_HELLO_WORLD_CACHE = "simple-hello-world-cache"; + public static final String EXPIRING_HELLO_WORLD_CACHE = "expiring-hello-world-cache"; + public static final String EVICTING_HELLO_WORLD_CACHE = "evicting-hello-world-cache"; + public static final String PASSIVATING_HELLO_WORLD_CACHE = "passivating-hello-world-cache"; + public static final String TRANSACTIONAL_CACHE = "transactional-cache"; + + public DefaultCacheManager cacheManager() { + DefaultCacheManager cacheManager = new DefaultCacheManager(); + return cacheManager; + } + + public Cache transactionalCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(TRANSACTIONAL_CACHE, cacheManager, listener, transactionalConfiguration()); + } + + public Cache simpleHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(SIMPLE_HELLO_WORLD_CACHE, cacheManager, listener, new ConfigurationBuilder().build()); + } + + public Cache expiringHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(EXPIRING_HELLO_WORLD_CACHE, cacheManager, listener, expiringConfiguration()); + } + + public Cache evictingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(EVICTING_HELLO_WORLD_CACHE, cacheManager, listener, evictingConfiguration()); + } + + public Cache passivatingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(PASSIVATING_HELLO_WORLD_CACHE, cacheManager, listener, passivatingConfiguration()); + } + + private Cache buildCache(String cacheName, DefaultCacheManager cacheManager, + CacheListener listener, Configuration configuration) { + + cacheManager.defineConfiguration(cacheName, configuration); + Cache cache = cacheManager.getCache(cacheName); + cache.addListener(listener); + return cache; + } + + private Configuration expiringConfiguration() { + return new ConfigurationBuilder().expiration().lifespan(1, TimeUnit.SECONDS) + .build(); + } + + private Configuration evictingConfiguration() { + return new ConfigurationBuilder() + .memory().evictionType(EvictionType.COUNT).size(1) + .build(); + } + + private Configuration passivatingConfiguration() { + return new ConfigurationBuilder() + .memory().evictionType(EvictionType.COUNT).size(1) + .persistence() + .passivation(true) + .addSingleFileStore() + .purgeOnStartup(true) + .location(System.getProperty("java.io.tmpdir")) + .build(); + } + + private Configuration transactionalConfiguration() { + return new ConfigurationBuilder() + .transaction().transactionMode(TransactionMode.TRANSACTIONAL) + .lockingMode(LockingMode.PESSIMISTIC) + .build(); + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java b/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java new file mode 100644 index 0000000000..2f6536ad87 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java @@ -0,0 +1,55 @@ +package com.baeldung.infinispan.listener; + +import org.infinispan.notifications.Listener; +import org.infinispan.notifications.cachelistener.annotation.*; +import org.infinispan.notifications.cachelistener.event.*; + +@Listener +public class CacheListener { + + @CacheEntryCreated + public void entryCreated(CacheEntryCreatedEvent event) { + this.printLog("Adding key '" + event.getKey() + "' to cache", event); + } + + @CacheEntryExpired + public void entryExpired(CacheEntryExpiredEvent event) { + this.printLog("Expiring key '" + event.getKey() + "' from cache", event); + } + + @CacheEntryVisited + public void entryVisited(CacheEntryVisitedEvent event) { + this.printLog("Key '" + event.getKey() + "' was visited", event); + } + + @CacheEntryActivated + public void entryActivated(CacheEntryActivatedEvent event) { + this.printLog("Activating key '" + event.getKey() + "' on cache", event); + } + + @CacheEntryPassivated + public void entryPassivated(CacheEntryPassivatedEvent event) { + this.printLog("Passivating key '" + event.getKey() + "' from cache", event); + } + + @CacheEntryLoaded + public void entryLoaded(CacheEntryLoadedEvent event) { + this.printLog("Loading key '" + event.getKey() + "' to cache", event); + } + + @CacheEntriesEvicted + public void entriesEvicted(CacheEntriesEvictedEvent event) { + final StringBuilder builder = new StringBuilder(); + event.getEntries().entrySet().forEach((e) -> + builder.append(e.getKey() + ", ") + ); + System.out.println("Evicting following entries from cache: " + builder.toString()); + } + + private void printLog(String log, CacheEntryEvent event) { + if (!event.isPre()) { + System.out.println(log); + } + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java b/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java new file mode 100644 index 0000000000..85c0d539a3 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.infinispan.repository; + +public class HelloWorldRepository { + + public String getHelloWorld() { + try { + System.out.println("Executing some heavy query"); + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "Hello World!"; + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java b/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java new file mode 100644 index 0000000000..0d1ffb4168 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java @@ -0,0 +1,90 @@ +package com.baeldung.infinispan.service; + +import com.baeldung.infinispan.listener.CacheListener; +import com.baeldung.infinispan.repository.HelloWorldRepository; +import org.infinispan.Cache; + +import java.util.concurrent.TimeUnit; + +public class HelloWorldService { + + private final HelloWorldRepository repository; + + private final Cache simpleHelloWorldCache; + private final Cache expiringHelloWorldCache; + private final Cache evictingHelloWorldCache; + private final Cache passivatingHelloWorldCache; + + public HelloWorldService(HelloWorldRepository repository, CacheListener listener, + Cache simpleHelloWorldCache, + Cache expiringHelloWorldCache, + Cache evictingHelloWorldCache, + Cache passivatingHelloWorldCache) { + + this.repository = repository; + + this.simpleHelloWorldCache = simpleHelloWorldCache; + this.expiringHelloWorldCache = expiringHelloWorldCache; + this.evictingHelloWorldCache = evictingHelloWorldCache; + this.passivatingHelloWorldCache = passivatingHelloWorldCache; + } + + public String findSimpleHelloWorld() { + String cacheKey = "simple-hello"; + String helloWorld = simpleHelloWorldCache.get(cacheKey); + if (helloWorld == null) { + helloWorld = repository.getHelloWorld(); + simpleHelloWorldCache.put(cacheKey, helloWorld); + } + return helloWorld; + } + + public String findExpiringHelloWorld() { + String cacheKey = "expiring-hello"; + String helloWorld = simpleHelloWorldCache.get(cacheKey); + if (helloWorld == null) { + helloWorld = repository.getHelloWorld(); + simpleHelloWorldCache.put(cacheKey, helloWorld, 1, TimeUnit.SECONDS); + } + return helloWorld; + } + + public String findIdleHelloWorld() { + String cacheKey = "idle-hello"; + String helloWorld = simpleHelloWorldCache.get(cacheKey); + if (helloWorld == null) { + helloWorld = repository.getHelloWorld(); + simpleHelloWorldCache.put(cacheKey, helloWorld, -1, TimeUnit.SECONDS, 10, TimeUnit.SECONDS); + } + return helloWorld; + } + + public String findSimpleHelloWorldInExpiringCache() { + String cacheKey = "simple-hello"; + String helloWorld = expiringHelloWorldCache.get(cacheKey); + if (helloWorld == null) { + helloWorld = repository.getHelloWorld(); + expiringHelloWorldCache.put(cacheKey, helloWorld); + } + return helloWorld; + } + + public String findEvictingHelloWorld(String key) { + String value = evictingHelloWorldCache.get(key); + if(value == null) { + value = repository.getHelloWorld(); + evictingHelloWorldCache.put(key, value); + } + return value; + } + + public String findPassivatingHelloWorld(String key) { + String value = passivatingHelloWorldCache.get(key); + if(value == null) { + value = repository.getHelloWorld(); + passivatingHelloWorldCache.put(key, value); + } + return value; + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java b/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java new file mode 100644 index 0000000000..b0dbf5475f --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java @@ -0,0 +1,57 @@ +package com.baeldung.infinispan.service; + +import org.infinispan.Cache; +import org.springframework.util.StopWatch; + +import javax.transaction.TransactionManager; + +public class TransactionalService { + + private final Cache transactionalCache; + + private static final String KEY = "key"; + + public TransactionalService(Cache transactionalCache) { + this.transactionalCache = transactionalCache; + + transactionalCache.put(KEY, 0); + } + + public Integer getQuickHowManyVisits() { + try { + TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager(); + tm.begin(); + Integer howManyVisits = transactionalCache.get(KEY); + howManyVisits++; + System.out.println("Ill try to set HowManyVisits to " + howManyVisits); + StopWatch watch = new StopWatch(); + watch.start(); + transactionalCache.put(KEY, howManyVisits); + watch.stop(); + System.out.println("I was able to set HowManyVisits to " + howManyVisits + + " after waiting " + watch.getTotalTimeSeconds() + " seconds"); + + tm.commit(); + return howManyVisits; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + public void startBackgroundBatch() { + try { + TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager(); + tm.begin(); + transactionalCache.put(KEY, 1000); + System.out.println("HowManyVisits should now be 1000, " + + "but we are holding the transaction"); + Thread.sleep(1000L); + tm.rollback(); + System.out.println("The slow batch suffered a rollback"); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java b/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java new file mode 100644 index 0000000000..b05314491b --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java @@ -0,0 +1,56 @@ +package com.baeldung.infinispan; + +import com.baeldung.infinispan.listener.CacheListener; +import com.baeldung.infinispan.repository.HelloWorldRepository; +import com.baeldung.infinispan.service.HelloWorldService; +import com.baeldung.infinispan.service.TransactionalService; +import org.infinispan.Cache; +import org.infinispan.manager.DefaultCacheManager; +import org.junit.After; +import org.junit.Before; + +public class ConfigurationTest { + + private DefaultCacheManager cacheManager; + + private HelloWorldRepository repository = new HelloWorldRepository(); + + protected HelloWorldService helloWorldService; + protected TransactionalService transactionalService; + + @Before + public void setup() { + CacheConfiguration configuration = new CacheConfiguration(); + CacheListener listener = new CacheListener(); + + cacheManager = configuration.cacheManager(); + + Cache transactionalCache = + configuration.transactionalCache(cacheManager, listener); + + Cache simpleHelloWorldCache = + configuration.simpleHelloWorldCache(cacheManager, listener); + + Cache expiringHelloWorldCache = + configuration.expiringHelloWorldCache(cacheManager, listener); + + Cache evictingHelloWorldCache = + configuration.evictingHelloWorldCache(cacheManager, listener); + + Cache passivatingHelloWorldCache = + configuration.passivatingHelloWorldCache(cacheManager, listener); + + this.helloWorldService = new HelloWorldService(repository, + listener, simpleHelloWorldCache, expiringHelloWorldCache, evictingHelloWorldCache, + passivatingHelloWorldCache); + + this.transactionalService = new TransactionalService(transactionalCache); + + } + + @After + public void tearDown() { + cacheManager.stop(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java b/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java new file mode 100644 index 0000000000..bda2e6886b --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java @@ -0,0 +1,105 @@ +package com.baeldung.infinispan.service; + +import com.baeldung.infinispan.ConfigurationTest; +import org.junit.Test; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +public class HelloWorldServiceUnitTest extends ConfigurationTest { + + @Test + public void whenGetIsCalledTwoTimes_thenTheSecondShouldHitTheCache() { + long milis = System.currentTimeMillis(); + helloWorldService.findSimpleHelloWorld(); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findSimpleHelloWorld(); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isLessThan(100); + } + + @Test + public void whenGetIsCalledTwoTimesQuickly_thenTheSecondShouldHitTheCache() { + long milis = System.currentTimeMillis(); + helloWorldService.findExpiringHelloWorld(); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findExpiringHelloWorld(); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isLessThan(100); + } + + @Test + public void whenGetIsCalledTwoTimesSparsely_thenNeitherShouldHitTheCache() + throws InterruptedException { + + long milis = System.currentTimeMillis(); + helloWorldService.findSimpleHelloWorldInExpiringCache(); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + Thread.sleep(1100); + + milis = System.currentTimeMillis(); + helloWorldService.findSimpleHelloWorldInExpiringCache(); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + } + + @Test + public void givenOneEntryIsConfigured_whenTwoAreAdded_thenFirstShouldntBeAvailable() + throws InterruptedException { + + long milis = System.currentTimeMillis(); + helloWorldService.findEvictingHelloWorld("key 1"); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findEvictingHelloWorld("key 2"); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findEvictingHelloWorld("key 1"); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + } + + @Test + public void givenOneEntryIsConfigured_whenTwoAreAdded_thenTheFirstShouldBeAvailable() + throws InterruptedException { + + long milis = System.currentTimeMillis(); + helloWorldService.findPassivatingHelloWorld("key 1"); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findPassivatingHelloWorld("key 2"); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findPassivatingHelloWorld("key 1"); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isLessThan(100); + } + +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java b/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java new file mode 100644 index 0000000000..f529222079 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.infinispan.service; + +import com.baeldung.infinispan.ConfigurationTest; +import org.junit.Test; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +public class TransactionalServiceUnitTest extends ConfigurationTest { + + @Test + public void whenLockingAnEntry_thenItShouldBeInaccessible() throws InterruptedException { + Runnable backGroundJob = () -> transactionalService.startBackgroundBatch(); + Thread backgroundThread = new Thread(backGroundJob); + transactionalService.getQuickHowManyVisits(); + backgroundThread.start(); + Thread.sleep(100); //lets wait our thread warm up + long milis = System.currentTimeMillis(); + transactionalService.getQuickHowManyVisits(); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThan(500).isLessThan(1000); + } + +}