Merge pull request #4 from eugenp/master

Update
This commit is contained in:
markusgulden 2018-01-27 11:08:33 +01:00 committed by GitHub
commit cb593c981d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
278 changed files with 6896 additions and 892 deletions

129
activejdbc/pom.xml Normal file
View File

@ -0,0 +1,129 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>activejdbc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>activejdbc</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<activejdbc.version>1.4.13</activejdbc.version>
<environments>development.test,development</environments>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.javalite</groupId>
<artifactId>activejdbc-instrumentation</artifactId>
<version>${activejdbc.version}</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>instrument</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.javalite</groupId>
<artifactId>db-migrator-maven-plugin</artifactId>
<version>${activejdbc.version}</version>
<configuration>
<configFile>${project.basedir}/src/main/resources/database.properties</configFile>
<environments>${environments}</environments>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<reportFormat>brief</reportFormat>
<trimStackTrace>true</trimStackTrace>
<useFile>false</useFile>
<includes>
<include>**/*Spec*.java</include>
<include>**/*Test*.java</include>
</includes>
<excludes>
<exclude>**/helpers/*</exclude>
<exclude>**/*$*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javalite</groupId>
<artifactId>activejdbc</artifactId>
<version>${activejdbc.version}</version>
<exclusions>
<exclusion>
<groupId>opensymphony</groupId>
<artifactId>oscache</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.9</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>snapshots1</id>
<name>JavaLite Snapshots1</name>
<url>http://repo.javalite.io/</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>snapshots2</id>
<name>JavaLite Snapshots2</name>
<url>http://repo.javalite.io/</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -0,0 +1,61 @@
package com.baeldung;
import com.baeldung.model.Employee;
import com.baeldung.model.Role;
import org.javalite.activejdbc.Base;
import org.javalite.activejdbc.LazyList;
import org.javalite.activejdbc.Model;
public class ActiveJDBCApp
{
public static void main( String[] args )
{
try {
Base.open();
ActiveJDBCApp app = new ActiveJDBCApp();
app.create();
app.update();
app.delete();
app.deleteCascade();
} catch (Exception e) {
e.printStackTrace();
} finally {
Base.close();
}
}
protected void create() {
Employee employee = new Employee("Hugo","C","M","BN");
employee.saveIt();
employee.add(new Role("Java Developer","BN"));
LazyList<Model> all = Employee.findAll();
System.out.println(all.size());
}
protected void update() {
Employee employee = Employee.findFirst("first_name = ?","Hugo");
employee.set("last_namea","Choi").saveIt();
employee = Employee.findFirst("last_name = ?","Choi");
System.out.println(employee.getString("first_name") + " " + employee.getString("last_name"));
}
protected void delete() {
Employee employee = Employee.findFirst("first_name = ?","Hugo");
employee.delete();
employee = Employee.findFirst("last_name = ?","Choi");
if(null == employee){
System.out.println("No such Employee found!");
}
}
protected void deleteCascade() {
create();
Employee employee = Employee.findFirst("first_name = ?","Hugo");
employee.deleteCascade();
employee = Employee.findFirst("last_name = ?","C");
if(null == employee){
System.out.println("No such Employee found!");
}
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.model;
import org.javalite.activejdbc.Model;
public class Employee extends Model {
public Employee(){
}
public Employee(String firstName, String lastName, String gender, String createdBy) {
set("first_name1",firstName);
set("last_name",lastName);
set("gender",gender);
set("created_by",createdBy);
}
}

View File

@ -0,0 +1,18 @@
package com.baeldung.model;
import org.javalite.activejdbc.Model;
import org.javalite.activejdbc.annotations.Table;
@Table("EMP_ROLES")
public class Role extends Model {
public Role(){
}
public Role(String role,String createdBy){
set("role_name",role);
set("created_by",createdBy);
}
}

View File

@ -0,0 +1,25 @@
# noinspection SqlNoDataSourceInspectionForFile
create table organisation.employees
(
id int not null auto_increment
primary key,
first_name varchar(100) not null,
last_name varchar(100) not null,
gender varchar(1) not null,
created_at datetime not null,
updated_at datetime null,
created_by varchar(100) not null,
updated_by varchar(100) null
)ENGINE = InnoDB DEFAULT CHARSET = utf8;
create table organisation.emp_roles
(
id int not null auto_increment primary key,
employee_id int not null,
role_name varchar(100) not null,
created_at datetime not null,
updated_at datetime null,
created_by varchar(100) not null,
updated_by varchar(100) null
)ENGINE = InnoDB DEFAULT CHARSET = utf8;

View File

@ -0,0 +1,10 @@
development.driver=com.mysql.jdbc.Driver
development.username=root
development.password=123456
development.url=jdbc:mysql://localhost/organisation
development.test.driver=com.mysql.jdbc.Driver
development.test.username=root
development.test.password=123456
development.test.url=jdbc:mysql://localhost/organisation_test

View File

@ -0,0 +1,51 @@
package com.baeldung;
import com.baeldung.model.Employee;
import com.baeldung.model.Role;
import org.javalite.activejdbc.test.DBSpec;
import org.junit.Test;
import java.util.List;
public class ActiveJDBCAppTest extends DBSpec
{
@Test
public void ifEmployeeCreated_thenIsValid() {
Employee employee = new Employee("B", "N", "M", "BN");
the(employee).shouldBe("valid");
}
@Test
public void ifEmployeeCreatedWithRoles_thenShouldPersist() {
Employee employee = new Employee("B", "N", "M", "BN");
employee.saveIt();
employee.add(new Role("Java Developer","BN"));
employee.add(new Role("Lead Java Developer","BN"));
a(Role.count()).shouldBeEqual(2);
List<Role> roles = employee.getAll(Role.class).orderBy("created_at");
the(roles.get(0).getRoleName()).shouldBeEqual("Java Developer");
the(roles.get(1).getRoleName()).shouldBeEqual("Lead Java Developer");
}
@Test
public void ifEmployeeCreatedWithRoles_whenNameUpdated_thenShouldShowNewName() {
Employee employee = new Employee("Binesh", "N", "M", "BN");
employee.saveIt();
employee.add(new Role("Java Developer","BN"));
employee.add(new Role("Lead Java Developer","BN"));
employee = Employee.findFirst("first_name = ?", "Binesh");
employee.set("last_name","Narayanan").saveIt();
Employee updated = Employee.findFirst("first_name = ?", "Binesh");
the(updated.getLastName()).shouldBeEqual("Narayanan");
}
@Test
public void ifEmployeeCreatedWithRoles_whenDeleted_thenShouldNotBeFound() {
Employee employee = new Employee("Binesh", "N", "M", "BN");
employee.saveIt();
employee.add(new Role("Java Developer","BN"));
employee.delete();
employee = Employee.findFirst("first_name = ?", "Binesh");
the(employee).shouldBeNull();
}
}

View File

@ -1,3 +1,4 @@
### 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)
- [Creating a MS PowerPoint Presentation in Java](https://github.com/eugenp/tutorials/tree/master/apache-poi)

View File

@ -37,3 +37,6 @@
- [Iterable to Stream in Java](http://www.baeldung.com/java-iterable-to-stream)
- [Converting String to Stream of chars](http://www.baeldung.com/java-string-to-stream)
- [How to Iterate Over a Stream With Indices](http://www.baeldung.com/java-stream-indices)
- [Efficient Word Frequency Calculator in Java](http://www.baeldung.com/java-word-frequency)
- [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams)
- [Fail-Safe Iterator vs Fail-Fast Iterator](http://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator)

View File

@ -1,45 +1,19 @@
package com.baeldung.spliteratorAPI;
import java.util.Arrays;
import java.util.List;
import java.util.Spliterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class Executor {
public void executeCustomSpliterator() {
Article article = new Article(Arrays.asList(new Author("Ahmad", 0), new Author("Eugen", 0), new Author("Alice", 1), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1),
new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0),
new Author("Alice", 1), new Author("Mike", 0), new Author("Michał", 0), new Author("Loredana", 1)), 0);
Stream<Author> stream = IntStream.range(0, article.getListOfAuthors()
.size())
.mapToObj(article.getListOfAuthors()::get);
System.out.println("count= " + countAutors(stream.parallel()));
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(article.getListOfAuthors());
Stream<Author> stream2 = StreamSupport.stream(spliterator, true);
System.out.println("count= " + countAutors(stream2.parallel()));
}
public void executeSpliterator() {
Spliterator<Article> split1 = generateElements().spliterator();
Spliterator<Article> split2 = split1.trySplit();
ExecutorService service = Executors.newCachedThreadPool();
service.execute(new Task(split1));
service.execute(new Task(split2));
}
private static int countAutors(Stream<Author> stream) {
RelatedAuthorCounter wordCounter = stream.reduce(new RelatedAuthorCounter(0, true), RelatedAuthorCounter::accumulate, RelatedAuthorCounter::combine);
public static int countAutors(Stream<Author> stream) {
RelatedAuthorCounter wordCounter = stream.reduce(new RelatedAuthorCounter(0, true),
RelatedAuthorCounter::accumulate, RelatedAuthorCounter::combine);
return wordCounter.getCounter();
}
private List<Article> generateElements() {
return Stream.generate(() -> new Article("Java"))
.limit(35000)
.collect(Collectors.toList());
public static List<Article> generateElements() {
return Stream.generate(() -> new Article("Java")).limit(35000).collect(Collectors.toList());
}
}

View File

@ -2,11 +2,12 @@ package com.baeldung.spliteratorAPI;
import java.util.List;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class RelatedAuthorSpliterator implements Spliterator<Author> {
private final List<Author> list;
private int current = 0;
AtomicInteger current = new AtomicInteger();
public RelatedAuthorSpliterator(List<Author> list) {
this.list = list;
@ -14,21 +15,21 @@ public class RelatedAuthorSpliterator implements Spliterator<Author> {
@Override
public boolean tryAdvance(Consumer<? super Author> action) {
action.accept(list.get(current++));
return current < list.size();
action.accept(list.get(current.getAndIncrement()));
return current.get() < list.size();
}
@Override
public Spliterator<Author> trySplit() {
int currentSize = list.size() - current;
int currentSize = list.size() - current.get();
if (currentSize < 10) {
return null;
}
for (int splitPos = currentSize / 2 + current; splitPos < list.size(); splitPos++) {
if (list.get(splitPos)
.getRelatedArticleId() == 0) {
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(list.subList(current, splitPos));
current = splitPos;
for (int splitPos = currentSize / 2 + current.intValue(); splitPos < list.size(); splitPos++) {
if (list.get(splitPos).getRelatedArticleId() == 0) {
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(list.subList(current.get(), splitPos));
current.set(splitPos);
return spliterator;
}
}
@ -37,11 +38,12 @@ public class RelatedAuthorSpliterator implements Spliterator<Author> {
@Override
public long estimateSize() {
return list.size() - current;
return list.size() - current.get();
}
@Override
public int characteristics() {
return SIZED + CONCURRENT;
return CONCURRENT;
}
}

View File

@ -1,8 +1,9 @@
package com.baeldung.spliteratorAPI;
import java.util.Spliterator;
import java.util.concurrent.Callable;
public class Task implements Runnable {
public class Task implements Callable<String> {
private Spliterator<Article> spliterator;
private final static String SUFFIX = "- published by Baeldung";
@ -11,7 +12,7 @@ public class Task implements Runnable {
}
@Override
public void run() {
public String call() {
int current = 0;
while (spliterator.tryAdvance(article -> {
article.setName(article.getName()
@ -20,7 +21,7 @@ public class Task implements Runnable {
current++;
}
;
System.out.println(Thread.currentThread()
.getName() + ":" + current);
return Thread.currentThread()
.getName() + ":" + current;
}
}

View File

@ -0,0 +1,44 @@
package com.baeldung.spliteratorAPI;
import java.util.Arrays;
import java.util.Spliterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static org.assertj.core.api.Assertions.*;
import org.junit.Before;
import org.junit.Test;
public class ExecutorTest {
Article article;
Stream<Author> stream;
Spliterator<Author> spliterator;
Spliterator<Article> split1;
Spliterator<Article> split2;
@Before
public void init() {
article = new Article(Arrays.asList(new Author("Ahmad", 0), new Author("Eugen", 0), new Author("Alice", 1),
new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0),
new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0),
new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1),
new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1),
new Author("Mike", 0), new Author("Michał", 0), new Author("Loredana", 1)), 0);
stream = article.getListOfAuthors().stream();
split1 = Executor.generateElements().spliterator();
split2 = split1.trySplit();
spliterator = new RelatedAuthorSpliterator(article.getListOfAuthors());
}
@Test
public void givenAstreamOfAuthors_whenProcessedInParallelWithCustomSpliterator_coubtProducessRightOutput() {
Stream<Author> stream2 = StreamSupport.stream(spliterator, true);
assertThat(Executor.countAutors(stream2.parallel())).isEqualTo(9);
}
@Test
public void givenSpliterator_whenAppliedToAListOfArticle_thenSplittedInHalf() {
assertThat(new Task(split1).call()).containsSequence(Executor.generateElements().size() / 2 + "");
assertThat(new Task(split2).call()).containsSequence(Executor.generateElements().size() / 2 + "");
}
}

View File

@ -33,3 +33,4 @@
- [Daemon Threads in Java](http://www.baeldung.com/java-daemon-thread)
- [Implementing a Runnable vs Extending a Thread](http://www.baeldung.com/java-runnable-vs-extending-thread)
- [How to Kill a Java Thread](http://www.baeldung.com/java-thread-stop)
- [ExecutorService - Waiting for Threads to Finish](http://www.baeldung.com/java-executor-wait-for-threads)

View File

@ -43,7 +43,8 @@ public class ControlSubThread implements Runnable {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
// no-op, just loop again
Thread.currentThread().interrupt();
System.out.println("Thread was interrupted, Failed to complete operation");
}
// do something
}

View File

@ -1,5 +1,7 @@
package com.baeldung.concurrent.waitandnotify;
import org.slf4j.Logger;
public class Data {
private String packet;
@ -11,7 +13,9 @@ public class Data {
while (transfer) {
try {
wait();
} catch (InterruptedException e) {}
} catch (InterruptedException e) {
System.out.println("Thread Interrupted");
}
}
transfer = true;
@ -23,7 +27,9 @@ public class Data {
while (!transfer) {
try {
wait();
} catch (InterruptedException e) {}
} catch (InterruptedException e) {
System.out.println("Thread Interrupted");
}
}
transfer = false;

View File

@ -19,7 +19,9 @@ public class Receiver implements Runnable {
//Thread.sleep() to mimic heavy server-side processing
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 5000));
} catch (InterruptedException e) {}
} catch (InterruptedException e) {
System.out.println("Thread Interrupted");
}
}
}
}

View File

@ -24,7 +24,9 @@ public class Sender implements Runnable {
//Thread.sleep() to mimic heavy server-side processing
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 5000));
} catch (InterruptedException e) {}
} catch (InterruptedException e) {
System.out.println("Thread Interrupted");
}
}
}
}

View File

@ -118,3 +118,12 @@
- [Implementing a Binary Tree in Java](http://www.baeldung.com/java-binary-tree)
- [A Guide to ThreadLocalRandom in Java](http://www.baeldung.com/java-thread-local-random)
- [RegEx for matching Date Pattern in Java](http://www.baeldung.com/java-date-regular-expressions)
- [Introduction to the JDBC RowSet Interface in Java](http://www.baeldung.com/java-jdbc-rowset)
- [Nested Classes in Java](http://www.baeldung.com/java-nested-classes)
- [A Guide to Java Loops](http://www.baeldung.com/java-loops)
- [Varargs in Java](http://www.baeldung.com/java-varargs)
- [A Guide to HashSet in Java](http://www.baeldung.com/java-hashset)
- [A Guide to Inner Interfaces in Java](http://www.baeldung.com/java-inner-interfaces)
- [Polymorphism in Java](http://www.baeldung.com/java-polymorphism)
- [Recursion In Java](http://www.baeldung.com/java-recursion)
- [A Guide to the finalize Method in Java](http://www.baeldung.com/java-finalize)

View File

@ -0,0 +1,30 @@
package com.baeldung.finalize;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class CloseableResource implements AutoCloseable {
private BufferedReader reader;
public CloseableResource() {
InputStream input = this.getClass().getClassLoader().getResourceAsStream("file.txt");
reader = new BufferedReader(new InputStreamReader(input));
}
public String readFirstLine() throws IOException {
String firstLine = reader.readLine();
return firstLine;
}
@Override
public void close() {
try {
reader.close();
System.out.println("Closed BufferedReader in the close method");
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.finalize;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Finalizable {
private BufferedReader reader;
public Finalizable() {
InputStream input = this.getClass().getClassLoader().getResourceAsStream("file.txt");
reader = new BufferedReader(new InputStreamReader(input));
}
public String readFirstLine() throws IOException {
String firstLine = reader.readLine();
return firstLine;
}
@Override
public void finalize() {
try {
reader.close();
System.out.println("Closed BufferedReader in the finalizer");
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,62 @@
package com.baeldung.trie;
public class Trie {
private TrieNode root;
Trie() {
root = new TrieNode();
}
public void insert(String word) {
TrieNode current = root;
for (int i = 0; i < word.length(); i++) {
current = current.getChildren().computeIfAbsent(word.charAt(i), c -> new TrieNode());
}
current.setEndOfWord(true);
}
public boolean delete(String word) {
return delete(root, word, 0);
}
public boolean containsNode(String word) {
TrieNode current = root;
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
TrieNode node = current.getChildren().get(ch);
if (node == null) {
return false;
}
current = node;
}
return current.isEndOfWord();
}
public boolean isEmpty() {
return root == null;
}
private boolean delete(TrieNode current, String word, int index) {
if (index == word.length()) {
if (!current.isEndOfWord()) {
return false;
}
current.setEndOfWord(false);
return current.getChildren().isEmpty();
}
char ch = word.charAt(index);
TrieNode node = current.getChildren().get(ch);
if (node == null) {
return false;
}
boolean shouldDeleteCurrentNode = delete(node, word, index + 1);
if (shouldDeleteCurrentNode) {
current.getChildren().remove(ch);
return current.getChildren().isEmpty();
}
return false;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.trie;
import java.util.HashMap;
import java.util.Map;
class TrieNode {
private Map<Character, TrieNode> children;
private boolean endOfWord;
public TrieNode() {
children = new HashMap<>();
endOfWord = false;
}
public Map<Character, TrieNode> getChildren() {
return children;
}
public void setChildren(Map<Character, TrieNode> children) {
this.children = children;
}
public boolean isEndOfWord() {
return endOfWord;
}
public void setEndOfWord(boolean endOfWord) {
this.endOfWord = endOfWord;
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.finalize;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
public class FinalizeUnitTest {
@Test
public void whenGC_thenFinalizerExecuted() throws IOException {
String firstLine = new Finalizable().readFirstLine();
Assert.assertEquals("baeldung.com", firstLine);
System.gc();
}
@Test
public void whenTryWResourcesExits_thenResourceClosed() throws IOException {
try (CloseableResource resource = new CloseableResource()) {
String firstLine = resource.readFirstLine();
Assert.assertEquals("baeldung.com", firstLine);
}
}
}

View File

@ -0,0 +1,68 @@
package com.baeldung.trie;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class TrieTest {
@Test
public void whenEmptyTrie_thenNoElements() {
Trie trie = new Trie();
assertFalse(trie.isEmpty());
}
@Test
public void givenATrie_whenAddingElements_thenTrieNotEmpty() {
Trie trie = createExampleTrie();
assertFalse(trie.isEmpty());
}
@Test
public void givenATrie_whenAddingElements_thenTrieHasThoseElements() {
Trie trie = createExampleTrie();
assertFalse(trie.containsNode("3"));
assertFalse(trie.containsNode("vida"));
assertTrue(trie.containsNode("Programming"));
assertTrue(trie.containsNode("is"));
assertTrue(trie.containsNode("a"));
assertTrue(trie.containsNode("way"));
assertTrue(trie.containsNode("of"));
assertTrue(trie.containsNode("life"));
}
@Test
public void givenATrie_whenLookingForNonExistingElement_thenReturnsFalse() {
Trie trie = createExampleTrie();
assertFalse(trie.containsNode("99"));
}
@Test
public void givenATrie_whenDeletingElements_thenTreeDoesNotContainThoseElements() {
Trie trie = createExampleTrie();
assertTrue(trie.containsNode("Programming"));
trie.delete("Programming");
assertFalse(trie.containsNode("Programming"));
}
private Trie createExampleTrie() {
Trie trie = new Trie();
trie.insert("Programming");
trie.insert("is");
trie.insert("a");
trie.insert("way");
trie.insert("of");
trie.insert("life");
return trie;
}
}

View File

@ -16,5 +16,5 @@
- [Delegated Properties in Kotlin](http://www.baeldung.com/kotlin-delegated-properties)
- [Sealed Classes in Kotlin](http://www.baeldung.com/kotlin-sealed-classes)
- [JUnit 5 for Kotlin Developers](http://www.baeldung.com/junit-5-kotlin)
- [Extension Methods in Kotlin](http://www.baeldung.com/kotlin-extension-methods)

View File

@ -44,6 +44,16 @@
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin-stdlib.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jre8</artifactId>
<version>${kotlin-stdlib.version}</version>
</dependency>
<dependency>
<groupId>khttp</groupId>
<artifactId>khttp</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit</artifactId>

View File

@ -0,0 +1,67 @@
package com.baeldung.kotlin
import org.junit.Test
import java.beans.ExceptionListener
import java.beans.XMLEncoder
import java.io.*
import java.lang.Exception
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail
class UseTest {
@Test
fun givenCloseable_whenUseIsCalled_thenItIsClosed() {
val stringWriter = StringWriter()
val writer = BufferedWriter(stringWriter) //Using a BufferedWriter because after close() it throws.
writer.use {
assertEquals(writer, it)
it.write("something")
}
try {
writer.write("something else")
fail("write() should have thrown an exception because the writer is closed.")
} catch (e: IOException) {
//Ok
}
assertEquals("something", stringWriter.toString())
}
@Test
fun givenAutoCloseable_whenUseIsCalled_thenItIsClosed() {
val baos = ByteArrayOutputStream()
val encoder = XMLEncoder(PrintStream(baos)) //XMLEncoder is AutoCloseable but not Closeable.
//Here, we use a PrintStream because after close() it throws.
encoder.exceptionListener = ThrowingExceptionListener()
encoder.use {
assertEquals(encoder, it)
it.writeObject("something")
}
try {
encoder.writeObject("something else")
encoder.flush()
fail("write() should have thrown an exception because the encoder is closed.")
} catch (e: IOException) {
//Ok
}
}
@Test
fun whenSimpleFormIsUsed_thenItWorks() {
StringWriter().use { it.write("something") }
}
}
class ThrowingExceptionListener : ExceptionListener {
override fun exceptionThrown(e: Exception?) {
if(e != null) {
throw e
}
}
}

View File

@ -0,0 +1,153 @@
package com.baeldung.kotlin.khttp
import khttp.structures.files.FileLike
import org.json.JSONObject
import org.junit.Test
import java.beans.ExceptionListener
import java.beans.XMLEncoder
import java.io.*
import java.lang.Exception
import java.net.ConnectException
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail
class KhttpTest {
@Test
fun whenHttpGetRequestIsMade_thenArgsAreReturned() {
val response = khttp.get(
url = "http://httpbin.org/get",
params = mapOf("p1" to "1", "p2" to "2"))
val args = response.jsonObject.getJSONObject("args")
assertEquals("1", args["p1"])
assertEquals("2", args["p2"])
}
@Test
fun whenAlternateHttpGetRequestIsMade_thenArgsAreReturned() {
val response = khttp.request(
method = "GET",
url = "http://httpbin.org/get",
params = mapOf("p1" to "1", "p2" to "2"))
val args = response.jsonObject.getJSONObject("args")
assertEquals("1", args["p1"])
assertEquals("2", args["p2"])
}
@Test
fun whenHeadersAreSet_thenHeadersAreSent() {
val response = khttp.get(
url = "http://httpbin.org/get",
headers = mapOf("header1" to "1", "header2" to "2"))
val headers = response.jsonObject.getJSONObject("headers")
assertEquals("1", headers["Header1"])
assertEquals("2", headers["Header2"])
}
@Test
fun whenHttpPostRequestIsMadeWithJson_thenBodyIsReturned() {
val response = khttp.post(
url = "http://httpbin.org/post",
params = mapOf("p1" to "1", "p2" to "2"),
json = mapOf("pr1" to "1", "pr2" to "2"))
val args = response.jsonObject.getJSONObject("args")
assertEquals("1", args["p1"])
assertEquals("2", args["p2"])
val json = response.jsonObject.getJSONObject("json")
assertEquals("1", json["pr1"])
assertEquals("2", json["pr2"])
}
@Test
fun whenHttpPostRequestIsMadeWithMapData_thenBodyIsReturned() {
val response = khttp.post(
url = "http://httpbin.org/post",
params = mapOf("p1" to "1", "p2" to "2"),
data = mapOf("pr1" to "1", "pr2" to "2"))
val args = response.jsonObject.getJSONObject("args")
assertEquals("1", args["p1"])
assertEquals("2", args["p2"])
val form = response.jsonObject.getJSONObject("form")
assertEquals("1", form["pr1"])
assertEquals("2", form["pr2"])
}
@Test
fun whenHttpPostRequestIsMadeWithFiles_thenBodyIsReturned() {
val response = khttp.post(
url = "http://httpbin.org/post",
params = mapOf("p1" to "1", "p2" to "2"),
files = listOf(
FileLike("file1", "content1"),
FileLike("file2", javaClass.getResource("KhttpTest.class").openStream().readBytes())))
val args = response.jsonObject.getJSONObject("args")
assertEquals("1", args["p1"])
assertEquals("2", args["p2"])
val files = response.jsonObject.getJSONObject("files")
assertEquals("content1", files["file1"])
}
@Test
fun whenHttpPostRequestIsMadeWithInputStream_thenBodyIsReturned() {
val response = khttp.post(
url = "http://httpbin.org/post",
params = mapOf("p1" to "1", "p2" to "2"),
data = ByteArrayInputStream("content!".toByteArray()))
val args = response.jsonObject.getJSONObject("args")
assertEquals("1", args["p1"])
assertEquals("2", args["p2"])
assertEquals("content!", response.jsonObject["data"])
}
@Test
fun whenHttpPostStreamingRequestIsMade_thenBodyIsReturnedInChunks() {
val response = khttp.post(
url = "http://httpbin.org/post",
stream = true,
json = mapOf("pr1" to "1", "pr2" to "2"))
val baos = ByteArrayOutputStream()
response.contentIterator(chunkSize = 10).forEach { arr : ByteArray -> baos.write(arr) }
val json = JSONObject(String(baos.toByteArray())).getJSONObject("json")
assertEquals("1", json["pr1"])
assertEquals("2", json["pr2"])
}
@Test
fun whenHttpRequestFails_thenExceptionIsThrown() {
try {
khttp.get(url = "http://localhost/nothing/to/see/here")
fail("Should have thrown an exception")
} catch (e : ConnectException) {
//Ok
}
}
@Test
fun whenHttpNotFound_thenExceptionIsThrown() {
val response = khttp.get(url = "http://httpbin.org/nothing/to/see/here")
assertEquals(404, response.statusCode)
}
}

View File

@ -1,4 +1,4 @@
## Relevant articles:
- [Intro to Dubbo](http://www.baeldung.com/dubbo-intro)
- [Introduction to Dubbo](http://www.baeldung.com/dubbo)

View File

@ -1,2 +1,3 @@
### Relevant Articles:
- [Database Migrations with Flyway](http://www.baeldung.com/database-migrations-with-flyway)
- [A Guide to Flyway Callbacks](http://www.baeldung.com/flyway-callbacks)

View File

@ -1,2 +1,4 @@
## Relevant articles:
- [Introduction to Gradle](http://www.baeldung.com/gradle)
- [Writing Custom Gradle Plugins](http://www.baeldung.com/gradle-create-plugin)
- [Creating a Fat Jar in Gradle](http://www.baeldung.com/gradle-fat-jar)

15
guest/deep-jsf/README.md Normal file
View File

@ -0,0 +1,15 @@
## Building
To build the module, use Maven's `package` goal:
```
mvn clean package
```
The `war` file will be available at `target/deep-jsf.war`
## Running
The `war` application is deployed to a Java EE 7 compliant application server, for example, to GlassFish 4 or later.
The example then will be accessible at http://localhost:8080/deep-jsf/index.xhtml

40
guest/deep-jsf/pom.xml Normal file
View File

@ -0,0 +1,40 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.stackify</groupId>
<artifactId>deep-jsf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>deep-jsf</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,14 @@
package com.stackify.deepjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class GreetControllerBean {
public String greet() {
return "greet";
}
}

View File

@ -0,0 +1,47 @@
package com.stackify.deepjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;
@ManagedBean
@RequestScoped
public class PhaseListenerBean {
public void beforeListener(PhaseEvent event) {
if (!event.getPhaseId().equals(PhaseId.RENDER_RESPONSE)) {
return;
}
UIViewRoot root = event.getFacesContext().getViewRoot();
boolean showNewFeature = showNewFeatureForIp(event);
processComponentTree(root, event, showNewFeature);
}
private boolean showNewFeatureForIp(PhaseEvent event) {
HttpServletRequest request = (HttpServletRequest) event.getFacesContext()
.getExternalContext().getRequest();
String ip = request.getRemoteAddr();
return !ip.startsWith("127.0");
}
private void processComponentTree(UIComponent component, PhaseEvent event, boolean show) {
component.visitTree(VisitContext.createVisitContext(event.getFacesContext()),
(context, target) -> {
if (target.getId() != null
&& target.getId().startsWith("new-feature-")
&& !show) {
target.setRendered(false);
}
return VisitResult.ACCEPT;
});
}
}

View File

@ -0,0 +1,48 @@
package com.stackify.deepjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ValueChangeEvent;
@ManagedBean
@SessionScoped
public class UserBean {
private String name = "";
private String lastName = "";
private String proposedLogin = "";
public void nameChanged(ValueChangeEvent event) {
this.proposedLogin = event.getNewValue() + "-" + lastName;
}
public void lastNameChanged(ValueChangeEvent event) {
this.proposedLogin = name + "-" + event.getNewValue();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getProposedLogin() {
return proposedLogin;
}
public void setProposedLogin(String proposedLogin) {
this.proposedLogin = proposedLogin;
}
}

View File

@ -0,0 +1,14 @@
package com.stackify.deepjsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class UserControllerBean {
public String register() {
return "register-success";
}
}

View File

@ -0,0 +1,15 @@
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<navigation-rule>
<from-view-id>/register.xhtml</from-view-id>
<navigation-case>
<from-outcome>register-success</from-outcome>
<to-view-id>/hello.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view beforePhase="#{phaseListenerBean.beforeListener}">
<h:outputLabel value="Hello, #{userBean.name}"/>
<h:outputLabel id="new-feature-last-name" value=" #{userBean.lastName}"/>
</f:view>
</html>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view>
<h:outputLabel value="Hello, #{userBean.name} #{userBean.lastName}! Your login is: #{userBean.proposedLogin}"/>
</f:view>
</html>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view beforePhase="#{phaseListenerBean.beforeListener}">
<h:form>
<h:panelGrid columns="2">
<h:outputLabel value="First Name:"/>
<h:inputText id="name" value="#{userBean.name}"/>
<h:outputLabel id="new-feature-last-name-label" value="Last Name:"/>
<h:inputText id="new-feature-last-name" value="#{userBean.lastName}"/>
<h:commandButton value="Submit" action="#{greetControllerBean.greet}"/>
</h:panelGrid>
</h:form>
</f:view>
</html>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<h:outputScript library="javax.faces" name="jsf.js"/>
</h:head>
<f:view>
<h:form>
<h:panelGrid columns="2">
<h:outputLabel value="First Name:"/>
<h:inputText id="name" value="#{userBean.name}"
valueChangeListener="#{userBean.nameChanged}">
<f:ajax event="change" execute="@this" render="proposed-login"/>
</h:inputText>
<h:outputLabel id="lastname-label" value="Last Name:"/>
<h:inputText id="lastname" value="#{userBean.lastName}"
valueChangeListener="#{userBean.lastNameChanged}">
<f:ajax event="change" execute="@this" render="proposed-login"/>
</h:inputText>
<h:outputLabel id="login-label" value="Proposed Login:"/>
<h:inputText id="proposed-login" disabled="true" value="#{userBean.proposedLogin}"/>
<h:commandButton value="Submit" action="#{userControllerBean.register}"/>
</h:panelGrid>
</h:form>
</f:view>
</html>

View File

@ -5,3 +5,5 @@
- [Hibernate Mapping Date and Time](http://www.baeldung.com/hibernate-date-time)
- [Hibernate Inheritance Mapping](http://www.baeldung.com/hibernate-inheritance)
- [A Guide to Multitenancy in Hibernate 5](http://www.baeldung.com/hibernate-5-multitenancy)
- [Introduction to Hibernate Spatial](http://www.baeldung.com/hibernate-spatial)
- [Hibernate Interceptors](http://www.baeldung.com/hibernate-interceptor)

View File

@ -2,6 +2,7 @@
### 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.

View File

@ -55,7 +55,7 @@ public class InfluxDBConnectionLiveTest {
InfluxDB connection = connectDatabase();
// Create "baeldung and check for it
// Create "baeldung" and check for it
connection.createDatabase("baeldung");
assertTrue(connection.databaseExists("baeldung"));

20
java-rmi/pom.xml Normal file
View File

@ -0,0 +1,20 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.rmi</groupId>
<artifactId>java-rmi</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@ -0,0 +1,36 @@
package com.baeldung.rmi;
import java.io.Serializable;
public class Message implements Serializable {
private String messageText;
private String contentType;
public Message() {
}
public Message(String messageText, String contentType) {
this.messageText = messageText;
this.contentType = contentType;
}
public String getMessageText() {
return messageText;
}
public void setMessageText(String messageText) {
this.messageText = messageText;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MessengerService extends Remote {
public String sendMessage(String clientMessage) throws RemoteException;
public Message sendMessage(Message clientMessage) throws RemoteException;
}

View File

@ -0,0 +1,37 @@
package com.baeldung.rmi;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class MessengerServiceImpl implements MessengerService {
public String sendMessage(String clientMessage) {
String serverMessage = null;
if (clientMessage.equals("Client Message")) {
serverMessage = "Server Message";
}
return serverMessage;
}
public void createStubAndBind() throws RemoteException {
MessengerService stub = (MessengerService) UnicastRemoteObject.exportObject((MessengerService) this, 0);
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("MessengerService", stub);
}
public Message sendMessage(Message clientMessage) throws RemoteException {
Message serverMessage = null;
if (clientMessage.getMessageText().equals("Client Message")) {
serverMessage = new Message("Server Message", "text/plain");
}
return serverMessage;
}
}

View File

@ -0,0 +1,44 @@
package com.baeldung.rmi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import org.junit.BeforeClass;
import org.junit.Test;
public class JavaRMIIntegrationTest {
@BeforeClass
public static void whenRunServer_thenServerStarts() {
try {
MessengerServiceImpl server = new MessengerServiceImpl();
server.createStubAndBind();
} catch (RemoteException e) {
fail("Exception Occurred");
}
}
@Test
public void whenClientSendsMessageToServer_thenServerSendsResponseMessage() {
try {
Registry registry = LocateRegistry.getRegistry();
MessengerService server = (MessengerService) registry.lookup("MessengerService");
String responseMessage = server.sendMessage("Client Message");
String expectedMessage = "Server Message";
assertEquals(responseMessage, expectedMessage);
} catch (RemoteException e) {
fail("Exception Occurred");
} catch (NotBoundException nb) {
fail("Exception Occurred");
}
}
}

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>2.33</version>
<relativePath />
</parent>
<artifactId>jenkins-hello-world</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>hpi</packaging>
<properties>
<!-- Baseline Jenkins version you use to build the plugin. Users must have this version or newer to run. -->
<jenkins.version>2.7.3</jenkins.version>
</properties>
<name>Hello World Plugin</name>
<description>A sample Jenkins Hello World plugin</description>
<url>https://wiki.jenkins-ci.org/display/JENKINS/TODO+Plugin</url>
<licenses>
<license>
<name>MIT License</name>
<url>http://opensource.org/licenses/MIT</url>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>structs</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>2.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>2.39</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<version>2.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</artifactId>
<version>2.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-durable-task-step</artifactId>
<version>2.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>2.20</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-support</artifactId>
<version>2.14</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
<url>https://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repo.jenkins-ci.org</id>
<url>https://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -0,0 +1,20 @@
package com.baeldung.jenkins.helloworld;
public class ProjectStats {
private final int classesNumber;
private final int linesNumber;
public ProjectStats(int classesNumber, int linesNumber) {
this.classesNumber = classesNumber;
this.linesNumber = linesNumber;
}
public int getClassesNumber() {
return classesNumber;
}
public int getLinesNumber() {
return linesNumber;
}
}

View File

@ -0,0 +1,123 @@
package com.baeldung.jenkins.helloworld;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapperDescriptor;
import org.kohsuke.stapler.DataBoundConstructor;
import javax.annotation.Nonnull;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Stack;
public class ProjectStatsBuildWrapper extends BuildWrapper {
private static final String REPORT_TEMPLATE_PATH = "/stats.html";
private static final String PROJECT_NAME_VAR = "$PROJECT_NAME$";
private static final String CLASSES_NUMBER_VAR = "$CLASSES_NUMBER$";
private static final String LINES_NUMBER_VAR = "$LINES_NUMBER$";
@DataBoundConstructor
public ProjectStatsBuildWrapper() {
}
@Override
public Environment setUp(AbstractBuild build, final Launcher launcher, BuildListener listener) {
return new Environment() {
@Override
public boolean tearDown(AbstractBuild build, BuildListener listener)
throws IOException, InterruptedException
{
ProjectStats stats = buildStats(build.getWorkspace());
String report = generateReport(build.getProject().getDisplayName(), stats);
File artifactsDir = build.getArtifactsDir();
if (!artifactsDir.isDirectory()) {
boolean success = artifactsDir.mkdirs();
if (!success) {
listener.getLogger().println("Can't create artifacts directory at "
+ artifactsDir.getAbsolutePath());
}
}
String path = artifactsDir.getCanonicalPath() + REPORT_TEMPLATE_PATH;
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path),
StandardCharsets.UTF_8))) {
writer.write(report);
}
return super.tearDown(build, listener);
}
};
}
private static ProjectStats buildStats(FilePath root) throws IOException, InterruptedException {
int classesNumber = 0;
int linesNumber = 0;
Stack<FilePath> toProcess = new Stack<>();
toProcess.push(root);
while (!toProcess.isEmpty()) {
FilePath path = toProcess.pop();
if (path.isDirectory()) {
toProcess.addAll(path.list());
} else if (path.getName().endsWith(".java")) {
classesNumber++;
linesNumber += countLines(path);
}
}
return new ProjectStats(classesNumber, linesNumber);
}
private static int countLines(FilePath path) throws IOException, InterruptedException {
byte[] buffer = new byte[1024];
int result = 1;
try (InputStream in = path.read()) {
while (true) {
int read = in.read(buffer);
if (read < 0) {
return result;
}
for (int i = 0; i < read; i++) {
if (buffer[i] == '\n') {
result++;
}
}
}
}
}
private static String generateReport(String projectName, ProjectStats stats) throws IOException {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
try (InputStream in = ProjectStatsBuildWrapper.class.getResourceAsStream(REPORT_TEMPLATE_PATH)) {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) >= 0) {
bOut.write(buffer, 0, read);
}
}
String content = new String(bOut.toByteArray(), StandardCharsets.UTF_8);
content = content.replace(PROJECT_NAME_VAR, projectName);
content = content.replace(CLASSES_NUMBER_VAR, String.valueOf(stats.getClassesNumber()));
content = content.replace(LINES_NUMBER_VAR, String.valueOf(stats.getLinesNumber()));
return content;
}
@Extension
public static final class DescriptorImpl extends BuildWrapperDescriptor {
@Override
public boolean isApplicable(AbstractProject<?, ?> item) {
return true;
}
@Nonnull
@Override
public String getDisplayName() {
return "Construct project stats during build";
}
}
}

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$PROJECT_NAME$</title>
</head>
<body>
Project $PROJECT_NAME$:
<table border="1">
<tr>
<th>Classes number</th>
<th>Lines number</th>
</tr>
<tr>
<td>$CLASSES_NUMBER$</td>
<td>$LINES_NUMBER$</td>
</tr>
</table>
</body>
</html>

View File

@ -39,3 +39,8 @@ $ curl -X POST -H "Content-Type:application/json" -d '{ "firstName" : "Dassi", "
Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080)
Enjoy it :)
### Relevant Articles:
- [Intro to Performance Testing using JMeter](http://www.baeldung.com/jmeter)
- [Configure Jenkins to Run and Show JMeter Tests](http://www.baeldung.com/jenkins-and-jmeter)

View File

@ -2,3 +2,4 @@
- [Introduction to Reladomo](http://www.baeldung.com/reladomo)
- [Introduction to ORMLite](http://www.baeldung.com/ormlite)
- [Introduction To Kryo](http://www.baeldung.com/kryo)
- [Introduction to KafkaStreams in Java](http://www.baeldung.com/java-kafka-streams)

View File

@ -58,6 +58,8 @@
- [Introduction to BouncyCastle with Java](http://www.baeldung.com/java-bouncy-castle)
- [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)
The libraries module contains examples related to small libraries that are relatively easy to use and does not require any separate module of its own.

View File

@ -194,6 +194,11 @@
<artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
@ -741,12 +746,11 @@
<assertj.version>3.6.2</assertj.version>
<jsonassert.version>1.5.0</jsonassert.version>
<javers.version>3.1.0</javers.version>
<jetty.version>9.4.3.v20170317</jetty.version>
<httpclient.version>4.5.3</httpclient.version>
<commons.io.version>2.5</commons.io.version>
<commons.dbutils.version>1.6</commons.dbutils.version>
<h2.version>1.4.196</h2.version>
<jetty.version>9.4.2.v20170220</jetty.version>
<jetty.version>9.4.8.v20171121</jetty.version>
<httpclient.version>4.5.3</httpclient.version>
<commons.io.version>2.5</commons.io.version>
<flink.version>1.2.0</flink.version>

View File

@ -0,0 +1,94 @@
package com.baeldung.jetty;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* Simple factory for creating Jetty basic instances.
*
* @author Donato Rimenti
*
*/
public class JettyServerFactory {
/**
* Exposed context of the app.
*/
public final static String APP_PATH = "/myApp";
/**
* The server port.
*/
public final static int SERVER_PORT = 13133;
/**
* Private constructor to avoid instantiation.
*/
private JettyServerFactory() {
}
/**
* Returns a simple server listening on port 80 with a timeout of 30 seconds
* for connections and no handlers.
*
* @return a server
*/
public static Server createBaseServer() {
Server server = new Server();
// Adds a connector for port 80 with a timeout of 30 seconds.
ServerConnector connector = new ServerConnector(server);
connector.setPort(SERVER_PORT);
connector.setHost("127.0.0.1");
connector.setIdleTimeout(30000);
server.addConnector(connector);
return server;
}
/**
* Creates a server which delegates the request handling to a web
* application.
*
* @return a server
*/
public static Server createWebAppServer() {
// Adds an handler to a server and returns it.
Server server = createBaseServer();
String webAppFolderPath = JettyServerFactory.class.getClassLoader().getResource("jetty-embedded-demo-app.war")
.getPath();
Handler webAppHandler = new WebAppContext(webAppFolderPath, APP_PATH);
server.setHandler(webAppHandler);
return server;
}
/**
* Creates a server which delegates the request handling to both a logging
* handler and to a web application, in this order.
*
* @return a server
*/
public static Server createMultiHandlerServer() {
Server server = createBaseServer();
// Creates the handlers and adds them to the server.
HandlerCollection handlers = new HandlerCollection();
String webAppFolderPath = JettyServerFactory.class.getClassLoader().getResource("jetty-embedded-demo-app.war")
.getPath();
Handler customRequestHandler = new WebAppContext(webAppFolderPath, APP_PATH);
handlers.addHandler(customRequestHandler);
Handler loggingRequestHandler = new LoggingRequestHandler();
handlers.addHandler(loggingRequestHandler);
server.setHandler(handlers);
return server;
}
}

View File

@ -0,0 +1,168 @@
package com.baeldung.jetty;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Handler implementation which simply logs that a request has been received.
*
* @author Donato Rimenti
*/
public class LoggingRequestHandler implements Handler {
/**
* Logger.
*/
private final static Logger LOG = LoggerFactory.getLogger(LoggingRequestHandler.class);
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#addLifeCycleListener(org.
* eclipse.jetty.util.component.LifeCycle.Listener)
*/
@Override
public void addLifeCycleListener(Listener arg0) {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#isFailed()
*/
@Override
public boolean isFailed() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#isRunning()
*/
@Override
public boolean isRunning() {
return true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#isStarted()
*/
@Override
public boolean isStarted() {
return true;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#isStarting()
*/
@Override
public boolean isStarting() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#isStopped()
*/
@Override
public boolean isStopped() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#isStopping()
*/
@Override
public boolean isStopping() {
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jetty.util.component.LifeCycle#removeLifeCycleListener(org.
* eclipse.jetty.util.component.LifeCycle.Listener)
*/
@Override
public void removeLifeCycleListener(Listener arg0) {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#start()
*/
@Override
public void start() throws Exception {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.util.component.LifeCycle#stop()
*/
@Override
public void stop() throws Exception {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.server.Handler#destroy()
*/
@Override
public void destroy() {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.server.Handler#getServer()
*/
@Override
public Server getServer() {
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.server.Handler#handle(java.lang.String,
* org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
@Override
public void handle(String arg0, Request arg1, HttpServletRequest arg2, HttpServletResponse arg3)
throws IOException, ServletException {
LOG.info("Received a new request");
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jetty.server.Handler#setServer(org.eclipse.jetty.server.
* Server)
*/
@Override
public void setServer(Server server) {
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.netty;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.logging.Logger;
public class ChannelHandlerA extends ChannelInboundHandlerAdapter {
private Logger logger = Logger.getLogger(getClass().getName());
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
throw new Exception("Ooops");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.info("Exception Occurred in ChannelHandler A");
ctx.fireExceptionCaught(cause);
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.netty;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.logging.Logger;
public class ChannelHandlerB extends ChannelInboundHandlerAdapter {
private Logger logger = Logger.getLogger(getClass().getName());
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.info("Exception Handled in ChannelHandler B");
logger.info(cause.getLocalizedMessage());
//do more exception handling
ctx.close();
}
}

View File

@ -0,0 +1,47 @@
package com.baeldung.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class NettyServerB {
private int port;
private NettyServerB(int port) {
this.port = port;
}
private void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ChannelHandlerA(), new ChannelHandlerB());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(port).sync(); // (7)
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new NettyServerB(8080).run();
}
}

View File

@ -0,0 +1,86 @@
package com.baeldung.jetty;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.eclipse.jetty.server.Server;
import org.junit.Assert;
import org.junit.Test;
/**
* Test for {@link JettyServerFactory}.
*
* @author Donato Rimenti
*
*/
public class JettyServerFactoryUnitTest {
/**
* Tests that when a base server is provided a request returns a status 404.
*
* @throws Exception
*/
@Test
public void givenBaseServer_whenHttpRequest_thenStatus404() throws Exception {
Server server = JettyServerFactory.createBaseServer();
server.start();
int statusCode = sendGetRequest();
Assert.assertEquals(404, statusCode);
server.stop();
}
/**
* Tests that when a web app server is provided a request returns a status
* 200.
*
* @throws Exception
*/
@Test
public void givenWebAppServer_whenHttpRequest_thenStatus200() throws Exception {
Server server = JettyServerFactory.createWebAppServer();
server.start();
int statusCode = sendGetRequest();
Assert.assertEquals(200, statusCode);
server.stop();
}
/**
* Tests that when a multi handler server is provided a request returns a
* status 200.
*
* @throws Exception
*/
@Test
public void givenMultiHandlerServerServer_whenHttpRequest_thenStatus200() throws Exception {
Server server = JettyServerFactory.createMultiHandlerServer();
server.start();
int statusCode = sendGetRequest();
Assert.assertEquals(200, statusCode);
server.stop();
}
/**
* Sends a default HTTP GET request to the server and returns the response
* status code.
*
* @return the status code of the response
* @throws Exception
*/
private int sendGetRequest() throws Exception {
HttpHost target = new HttpHost("localhost", JettyServerFactory.SERVER_PORT);
HttpRequest request = new HttpGet(JettyServerFactory.APP_PATH);
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(target, request);
return response.getStatusLine().getStatusCode();
}
}

View File

@ -34,7 +34,7 @@ public class PactConsumerDrivenContractUnitTest {
return builder
.given("test GET")
.uponReceiving("GET REQUEST")
.path("/")
.path("/pact")
.method("GET")
.willRespondWith()
.status(200)
@ -45,11 +45,9 @@ public class PactConsumerDrivenContractUnitTest {
.method("POST")
.headers(headers)
.body("{\"name\": \"Michael\"}")
.path("/create")
.path("/pact")
.willRespondWith()
.status(201)
.headers(headers)
.body("")
.toPact();
}
@ -59,7 +57,7 @@ public class PactConsumerDrivenContractUnitTest {
public void givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody() {
//when
ResponseEntity<String> response
= new RestTemplate().getForEntity(mockProvider.getUrl(), String.class);
= new RestTemplate().getForEntity(mockProvider.getUrl() + "/pact", String.class);
//then
assertThat(response.getStatusCode().value()).isEqualTo(200);
@ -73,7 +71,7 @@ public class PactConsumerDrivenContractUnitTest {
//when
ResponseEntity<String> postResponse = new RestTemplate().exchange(
mockProvider.getUrl() + "/create",
mockProvider.getUrl() + "/pact",
HttpMethod.POST,
new HttpEntity<>(jsonBody, httpHeaders),
String.class

View File

@ -1,3 +1,6 @@
## Logging Modules
### Relevant Articles:
- [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender)

View File

@ -59,10 +59,10 @@
<properties>
<jackson.version>2.8.5</jackson.version>
<jackson.version>2.9.3</jackson.version>
<h2.version>1.4.193</h2.version>
<commons-dbcp2.version>2.1.1</commons-dbcp2.version>
<log4j-core.version>2.7</log4j-core.version>
<log4j-core.version>2.10.0</log4j-core.version>
</properties>
</project>

View File

@ -0,0 +1,45 @@
package com.baeldung.logging.log4j2.tests;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JSONLayoutTest {
private static Logger logger;
private ByteArrayOutputStream consoleOutput = new ByteArrayOutputStream();
private PrintStream ps = new PrintStream(consoleOutput);
@Before
public void setUp() {
// Redirect console output to our stream
System.setOut(ps);
logger = LogManager.getLogger("CONSOLE_JSON_APPENDER");
}
@Test
public void whenLogLayoutInJSON_thenOutputIsCorrectJSON() {
logger.debug("Debug message");
String currentLog = consoleOutput.toString();
assertTrue(!currentLog.isEmpty() && isValidJSON(currentLog));
}
public static boolean isValidJSON(String jsonInString) {
try {
final ObjectMapper mapper = new ObjectMapper();
mapper.readTree(jsonInString);
return true;
} catch (IOException e) {
return false;
}
}
}

View File

@ -1,16 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns:xi="http://www.w3.org/2001/XInclude" status="WARN">
<Configuration xmlns:xi="http://www.w3.org/2001/XInclude"
status="WARN">
<Appenders>
<xi:include href="log4j2-includes/console-appender_pattern-layout_colored.xml" />
<xi:include
href="log4j2-includes/console-appender_pattern-layout_colored.xml" />
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d [%t] %-5level %logger{36} - %msg%n%throwable" />
<PatternLayout
pattern="%d [%t] %-5level %logger{36} - %msg%n%throwable" />
</Console>
<Console name="ConsoleRedAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%style{%message}{red}%n" />
<MarkerFilter marker="CONN_TRACE" />
</Console>
<Console name="ConsoleGreenAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%style{userId=%X{userId}:}{white} %style{%message}{green}%n" />
<PatternLayout
pattern="%style{userId=%X{userId}:}{white} %style{%message}{green}%n" />
</Console>
<Console name="ConsoleJSONAppender" target="SYSTEM_OUT">
<JsonLayout complete="false" compact="false">
<KeyValuePair key="myCustomField" value="myCustomValue" />
</JsonLayout>
</Console>
<File name="JSONLogfileAppender" fileName="target/logfile.json">
<JSONLayout compact="true" eventEol="true" />
@ -19,53 +28,58 @@
<Async name="AsyncAppender" bufferSize="80">
<AppenderRef ref="JSONLogfileAppender" />
</Async>
<!--
<Syslog name="Syslog" format="RFC5424" host="localhost" port="514" protocol="TCP" facility="local3" connectTimeoutMillis="10000" reconnectionDelayMillis="5000" mdcId="mdc" includeMDC="true" />
<Failover name="FailoverAppender" primary="Syslog">
<Failovers>
<AppenderRef ref="ConsoleAppender" />
</Failovers>
</Failover>
-->
<!-- <Syslog name="Syslog" format="RFC5424" host="localhost" port="514"
protocol="TCP" facility="local3" connectTimeoutMillis="10000" reconnectionDelayMillis="5000"
mdcId="mdc" includeMDC="true" /> <Failover name="FailoverAppender" primary="Syslog">
<Failovers> <AppenderRef ref="ConsoleAppender" /> </Failovers> </Failover> -->
<JDBC name="JDBCAppender" tableName="logs">
<ConnectionFactory class="com.baeldung.logging.log4j2.tests.jdbc.ConnectionFactory" method="getConnection" />
<ConnectionFactory
class="com.baeldung.logging.log4j2.tests.jdbc.ConnectionFactory"
method="getConnection" />
<Column name="when" isEventTimestamp="true" />
<Column name="logger" pattern="%logger" />
<Column name="level" pattern="%level" />
<Column name="message" pattern="%message" />
<Column name="throwable" pattern="%ex{full}" />
</JDBC>
<RollingFile name="XMLRollingfileAppender" fileName="target/logfile.xml" filePattern="target/logfile-%d{yyyy-MM-dd}-%i.log.gz">
<RollingFile name="XMLRollingfileAppender" fileName="target/logfile.xml"
filePattern="target/logfile-%d{yyyy-MM-dd}-%i.log.gz">
<XMLLayout />
<Policies>
<SizeBasedTriggeringPolicy size="17 kB" />
<SizeBasedTriggeringPolicy
size="17 kB" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="CONSOLE_PATTERN_APPENDER_MARKER" level="TRACE" additivity="false">
<Logger name="CONSOLE_PATTERN_APPENDER_MARKER" level="TRACE"
additivity="false">
<AppenderRef ref="ConsoleRedAppender" />
</Logger>
<Logger name="CONSOLE_PATTERN_APPENDER_THREAD_CONTEXT" level="INFO" additivity="false">
<Logger name="CONSOLE_PATTERN_APPENDER_THREAD_CONTEXT"
level="INFO" additivity="false">
<AppenderRef ref="ConsoleGreenAppender" />
<ThreadContextMapFilter>
<KeyValuePair key="userId" value="1000" />
</ThreadContextMapFilter>
</Logger>
<Logger name="ASYNC_JSON_FILE_APPENDER" level="INFO" additivity="false">
<Logger name="ASYNC_JSON_FILE_APPENDER" level="INFO"
additivity="false">
<AppenderRef ref="AsyncAppender" />
</Logger>
<!--
<Logger name="FAIL_OVER_SYSLOG_APPENDER" level="INFO" additivity="false">
<AppenderRef ref="FailoverAppender" />
</Logger>
-->
<!-- <Logger name="FAIL_OVER_SYSLOG_APPENDER" level="INFO" additivity="false">
<AppenderRef ref="FailoverAppender" /> </Logger> -->
<Logger name="JDBC_APPENDER" level="INFO" additivity="false">
<AppenderRef ref="JDBCAppender" />
</Logger>
<Logger name="XML_ROLLING_FILE_APPENDER" level="INFO" additivity="false">
<Logger name="XML_ROLLING_FILE_APPENDER" level="INFO"
additivity="false">
<AppenderRef ref="XMLRollingfileAppender" />
</Logger>
<Logger name="CONSOLE_JSON_APPENDER" level="TRACE"
additivity="false">
<AppenderRef ref="ConsoleJSONAppender" />
</Logger>
<Root level="DEBUG">
<AppenderRef ref="ConsoleAppender" />
</Root>

View File

@ -12,6 +12,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<logback.version>1.2.3</logback.version>
<logback.contrib.version>0.1.5</logback.contrib.version>
<jackson.version>2.9.3</jackson.version>
</properties>
<parent>
@ -28,7 +30,21 @@
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback.contrib</groupId>
<artifactId>logback-json-classic</artifactId>
<version>${logback.contrib.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback.contrib</groupId>
<artifactId>logback-jackson</artifactId>
<version>${logback.contrib.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>

View File

@ -0,0 +1,45 @@
package com.baeldung.logback;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JSONLayoutTest {
private static Logger logger;
private ByteArrayOutputStream consoleOutput = new ByteArrayOutputStream();
private PrintStream ps = new PrintStream(consoleOutput);
@Before
public void setUp() {
// Redirect console output to our stream
System.setOut(ps);
logger = LoggerFactory.getLogger("jsonLogger");
}
@Test
public void whenLogLayoutInJSON_thenOutputIsCorrectJSON() {
logger.debug("Debug message");
String currentLog = consoleOutput.toString();
assertTrue(!currentLog.isEmpty() && isValidJSON(currentLog));
}
public static boolean isValidJSON(String jsonInString) {
try {
final ObjectMapper mapper = new ObjectMapper();
mapper.readTree(jsonInString);
return true;
} catch (IOException e) {
return false;
}
}
}

View File

@ -1,4 +1,6 @@
<configuration debug="true">
<configuration debug="false">
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
<appender name="map" class="com.baeldung.logback.MapAppender">
<prefix>test</prefix>
@ -6,6 +8,21 @@
<appender name="badMap" class="com.baeldung.logback.MapAppender" />
# JSON appender
<appender name="json" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
<jsonFormatter
class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
<prettyPrint>true</prettyPrint>
</jsonFormatter>
<timestampFormat>yyyy-MM-dd' 'HH:mm:ss.SSS</timestampFormat>
</layout>
</appender>
<logger name="jsonLogger" level="TRACE">
<appender-ref ref="json" />
</logger>
<root level="debug">
<appender-ref ref="map" />
<appender-ref ref="badMap" />

4
lucene/README.md Normal file
View File

@ -0,0 +1,4 @@
### Relevant Articles:
- [Introduction to Apache Lucene](http://www.baeldung.com/lucene)
- [A Simple File Search with Lucene](http://www.baeldung.com/lucene-file-search)

3
muleesb/README.md Normal file
View File

@ -0,0 +1,3 @@
### Relevant Articles:
- [Getting Started With Mule ESB](http://www.baeldung.com/mule-esb)

View File

@ -23,3 +23,6 @@ Before launching unit tests:
- Install OrientDB
- Create BaeldungDB, BaeldungDBTwo and BaeldungDBThree databases
- Uncomment annotations on the test files
### Relevant Articles:
- [Introduction to the OrientDB Java APIs](http://www.baeldung.com/java-orientdb)

View File

@ -1,3 +1,7 @@
## Persistence Modules
### Relevant Articles:
- [Introduction to Hibernate Search](http://www.baeldung.com/hibernate-search)

View File

@ -1,3 +1,5 @@
### Relevant Articles:
- [Intro to Jedis the Java Redis Client Library](http://www.baeldung.com/jedis-java-redis-client-library)
- [A Guide to Redis with Redisson](http://www.baeldung.com/redis-redisson)
- [Intro to Lettuce the Java Redis Client Library](http://www.baeldung.com/lettuce-java-redis-client-library)

View File

@ -36,6 +36,13 @@
<artifactId>redisson</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
</dependencies>
<properties>

View File

@ -0,0 +1,312 @@
package com.baeldung;
import io.lettuce.core.LettuceFutures;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisFuture;
import io.lettuce.core.TransactionResult;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.pubsub.RedisPubSubListener;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.async.RedisPubSubAsyncCommands;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertTrue;
public class LettuceIntegrationLiveTest {
private static Logger log = LoggerFactory.getLogger(LettuceIntegrationLiveTest.class);
private static StatefulRedisConnection<String, String> redisConnection;
private static RedisClient redisClient;
@BeforeClass
public static void setUp() {
// Docker defaults to mapping redis port to 32768
redisClient = RedisClient.create("redis://localhost:32768/");
redisConnection = redisClient.connect();
}
@AfterClass
public static void destroy() {
redisConnection.close();
}
@Test
public void givenAString_thenSaveItAsRedisStringsSync() {
RedisCommands<String, String> syncCommands = redisConnection.sync();
String key = "key";
String value = "value";
syncCommands.set(key, value);
String response = syncCommands.get(key);
Assert.assertEquals(value, response);
}
@Test
public void givenValues_thenSaveAsRedisHashSync() {
RedisCommands<String, String> syncCommands = redisConnection.sync();
String recordName = "record1";
String name = "FirstName";
String value = "John";
String surname = "LastName";
String value1 = "Smith";
syncCommands.hset(recordName, name, value);
syncCommands.hset(recordName, surname, value1);
Map<String, String> record = syncCommands.hgetall(recordName);
Assert.assertEquals(record.get(name), value);
Assert.assertEquals(record.get(surname), value1);
}
@Test
public void givenAString_thenSaveItAsRedisStringsAsync() throws Exception {
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
String key = "key";
String value = "value";
asyncCommands.set(key, value);
RedisFuture<String> redisFuture = asyncCommands.get(key);
String response = redisFuture.get();
Assert.assertEquals(value, response);
}
@Test
public void givenValues_thenSaveAsRedisHashAsync() throws Exception {
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
String recordName = "record1";
String name = "FirstName";
String value = "John";
String surname = "LastName";
String value1 = "Smith";
asyncCommands.hset(recordName, name, value);
asyncCommands.hset(recordName, surname, value1);
RedisFuture<Map<String, String>> redisFuture = asyncCommands.hgetall(recordName);
Map<String, String> record = redisFuture.get();
Assert.assertEquals(record.get(name), value);
Assert.assertEquals(record.get(surname), value1);
}
@Test
public void givenValues_thenSaveAsRedisListAsync() throws Exception {
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
String listName = "tasks";
String firstTask = "firstTask";
String secondTask = "secondTask";
asyncCommands.del(listName);
asyncCommands.lpush(listName, firstTask);
asyncCommands.lpush(listName, secondTask);
RedisFuture<String> redisFuture = asyncCommands.rpop(listName);
String nextTask = redisFuture.get();
Assert.assertEquals(firstTask, nextTask);
asyncCommands.del(listName);
asyncCommands.lpush(listName, firstTask);
asyncCommands.lpush(listName, secondTask);
redisFuture = asyncCommands.lpop(listName);
nextTask = redisFuture.get();
Assert.assertEquals(secondTask, nextTask);
}
@Test
public void givenSetElements_thenSaveThemInRedisSetAsync() throws Exception {
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
String countries = "countries";
String countryOne = "Spain";
String countryTwo = "Ireland";
String countryThree = "Ireland";
asyncCommands.sadd(countries, countryOne);
RedisFuture<Set<String>> countriesSetFuture = asyncCommands.smembers(countries);
Assert.assertEquals(2, countriesSetFuture.get().size());
asyncCommands.sadd(countries, countryTwo);
countriesSetFuture = asyncCommands.smembers(countries);
Assert.assertEquals(2, countriesSetFuture.get().size());
asyncCommands.sadd(countries, countryThree);
countriesSetFuture = asyncCommands.smembers(countries);
Assert.assertEquals(2, countriesSetFuture.get().size());
RedisFuture<Boolean> exists = asyncCommands.sismember(countries, countryThree);
assertTrue(exists.get());
}
@Test
public void givenARanking_thenSaveItInRedisSortedSetAsync() throws Exception {
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
String key = "sortedset";
asyncCommands.zadd(key, 1, "one");
asyncCommands.zadd(key, 4, "zero");
asyncCommands.zadd(key, 2, "two");
RedisFuture<List<String>> values = asyncCommands.zrevrange(key, 0, 3);
Assert.assertEquals("zero", values.get().get(0));
values = asyncCommands.zrange(key, 0, 3);
Assert.assertEquals("one", values.get().get(0));
}
@Test
public void givenMultipleOperationsThatNeedToBeExecutedAtomically_thenWrapThemInATransaction() throws Exception {
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
// Start a transaction
asyncCommands.multi();
// Add three sets to it, and save the future responses
RedisFuture<String> result1 = asyncCommands.set("key1", "value1");
RedisFuture<String> result2 = asyncCommands.set("key2", "value2");
RedisFuture<String> result3 = asyncCommands.set("key3", "value3");
// Execute it
RedisFuture<TransactionResult> execResult = asyncCommands.exec();
TransactionResult transactionResult = execResult.get();
// Get the three results in the transaction return
String firstResult = transactionResult.get(0);
String secondResult = transactionResult.get(0);
String thirdResult = transactionResult.get(0);
// Our results are in both!
assertTrue(firstResult.equals("OK"));
assertTrue(secondResult.equals("OK"));
assertTrue(thirdResult.equals("OK"));
assertTrue(result1.get().equals("OK"));
assertTrue(result2.get().equals("OK"));
assertTrue(result3.get().equals("OK"));
}
@Test
public void givenMultipleIndependentOperations_whenNetworkOptimizationIsImportant_thenFlushManually() throws Exception {
int iterations = 50;
RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
asyncCommands.setAutoFlushCommands(false);
List<RedisFuture<?>> futures = new ArrayList<>();
for (int i = 0; i < iterations; i++) {
futures.add(asyncCommands.set("key" + i, "value" + i));
}
asyncCommands.flushCommands();
// Wait until all futures complete
boolean result = LettuceFutures.awaitAll(5, TimeUnit.SECONDS, futures.toArray(new RedisFuture[futures.size()]));
asyncCommands.setAutoFlushCommands(true);
}
@Test
public void givenPubSubChannel_whenMessage_thenMessageReceived() throws Exception {
Listener listener = new Listener();
StatefulRedisPubSubConnection<String, String> connection = redisClient.connectPubSub();
StatefulRedisPubSubConnection<String, String> pubconnection = redisClient.connectPubSub();
connection.addListener(listener);
RedisPubSubAsyncCommands<String, String> async = connection.async();
async.subscribe("channel");
RedisPubSubAsyncCommands<String, String> pubasync = pubconnection.async();
RedisFuture<Long> result = pubasync.publish("channel", "hithere");
// Need a long wait for publish to complete, depending on system.
result.get(15, TimeUnit.SECONDS);
assertTrue(listener.getMessage().equals("hithere"));
}
private static class Listener implements RedisPubSubListener<String, String> {
private String message;
String getMessage() {
return message;
}
@Override
public void message(String channel, String message) {
log.debug("Got {} on {}", message, channel);
this.message = message;
}
@Override
public void message(String pattern, String channel, String message) {
}
@Override
public void subscribed(String channel, long count) {
log.debug("Subscribed to {}", channel);
}
@Override
public void psubscribed(String pattern, long count) {
}
@Override
public void unsubscribed(String channel, long count) {
}
@Override
public void punsubscribed(String pattern, long count) {
}
}
}

View File

@ -88,6 +88,7 @@
<!-- <module>persistence-modules/java-cassandra</module> -->
<module>vavr</module>
<module>java-lite</module>
<module>java-rmi</module>
<module>java-vavr-stream</module>
<module>javax-servlets</module>
<module>javaxval</module>
@ -113,7 +114,9 @@
<module>lombok</module>
<!-- <module>kotlin</module>-->
<module>mapstruct</module>
<!--
<module>metrics</module>
-->
<module>mesos-marathon</module>
<module>testing-modules/mockito</module>
<module>testing-modules/mockito-2</module>

View File

@ -43,6 +43,10 @@
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Dependencies for Yasson -->
<!-- <dependency> -->
@ -56,6 +60,12 @@
<!-- <version>1.1.2</version> -->
<!-- </dependency> -->
<!-- Dependencies for Johnzon -->
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
@ -198,4 +208,5 @@
<geronimo-json_1.1_spec.version>1.0</geronimo-json_1.1_spec.version>
</properties>
</project>

View File

@ -1,4 +1,4 @@
package com.baeldung.actuator;
package com.baeldung.reactive.actuator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;

View File

@ -1,4 +1,4 @@
package com.baeldung.actuator;
package com.baeldung.reactive.actuator;
import org.springframework.boot.actuate.endpoint.annotation.*;
import org.springframework.stereotype.Component;

View File

@ -1,4 +1,4 @@
package com.baeldung.actuator;
package com.baeldung.reactive.actuator;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;

View File

@ -0,0 +1,11 @@
package com.baeldung.reactive.websocket;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Event {
private String eventId;
private String eventDt;
}

View File

@ -0,0 +1,26 @@
package com.baeldung.reactive.websocket;
import java.net.URI;
import java.time.Duration;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import reactor.core.publisher.Mono;
public class ReactiveJavaClientWebSocket {
public static void main(String[] args) throws InterruptedException {
WebSocketClient client = new ReactorNettyWebSocketClient();
client.execute(
URI.create("ws://localhost:8080/event-emitter"),
session -> session.send(
Mono.just(session.textMessage("event-spring-reactive-client-websocket")))
.thenMany(session.receive()
.map(WebSocketMessage::getPayloadAsText)
.log())
.then())
.block(Duration.ofSeconds(10L));
}
}

View File

@ -0,0 +1,11 @@
package com.baeldung.reactive.websocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ReactiveWebSocketApplication {
public static void main(String[] args) {
SpringApplication.run(ReactiveWebSocketApplication.class, args);
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.reactive.websocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ReactiveWebSocketConfiguration {
@Autowired
private WebSocketHandler webSocketHandler;
@Bean
public HandlerMapping webSocketHandlerMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/event-emitter", webSocketHandler);
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(1);
handlerMapping.setUrlMap(map);
return handlerMapping;
}
@Bean
public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter();
}
}

View File

@ -0,0 +1,48 @@
package com.baeldung.reactive.websocket;
import org.springframework.web.reactive.socket.WebSocketSession;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.UUID;
@Component
public class ReactiveWebSocketHandler implements WebSocketHandler {
private Flux<Event> eventFlux = Flux.generate(e -> {
Event event = new Event(UUID.randomUUID().toString(), LocalDateTime.now().toString());
e.next(event);
});
private Flux<Event> intervalFlux = Flux.interval(Duration.ofMillis(1000L)).zipWith(eventFlux, (time, event) -> event);
private ObjectMapper json = new ObjectMapper();
@Override
public Mono<Void> handle(WebSocketSession webSocketSession) {
return webSocketSession.send(intervalFlux.map(event -> {
try {
String jsonEvent = json.writeValueAsString(event);
System.out.println(jsonEvent);
return jsonEvent;
} catch (JsonProcessingException e) {
e.printStackTrace();
return "";
}
}).map(webSocketSession::textMessage))
.and(webSocketSession.receive().map(WebSocketMessage::getPayloadAsText).log());
}
}

View File

@ -1 +1,4 @@
logging.level.root=INFO
management.endpoints.web.expose=*
info.app.name=Spring Boot 2 actuator Application

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Baeldung: Spring 5 Reactive Client WebSocket (Browser)</title>
</head>
<body>
<div class="events"></div>
<script>
var clientWebSocket = new WebSocket("ws://localhost:8080/event-emitter");
clientWebSocket.onopen = function() {
console.log("clientWebSocket.onopen", clientWebSocket);
console.log("clientWebSocket.readyState", "websocketstatus");
clientWebSocket.send("event-me-from-browser");
}
clientWebSocket.onclose = function(error) {
console.log("clientWebSocket.onclose", clientWebSocket, error);
events("Closing connection");
}
clientWebSocket.onerror = function(error) {
console.log("clientWebSocket.onerror", clientWebSocket, error);
events("An error occured");
}
clientWebSocket.onmessage = function(error) {
console.log("clientWebSocket.onmessage", clientWebSocket, error);
events(error.data);
}
function events(responseEvent) {
document.querySelector(".events").innerHTML += responseEvent + "<br>";
}
</script>
</body>
</html>

View File

@ -1,6 +1,5 @@
package com.baeldung.actuator;
package com.baeldung.reactive.actuator;
import com.baeldung.jsonb.Spring5Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -10,12 +9,14 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.reactive.Spring5ReactiveApplication;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5Application.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Spring5ReactiveApplication.class)
public class ActuatorInfoIntegrationTest {
@Autowired

View File

@ -0,0 +1,3 @@
## Relevant articles:
- [Spring Security 5 -OAuth2 Login](http://www.baeldung.com/spring-security-5-oauth2-login)

View File

@ -30,6 +30,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
<!-- oauth2 -->
<dependency>
@ -40,6 +44,21 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,50 @@
package com.baeldung.loginextrafieldscustom;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain";
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: "
+ request.getMethod());
}
CustomAuthenticationToken authRequest = getAuthRequest(request);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
private CustomAuthenticationToken getAuthRequest(HttpServletRequest request) {
String username = obtainUsername(request);
String password = obtainPassword(request);
String domain = obtainDomain(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
if (domain == null) {
domain = "";
}
return new CustomAuthenticationToken(username, password, domain);
}
private String obtainDomain(HttpServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY);
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.loginextrafieldscustom;
import java.util.Collection;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken {
private String domain;
public CustomAuthenticationToken(Object principal, Object credentials, String domain) {
super(principal, credentials);
this.domain = domain;
super.setAuthenticated(false);
}
public CustomAuthenticationToken(Object principal, Object credentials, String domain,
Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
this.domain = domain;
super.setAuthenticated(true); // must use super, as we override
}
public String getDomain() {
return this.domain;
}
}

View File

@ -0,0 +1,92 @@
package com.baeldung.loginextrafieldscustom;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;
public class CustomUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
/**
* The plaintext password used to perform
* PasswordEncoder#matches(CharSequence, String)} on when the user is
* not found to avoid SEC-2056.
*/
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
private PasswordEncoder passwordEncoder;
private CustomUserDetailsService userDetailsService;
/**
* The password used to perform
* {@link PasswordEncoder#matches(CharSequence, String)} on when the user is
* not found to avoid SEC-2056. This is necessary, because some
* {@link PasswordEncoder} implementations will short circuit if the password is not
* in a valid format.
*/
private String userNotFoundEncodedPassword;
public CustomUserDetailsAuthenticationProvider(PasswordEncoder passwordEncoder, CustomUserDetailsService userDetailsService) {
this.passwordEncoder = passwordEncoder;
this.userDetailsService = userDetailsService;
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(
messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
String presentedPassword = authentication.getCredentials()
.toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(
messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
@Override
protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
CustomAuthenticationToken auth = (CustomAuthenticationToken) authentication;
UserDetails loadedUser;
try {
loadedUser = this.userDetailsService.loadUserByUsernameAndDomain(auth.getPrincipal()
.toString(), auth.getDomain());
} catch (UsernameNotFoundException notFound) {
if (authentication.getCredentials() != null) {
String presentedPassword = authentication.getCredentials()
.toString();
passwordEncoder.matches(presentedPassword, userNotFoundEncodedPassword);
}
throw notFound;
} catch (Exception repositoryProblem) {
throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}
if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null, "
+ "which is an interface contract violation");
}
return loadedUser;
}
}

View File

@ -0,0 +1,10 @@
package com.baeldung.loginextrafieldscustom;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public interface CustomUserDetailsService {
UserDetails loadUserByUsernameAndDomain(String username, String domain) throws UsernameNotFoundException;
}

Some files were not shown because too many files have changed in this diff Show More