diff --git a/apache-poi/README.md b/apache-poi/README.md index cef6810c97..10fe8ba2e7 100644 --- a/apache-poi/README.md +++ b/apache-poi/README.md @@ -1,2 +1,3 @@ ### Relevant Articles: - [Microsoft Word Processing in Java with Apache POI](http://www.baeldung.com/java-microsoft-word-with-apache-poi) +- [Working with Microsoft Excel in Java](http://www.baeldung.com/java-microsoft-excel) diff --git a/core-java/pom.xml b/core-java/pom.xml index 5c91150941..2b6f065c85 100644 --- a/core-java/pom.xml +++ b/core-java/pom.xml @@ -1,5 +1,5 @@ + 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 core-java @@ -10,6 +10,44 @@ + + org.neo4j + neo4j + 3.1.0 + + + + org.neo4j.driver + neo4j-java-driver + 1.1.1 + + + + org.neo4j + neo4j-jdbc-driver + 3.0.1 + + + + org.neo4j + neo4j-ogm-core + 2.1.1 + + + + org.neo4j + neo4j-ogm-embedded-driver + 2.1.1 + + + + com.google.inject + guice + 4.1.0 + no_aop + test + + net.sourceforge.collections @@ -63,7 +101,6 @@ grep4j ${grep4j.version} - @@ -269,7 +306,8 @@ true - + org.baeldung.executable.ExecutableMavenJar diff --git a/core-java/src/main/java/com/baeldung/graph/Car.java b/core-java/src/main/java/com/baeldung/graph/Car.java new file mode 100644 index 0000000000..1dc65a0d4b --- /dev/null +++ b/core-java/src/main/java/com/baeldung/graph/Car.java @@ -0,0 +1,50 @@ +package com.baeldung.graph; + +import org.neo4j.ogm.annotation.GraphId; +import org.neo4j.ogm.annotation.NodeEntity; +import org.neo4j.ogm.annotation.Relationship; + +/** + * @author Danil Kornishev (danil.kornishev@mastercard.com) + */ +@NodeEntity +public class Car { + @GraphId + private Long id; + + private String make; + + @Relationship(direction = "INCOMING") + private Company company; + + public Car(String make, String model) { + this.make = make; + this.model = model; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + private String model; +} diff --git a/core-java/src/main/java/com/baeldung/graph/Company.java b/core-java/src/main/java/com/baeldung/graph/Company.java new file mode 100644 index 0000000000..1fe892b331 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/graph/Company.java @@ -0,0 +1,45 @@ +package com.baeldung.graph; + +import org.neo4j.ogm.annotation.NodeEntity; +import org.neo4j.ogm.annotation.Relationship; + +/** + * @author Danil Kornishev (danil.kornishev@mastercard.com) + */ +@NodeEntity +public class Company { + private Long id; + + private String name; + + @Relationship(type="owns") + private Car car; + + public Company(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Car getCar() { + return car; + } + + public void setCar(Car car) { + this.car = car; + } +} diff --git a/core-java/src/main/java/com/baeldung/java_8_features/groupingby/BlogPost.java b/core-java/src/main/java/com/baeldung/java_8_features/groupingby/BlogPost.java new file mode 100644 index 0000000000..afc05e356a --- /dev/null +++ b/core-java/src/main/java/com/baeldung/java_8_features/groupingby/BlogPost.java @@ -0,0 +1,36 @@ +package com.baeldung.java_8_features.groupingby; + +public class BlogPost { + private String title; + private String author; + private BlogPostType type; + private int likes; + + public BlogPost(String title, String author, BlogPostType type, int likes) { + this.title = title; + this.author = author; + this.type = type; + this.likes = likes; + } + + public String getTitle() { + return title; + } + + public String getAuthor() { + return author; + } + + public BlogPostType getType() { + return type; + } + + public int getLikes() { + return likes; + } + + @Override + public String toString() { + return "BlogPost{" + "title='" + title + '\'' + ", type=" + type + ", likes=" + likes + '}'; + } +} diff --git a/core-java/src/main/java/com/baeldung/java_8_features/groupingby/BlogPostType.java b/core-java/src/main/java/com/baeldung/java_8_features/groupingby/BlogPostType.java new file mode 100644 index 0000000000..2029784e91 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/java_8_features/groupingby/BlogPostType.java @@ -0,0 +1,5 @@ +package com.baeldung.java_8_features.groupingby; + +public enum BlogPostType { + NEWS, REVIEW, GUIDE +} diff --git a/core-java/src/test/java/com/baeldung/graph/Neo4JServerTest.java b/core-java/src/test/java/com/baeldung/graph/Neo4JServerTest.java new file mode 100644 index 0000000000..b41588b71e --- /dev/null +++ b/core-java/src/test/java/com/baeldung/graph/Neo4JServerTest.java @@ -0,0 +1,60 @@ +package com.baeldung.graph; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +import org.junit.Ignore; +import org.junit.Test; +import org.neo4j.driver.v1.AuthTokens; +import org.neo4j.driver.v1.Driver; +import org.neo4j.driver.v1.GraphDatabase; +import org.neo4j.driver.v1.Session; +import org.neo4j.driver.v1.StatementResult; +import org.testng.Assert; + +@Ignore +public class Neo4JServerTest { + + @Test + public void standAloneDriver() { + Driver driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "12345")); + Session session = driver.session(); + + session.run("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + + "RETURN baeldung, tesla"); + + StatementResult result = session.run("MATCH (company:Company)-[:owns]-> (car:Car)" + + "WHERE car.make='tesla' and car.model='modelX'" + + "RETURN company.name"); + + Assert.assertTrue(result.hasNext()); + Assert.assertEquals(result.next().get("company.name").asString(), "Baeldung"); + + session.close(); + driver.close(); + } + + @Test + public void standAloneJdbc() throws Exception { + Connection con = DriverManager.getConnection("jdbc:neo4j:bolt://localhost/?user=neo4j,password=12345,scheme=basic"); + + // Querying + try (Statement stmt = con.createStatement()) { + stmt.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + + "RETURN baeldung, tesla"); + + ResultSet rs = stmt.executeQuery("MATCH (company:Company)-[:owns]-> (car:Car)" + + "WHERE car.make='tesla' and car.model='modelX'" + + "RETURN company.name"); + + while (rs.next()) { + Assert.assertEquals(rs.getString("company.name"), "Baeldung"); + } + } + con.close(); + } +} diff --git a/core-java/src/test/java/com/baeldung/graph/Neo4jOgmTest.java b/core-java/src/test/java/com/baeldung/graph/Neo4jOgmTest.java new file mode 100644 index 0000000000..00bd47d029 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/graph/Neo4jOgmTest.java @@ -0,0 +1,46 @@ +package com.baeldung.graph; + +import org.junit.Test; +import org.neo4j.ogm.config.Configuration; +import org.neo4j.ogm.model.Result; +import org.neo4j.ogm.session.Session; +import org.neo4j.ogm.session.SessionFactory; +import org.testng.Assert; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Danil Kornishev (danil.kornishev@mastercard.com) + */ +public class Neo4jOgmTest { + + @Test + public void testOgm() { + Configuration conf = new Configuration(); + conf.driverConfiguration().setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver"); + + SessionFactory factory = new SessionFactory(conf, "com.baeldung.graph"); + Session session = factory.openSession(); + + Car tesla = new Car("tesla", "modelS"); + Company baeldung = new Company("baeldung"); + + baeldung.setCar(tesla); + + session.save(baeldung); + + Map params = new HashMap<>(); + params.put("make", "tesla"); + Result result = session.query("MATCH (car:Car) <-[:owns]- (company:Company)" + + " WHERE car.make=$make" + + " RETURN company", params); + + Map firstResult = result.iterator().next(); + + Assert.assertEquals(firstResult.size(), 1); + + Company actual = (Company) firstResult.get("company"); + Assert.assertEquals(actual.getName(), baeldung.getName()); + } +} diff --git a/core-java/src/test/java/com/baeldung/graph/Neo4jTest.java b/core-java/src/test/java/com/baeldung/graph/Neo4jTest.java new file mode 100644 index 0000000000..6956c2c39f --- /dev/null +++ b/core-java/src/test/java/com/baeldung/graph/Neo4jTest.java @@ -0,0 +1,167 @@ +package com.baeldung.graph; + + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Label; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.NotFoundException; +import org.neo4j.graphdb.RelationshipType; +import org.neo4j.graphdb.Result; +import org.neo4j.graphdb.factory.GraphDatabaseFactory; +import org.testng.Assert; + +public class Neo4jTest { + + private static GraphDatabaseService graphDb; + + @Before + public void setUp() { + GraphDatabaseFactory graphDbFactory = new GraphDatabaseFactory(); + graphDb = graphDbFactory.newEmbeddedDatabase(new File("data/cars")); + } + + @After + public void tearDown() { + graphDb.shutdown(); + } + + @Test + public void testPersonCar() { + graphDb.beginTx(); + Node car = graphDb.createNode(Label.label("Car")); + car.setProperty("make", "tesla"); + car.setProperty("model", "model3"); + + Node owner = graphDb.createNode(Label.label("Person")); + owner.setProperty("firstName", "baeldung"); + owner.setProperty("lastName", "baeldung"); + + owner.createRelationshipTo(car, RelationshipType.withName("owner")); + + Result result = graphDb.execute("MATCH (c:Car) <-[owner]- (p:Person) " + + "WHERE c.make = 'tesla'" + + "RETURN p.firstName, p.lastName"); + + Map firstResult = result.next(); + Assert.assertEquals("baeldung", firstResult.get("p.firstName")); + } + + @Test + public void testCreateNode() { + + graphDb.beginTx(); + + Result result = graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"})" + + "RETURN baeldung"); + + Map firstResult = result.next(); + Node firstNode = (Node) firstResult.get("baeldung"); + Assert.assertEquals(firstNode.getProperty("name"), "Baeldung"); + } + + @Test + public void testCreateNodeAndLink() { + graphDb.beginTx(); + + Result result = graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + + "RETURN baeldung, tesla"); + + Map firstResult = result.next(); + Assert.assertTrue(firstResult.containsKey("baeldung")); + Assert.assertTrue(firstResult.containsKey("tesla")); + } + + @Test + public void testFindAndReturn() { + graphDb.beginTx(); + + graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + + "RETURN baeldung, tesla"); + + Result result = graphDb.execute("MATCH (company:Company)-[:owns]-> (car:Car)" + + "WHERE car.make='tesla' and car.model='modelX'" + + "RETURN company.name"); + + Map firstResult = result.next(); + Assert.assertEquals(firstResult.get("company.name"), "Baeldung"); + } + + @Test + public void testUpdate() { + graphDb.beginTx(); + + graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + + "RETURN baeldung, tesla"); + + Result result = graphDb.execute("MATCH (car:Car)" + + "WHERE car.make='tesla'" + + " SET car.milage=120" + + " SET car :Car:Electro" + + " SET car.model=NULL" + + " RETURN car"); + + Map firstResult = result.next(); + Node car = (Node) firstResult.get("car"); + + Assert.assertEquals(car.getProperty("milage"), 120L); + Assert.assertEquals(car.getLabels(), Arrays.asList(Label.label("Car"), Label.label("Electro"))); + + try { + car.getProperty("model"); + Assert.fail(); + } catch (NotFoundException e) { + // expected + } + } + + @Test + public void testDelete() { + graphDb.beginTx(); + + graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + + "RETURN baeldung, tesla"); + + graphDb.execute("MATCH (company:Company)" + + " WHERE company.name='Baeldung'" + + " DELETE company"); + + Result result = graphDb.execute("MATCH (company:Company)" + + " WHERE company.name='Baeldung'" + + " RETURN company"); + + Assert.assertFalse(result.hasNext()); + } + + @Test + public void testBindings() { + graphDb.beginTx(); + + Map params = new HashMap<>(); + params.put("name", "baeldung"); + params.put("make", "tesla"); + params.put("model", "modelS"); + + Result result = graphDb.execute("CREATE (baeldung:Company {name:$name}) " + + "-[:owns]-> (tesla:Car {make: $make, model: $model})" + + "RETURN baeldung, tesla", params); + + Map firstResult = result.next(); + Assert.assertTrue(firstResult.containsKey("baeldung")); + Assert.assertTrue(firstResult.containsKey("tesla")); + + Node car = (Node) firstResult.get("tesla"); + Assert.assertEquals(car.getProperty("model"), "modelS"); + } +} diff --git a/core-java/src/test/java/com/baeldung/java/concurrentmodification/ConcurrentModificationUnitTest.java b/core-java/src/test/java/com/baeldung/java/concurrentmodification/ConcurrentModificationUnitTest.java new file mode 100644 index 0000000000..f7a7bd5fe0 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/java/concurrentmodification/ConcurrentModificationUnitTest.java @@ -0,0 +1,80 @@ +package com.baeldung.java.concurrentmodification; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; + +import static java.util.stream.Collectors.toList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.util.Lists.newArrayList; + +public class ConcurrentModificationUnitTest { + @Test(expected = ConcurrentModificationException.class) + public void givenIterating_whenRemoving_thenThrowException() throws InterruptedException { + + List integers = newArrayList(1, 2, 3); + + for (Integer integer : integers) { + integers.remove(1); + } + } + + @Test + public void givenIterating_whenUsingIteratorRemove_thenNoError() throws InterruptedException { + + List integers = newArrayList(1, 2, 3); + + for (Iterator iterator = integers.iterator(); iterator.hasNext();) { + Integer integer = iterator.next(); + if(integer == 2) { + iterator.remove(); + } + } + + assertThat(integers).containsExactly(1, 3); + } + + @Test + public void givenIterating_whenUsingRemovalList_thenNoError() throws InterruptedException { + + List integers = newArrayList(1, 2, 3); + List toRemove = newArrayList(); + + for (Integer integer : integers) { + if(integer == 2) { + toRemove.add(integer); + } + } + integers.removeAll(toRemove); + + assertThat(integers).containsExactly(1, 3); + } + + @Test + public void whenUsingRemoveIf_thenRemoveElements() throws InterruptedException { + + Collection integers = newArrayList(1, 2, 3); + + integers.removeIf(i -> i == 2); + + assertThat(integers).containsExactly(1, 3); + } + + @Test + public void whenUsingStream_thenRemoveElements() { + Collection integers = newArrayList(1, 2, 3); + + List collected = integers + .stream() + .filter(i -> i != 2) + .map(Object::toString) + .collect(toList()); + + assertThat(collected).containsExactly("1", "3"); + } + +} diff --git a/core-java/src/test/java/com/baeldung/java8/Java8GroupingByCollectorUnitTest.java b/core-java/src/test/java/com/baeldung/java8/Java8GroupingByCollectorUnitTest.java new file mode 100644 index 0000000000..4452b4db9a --- /dev/null +++ b/core-java/src/test/java/com/baeldung/java8/Java8GroupingByCollectorUnitTest.java @@ -0,0 +1,231 @@ +package com.baeldung.java8; + +import com.baeldung.java_8_features.groupingby.BlogPost; +import com.baeldung.java_8_features.groupingby.BlogPostType; +import org.junit.Test; + +import java.util.*; +import java.util.concurrent.ConcurrentMap; + +import static java.util.Comparator.comparingInt; +import static java.util.stream.Collectors.*; +import static org.junit.Assert.*; + +public class Java8GroupingByCollectorUnitTest { + + private static final List posts = Arrays.asList( + new BlogPost("News item 1", "Author 1", BlogPostType.NEWS, 15), + new BlogPost("Tech review 1", "Author 2", BlogPostType.REVIEW, 5), + new BlogPost("Programming guide", "Author 1", BlogPostType.GUIDE, 20), + new BlogPost("News item 2", "Author 2", BlogPostType.NEWS, 35), + new BlogPost("Tech review 2", "Author 1", BlogPostType.REVIEW, 15)); + + @Test + public void givenAListOfPosts_whenGroupedByType_thenGetAMapBetweenTypeAndPosts() { + Map> postsPerType = posts + .stream() + .collect(groupingBy(BlogPost::getType)); + + assertEquals(2, postsPerType + .get(BlogPostType.NEWS) + .size()); + assertEquals(1, postsPerType + .get(BlogPostType.GUIDE) + .size()); + assertEquals(2, postsPerType + .get(BlogPostType.REVIEW) + .size()); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeAndTheirTitlesAreJoinedInAString_thenGetAMapBetweenTypeAndCsvTitles() { + Map postsPerType = posts + .stream() + .collect(groupingBy(BlogPost::getType, mapping(BlogPost::getTitle, joining(", ", "Post titles: [", "]")))); + + assertEquals("Post titles: [News item 1, News item 2]", postsPerType.get(BlogPostType.NEWS)); + assertEquals("Post titles: [Programming guide]", postsPerType.get(BlogPostType.GUIDE)); + assertEquals("Post titles: [Tech review 1, Tech review 2]", postsPerType.get(BlogPostType.REVIEW)); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeAndSumTheLikes_thenGetAMapBetweenTypeAndPostLikes() { + Map likesPerType = posts + .stream() + .collect(groupingBy(BlogPost::getType, summingInt(BlogPost::getLikes))); + + assertEquals(50, likesPerType + .get(BlogPostType.NEWS) + .intValue()); + assertEquals(20, likesPerType + .get(BlogPostType.REVIEW) + .intValue()); + assertEquals(20, likesPerType + .get(BlogPostType.GUIDE) + .intValue()); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeInAnEnumMap_thenGetAnEnumMapBetweenTypeAndPosts() { + EnumMap> postsPerType = posts + .stream() + .collect(groupingBy(BlogPost::getType, () -> new EnumMap<>(BlogPostType.class), toList())); + + assertEquals(2, postsPerType + .get(BlogPostType.NEWS) + .size()); + assertEquals(1, postsPerType + .get(BlogPostType.GUIDE) + .size()); + assertEquals(2, postsPerType + .get(BlogPostType.REVIEW) + .size()); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeInSets_thenGetAMapBetweenTypesAndSetsOfPosts() { + Map> postsPerType = posts + .stream() + .collect(groupingBy(BlogPost::getType, toSet())); + + assertEquals(2, postsPerType + .get(BlogPostType.NEWS) + .size()); + assertEquals(1, postsPerType + .get(BlogPostType.GUIDE) + .size()); + assertEquals(2, postsPerType + .get(BlogPostType.REVIEW) + .size()); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeConcurrently_thenGetAMapBetweenTypeAndPosts() { + ConcurrentMap> postsPerType = posts + .parallelStream() + .collect(groupingByConcurrent(BlogPost::getType)); + + assertEquals(2, postsPerType + .get(BlogPostType.NEWS) + .size()); + assertEquals(1, postsPerType + .get(BlogPostType.GUIDE) + .size()); + assertEquals(2, postsPerType + .get(BlogPostType.REVIEW) + .size()); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeAndAveragingLikes_thenGetAMapBetweenTypeAndAverageNumberOfLikes() { + Map averageLikesPerType = posts + .stream() + .collect(groupingBy(BlogPost::getType, averagingInt(BlogPost::getLikes))); + + assertEquals(25, averageLikesPerType + .get(BlogPostType.NEWS) + .intValue()); + assertEquals(20, averageLikesPerType + .get(BlogPostType.GUIDE) + .intValue()); + assertEquals(10, averageLikesPerType + .get(BlogPostType.REVIEW) + .intValue()); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeAndCounted_thenGetAMapBetweenTypeAndNumberOfPosts() { + Map numberOfPostsPerType = posts + .stream() + .collect(groupingBy(BlogPost::getType, counting())); + + assertEquals(2, numberOfPostsPerType + .get(BlogPostType.NEWS) + .intValue()); + assertEquals(1, numberOfPostsPerType + .get(BlogPostType.GUIDE) + .intValue()); + assertEquals(2, numberOfPostsPerType + .get(BlogPostType.REVIEW) + .intValue()); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeAndMaxingLikes_thenGetAMapBetweenTypeAndMaximumNumberOfLikes() { + Map> maxLikesPerPostType = posts + .stream() + .collect(groupingBy(BlogPost::getType, maxBy(comparingInt(BlogPost::getLikes)))); + + assertTrue(maxLikesPerPostType + .get(BlogPostType.NEWS) + .isPresent()); + assertEquals(35, maxLikesPerPostType + .get(BlogPostType.NEWS) + .get() + .getLikes()); + + assertTrue(maxLikesPerPostType + .get(BlogPostType.GUIDE) + .isPresent()); + assertEquals(20, maxLikesPerPostType + .get(BlogPostType.GUIDE) + .get() + .getLikes()); + + assertTrue(maxLikesPerPostType + .get(BlogPostType.REVIEW) + .isPresent()); + assertEquals(15, maxLikesPerPostType + .get(BlogPostType.REVIEW) + .get() + .getLikes()); + } + + @Test + public void givenAListOfPosts_whenGroupedByAuthorAndThenByType_thenGetAMapBetweenAuthorAndMapsBetweenTypeAndBlogPosts() { + Map>> map = posts + .stream() + .collect(groupingBy(BlogPost::getAuthor, groupingBy(BlogPost::getType))); + + assertEquals(1, map + .get("Author 1") + .get(BlogPostType.NEWS) + .size()); + assertEquals(1, map + .get("Author 1") + .get(BlogPostType.GUIDE) + .size()); + assertEquals(1, map + .get("Author 1") + .get(BlogPostType.REVIEW) + .size()); + + assertEquals(1, map + .get("Author 2") + .get(BlogPostType.NEWS) + .size()); + assertEquals(1, map + .get("Author 2") + .get(BlogPostType.REVIEW) + .size()); + assertNull(map + .get("Author 2") + .get(BlogPostType.GUIDE)); + } + + @Test + public void givenAListOfPosts_whenGroupedByTypeAndSummarizingLikes_thenGetAMapBetweenTypeAndSummary() { + Map likeStatisticsPerType = posts + .stream() + .collect(groupingBy(BlogPost::getType, summarizingInt(BlogPost::getLikes))); + + IntSummaryStatistics newsLikeStatistics = likeStatisticsPerType.get(BlogPostType.NEWS); + + assertEquals(2, newsLikeStatistics.getCount()); + assertEquals(50, newsLikeStatistics.getSum()); + assertEquals(25.0, newsLikeStatistics.getAverage(), 0.001); + assertEquals(35, newsLikeStatistics.getMax()); + assertEquals(15, newsLikeStatistics.getMin()); + } + +} diff --git a/guava/src/test/java/org/baeldung/guava/CustomEvent.java b/guava/src/main/java/org/baeldung/guava/CustomEvent.java similarity index 100% rename from guava/src/test/java/org/baeldung/guava/CustomEvent.java rename to guava/src/main/java/org/baeldung/guava/CustomEvent.java diff --git a/guava/src/test/java/org/baeldung/guava/EventBusWrapper.java b/guava/src/main/java/org/baeldung/guava/EventBusWrapper.java similarity index 100% rename from guava/src/test/java/org/baeldung/guava/EventBusWrapper.java rename to guava/src/main/java/org/baeldung/guava/EventBusWrapper.java diff --git a/guava/src/test/java/org/baeldung/guava/EventListener.java b/guava/src/main/java/org/baeldung/guava/EventListener.java similarity index 100% rename from guava/src/test/java/org/baeldung/guava/EventListener.java rename to guava/src/main/java/org/baeldung/guava/EventListener.java diff --git a/spring-jersey/pom.xml b/spring-jersey/pom.xml index 293850d41e..41ebb9a6b5 100644 --- a/spring-jersey/pom.xml +++ b/spring-jersey/pom.xml @@ -9,7 +9,7 @@ war - 2.25 + 2.25.1 1.7.22 1.1.8 4.12 diff --git a/spring-jersey/src/main/java/com/baeldung/client/rest/RestClient.java b/spring-jersey/src/main/java/com/baeldung/client/rest/RestClient.java index 0e45b68b14..34f7d45601 100644 --- a/spring-jersey/src/main/java/com/baeldung/client/rest/RestClient.java +++ b/spring-jersey/src/main/java/com/baeldung/client/rest/RestClient.java @@ -18,7 +18,7 @@ public class RestClient { } public Employee getJsonEmployee(int id) { - return client.target(REST_URI).path(new Integer(id).toString()).request(MediaType.APPLICATION_JSON).get(Employee.class); + return client.target(REST_URI).path(String.valueOf(id)).request(MediaType.APPLICATION_JSON).get(Employee.class); } public Response createXmlEmployee(Employee emp) { @@ -26,6 +26,6 @@ public class RestClient { } public Employee getXmlEmployee(int id) { - return client.target(REST_URI).path(new Integer(id).toString()).request(MediaType.APPLICATION_XML).get(Employee.class); + return client.target(REST_URI).path(String.valueOf(id)).request(MediaType.APPLICATION_XML).get(Employee.class); } } diff --git a/spring-mvc-forms/pom.xml b/spring-mvc-forms/pom.xml index 31a0c38791..f17d695c35 100644 --- a/spring-mvc-forms/pom.xml +++ b/spring-mvc-forms/pom.xml @@ -46,6 +46,23 @@ commons-fileupload ${fileupload.version} + + + org.springframework.security + spring-security-web + ${org.springframework.security.version} + + + org.springframework.security + spring-security-config + ${org.springframework.security.version} + + + org.springframework.security + spring-security-taglibs + ${org.springframework.security.version} + + @@ -98,6 +115,7 @@ 5.3.3.Final enter-location-of-server 1.3.2 + 4.2.1.RELEASE diff --git a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/SecurityConfig.java b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/SecurityConfig.java new file mode 100644 index 0000000000..e35844138d --- /dev/null +++ b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/SecurityConfig.java @@ -0,0 +1,122 @@ +package com.baeldung.springmvcforms.configuration; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.TestingAuthenticationProvider; +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.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public UserDetailsService userDetailsService() throws Exception { + InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); + manager.createUser(User.withUsername("user") + .password("userPass") + .roles("USER") + .build()); + manager.createUser(User.withUsername("admin") + .password("adminPass") + .roles("ADMIN") + .build()); + return manager; + } + + @Configuration + @Order(1) + public static class App1ConfigurationAdapter extends WebSecurityConfigurerAdapter { + + public App1ConfigurationAdapter() { + super(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication() + .withUser("admin") + .password("admin") + .roles("ADMIN"); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.antMatcher("/admin*") + .authorizeRequests() + .anyRequest() + .hasRole("ADMIN") + // log in + .and() + .formLogin() + .loginPage("/loginAdmin") + .loginProcessingUrl("/admin_login") + .failureUrl("/loginAdmin?error=loginError") + .defaultSuccessUrl("/adminPage") + // logout + .and() + .logout() + .logoutUrl("/admin_logout") + .logoutSuccessUrl("/protectedLinks") + .deleteCookies("JSESSIONID") + .and() + .exceptionHandling() + .accessDeniedPage("/403") + .and() + .csrf() + .disable(); + } + } + + @Configuration + @Order(2) + public static class App2ConfigurationAdapter extends WebSecurityConfigurerAdapter { + + public App2ConfigurationAdapter() { + super(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication() + .withUser("user") + .password("user") + .roles("USER"); + } + + protected void configure(HttpSecurity http) throws Exception { + http.antMatcher("/user*") + .authorizeRequests() + .anyRequest() + .hasRole("USER") + // log in + .and() + .formLogin() + .loginPage("/loginUser") + .loginProcessingUrl("/user_login") + .failureUrl("/loginUser?error=loginError") + .defaultSuccessUrl("/userPage") + // logout + .and() + .logout() + .logoutUrl("/user_logout") + .logoutSuccessUrl("/protectedLinks") + .deleteCookies("JSESSIONID") + .and() + .exceptionHandling() + .accessDeniedPage("/403") + .and() + .csrf() + .disable(); + } + } + +} diff --git a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/WebInitializer.java b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/WebInitializer.java index c602ea6454..fdc155e101 100644 --- a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/WebInitializer.java +++ b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/configuration/WebInitializer.java @@ -3,6 +3,7 @@ package com.baeldung.springmvcforms.configuration; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.filter.DelegatingFilterProxy; import org.springframework.web.servlet.DispatcherServlet; import javax.servlet.ServletContext; @@ -24,6 +25,9 @@ public class WebInitializer implements WebApplicationInitializer { servlet.setLoadOnStartup(1); servlet.addMapping("/"); + + container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain")) + .addMappingForUrlPatterns(null, false, "/*"); } // @Override // public void onStartup(ServletContext container) { diff --git a/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UsersController.java b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UsersController.java new file mode 100644 index 0000000000..c0858d427f --- /dev/null +++ b/spring-mvc-forms/src/main/java/com/baeldung/springmvcforms/controller/UsersController.java @@ -0,0 +1,38 @@ +package com.baeldung.springmvcforms.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class UsersController { + + @RequestMapping("/protectedLinks") + public String getAnonymousPage() { + return "protectedLinks"; + } + + @RequestMapping("/userPage") + public String getUserPage() { + return "userPage"; + } + + @RequestMapping("/adminPage") + public String getAdminPage() { + return "adminPage"; + } + + @RequestMapping("/loginAdmin") + public String getAdminLoginPage() { + return "loginAdmin"; + } + + @RequestMapping("/loginUser") + public String getUserLoginPage() { + return "loginUser"; + } + + @RequestMapping("/403") + public String getAccessDeniedPage() { + return "403"; + } +} diff --git a/spring-mvc-forms/src/main/webapp/WEB-INF/views/403.jsp b/spring-mvc-forms/src/main/webapp/WEB-INF/views/403.jsp new file mode 100644 index 0000000000..e665793e10 --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/WEB-INF/views/403.jsp @@ -0,0 +1,12 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + + + + +Your do not have permission to view this page. + + \ No newline at end of file diff --git a/spring-mvc-forms/src/main/webapp/WEB-INF/views/adminPage.jsp b/spring-mvc-forms/src/main/webapp/WEB-INF/views/adminPage.jsp new file mode 100644 index 0000000000..a210b690b0 --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/WEB-INF/views/adminPage.jsp @@ -0,0 +1,16 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + +Insert title here + + +Welcome admin! Logout + +

+Back to links + + \ No newline at end of file diff --git a/spring-mvc-forms/src/main/webapp/WEB-INF/views/loginAdmin.jsp b/spring-mvc-forms/src/main/webapp/WEB-INF/views/loginAdmin.jsp new file mode 100644 index 0000000000..a6b2ee7914 --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/WEB-INF/views/loginAdmin.jsp @@ -0,0 +1,38 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + + + +Insert title here + + + +

Admin login page

+
+ + + + + + + + + + + + + +
User:
Password:
+ +
+ + <% + if (request.getParameter("error") != null) { + out.println("Login failed!"); + } + %> + + + \ No newline at end of file diff --git a/spring-mvc-forms/src/main/webapp/WEB-INF/views/loginUser.jsp b/spring-mvc-forms/src/main/webapp/WEB-INF/views/loginUser.jsp new file mode 100644 index 0000000000..e65c11edaf --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/WEB-INF/views/loginUser.jsp @@ -0,0 +1,37 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + + + +Login + + + +

User login page

+ +
+ + + + + + + + + + + + +
User:
Password:
+ +
+ <% + if (request.getParameter("error") != null) { + out.println("Login failed!"); + } + %> + + + \ No newline at end of file diff --git a/spring-mvc-forms/src/main/webapp/WEB-INF/views/protectedLinks.jsp b/spring-mvc-forms/src/main/webapp/WEB-INF/views/protectedLinks.jsp new file mode 100644 index 0000000000..b8453903ba --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/WEB-INF/views/protectedLinks.jsp @@ -0,0 +1,16 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + +Insert title here + + + +">User page +
+">Admin page + + \ No newline at end of file diff --git a/spring-mvc-forms/src/main/webapp/WEB-INF/views/userPage.jsp b/spring-mvc-forms/src/main/webapp/WEB-INF/views/userPage.jsp new file mode 100644 index 0000000000..4c1bd47502 --- /dev/null +++ b/spring-mvc-forms/src/main/webapp/WEB-INF/views/userPage.jsp @@ -0,0 +1,15 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + +Insert title here + + +Welcome user! Logout +

+Back to links + + \ No newline at end of file