merge
This commit is contained in:
commit
d2b90c6d4a
|
@ -9,9 +9,9 @@
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>parent-modules</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
<version>1.5.2.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -21,6 +21,19 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.shiro</groupId>
|
||||||
|
<artifactId>shiro-spring-boot-web-starter</artifactId>
|
||||||
|
<version>${apache-shiro-core-version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.shiro</groupId>
|
<groupId>org.apache.shiro</groupId>
|
||||||
<artifactId>shiro-core</artifactId>
|
<artifactId>shiro-core</artifactId>
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.baeldung;
|
||||||
|
|
||||||
|
import org.apache.shiro.realm.Realm;
|
||||||
|
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
|
||||||
|
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by smatt on 21/08/2017.
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ShiroSpringApplication {
|
||||||
|
|
||||||
|
private static final transient Logger log = LoggerFactory.getLogger(ShiroSpringApplication.class);
|
||||||
|
|
||||||
|
public static void main(String... args) {
|
||||||
|
SpringApplication.run(ShiroSpringApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Realm realm() {
|
||||||
|
return new MyCustomRealm();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
|
||||||
|
DefaultShiroFilterChainDefinition filter
|
||||||
|
= new DefaultShiroFilterChainDefinition();
|
||||||
|
|
||||||
|
filter.addPathDefinition("/secure", "authc");
|
||||||
|
filter.addPathDefinition("/**", "anon");
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package com.baeldung.controllers;
|
||||||
|
|
||||||
|
import com.baeldung.models.UserCredentials;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
|
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||||
|
import org.apache.shiro.subject.Subject;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.ModelMap;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class ShiroSpringController {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
public String index() {
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@RequestMapping( value = "/login", method = {RequestMethod.GET, RequestMethod.POST})
|
||||||
|
public String login(HttpServletRequest req, UserCredentials cred, RedirectAttributes attr) {
|
||||||
|
|
||||||
|
if(req.getMethod().equals(RequestMethod.GET.toString())) {
|
||||||
|
return "login";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
Subject subject = SecurityUtils.getSubject();
|
||||||
|
|
||||||
|
if(!subject.isAuthenticated()) {
|
||||||
|
UsernamePasswordToken token = new UsernamePasswordToken(
|
||||||
|
cred.getUsername(), cred.getPassword(), cred.isRememberMe());
|
||||||
|
try {
|
||||||
|
subject.login(token);
|
||||||
|
} catch (AuthenticationException ae) {
|
||||||
|
ae.printStackTrace();
|
||||||
|
attr.addFlashAttribute("error", "Invalid Credentials");
|
||||||
|
return "redirect:/login";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "redirect:/secure";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/secure")
|
||||||
|
public String secure(ModelMap modelMap) {
|
||||||
|
|
||||||
|
Subject currentUser = SecurityUtils.getSubject();
|
||||||
|
String role = "", permission = "";
|
||||||
|
|
||||||
|
if(currentUser.hasRole("admin")) {
|
||||||
|
role = role + "You are an Admin";
|
||||||
|
}
|
||||||
|
else if(currentUser.hasRole("editor")) {
|
||||||
|
role = role + "You are an Editor";
|
||||||
|
}
|
||||||
|
else if(currentUser.hasRole("author")) {
|
||||||
|
role = role + "You are an Author";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentUser.isPermitted("articles:compose")) {
|
||||||
|
permission = permission + "You can compose an article, ";
|
||||||
|
} else {
|
||||||
|
permission = permission + "You are not permitted to compose an article!, ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentUser.isPermitted("articles:save")) {
|
||||||
|
permission = permission + "You can save articles, ";
|
||||||
|
} else {
|
||||||
|
permission = permission + "\nYou can not save articles, ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentUser.isPermitted("articles:publish")) {
|
||||||
|
permission = permission + "\nYou can publish articles";
|
||||||
|
} else {
|
||||||
|
permission = permission + "\nYou can not publish articles";
|
||||||
|
}
|
||||||
|
|
||||||
|
modelMap.addAttribute("username", currentUser.getPrincipal());
|
||||||
|
modelMap.addAttribute("permission", permission);
|
||||||
|
modelMap.addAttribute("role", role);
|
||||||
|
|
||||||
|
return "secure";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/logout")
|
||||||
|
public String logout() {
|
||||||
|
Subject subject = SecurityUtils.getSubject();
|
||||||
|
subject.logout();
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.baeldung.models;
|
||||||
|
|
||||||
|
public class UserCredentials {
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private boolean rememberMe = false;
|
||||||
|
|
||||||
|
public UserCredentials() {}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRememberMe() {
|
||||||
|
return rememberMe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRememberMe(boolean rememberMe) {
|
||||||
|
this.rememberMe = rememberMe;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "username = " + getUsername()
|
||||||
|
+ "\nrememberMe = " + isRememberMe();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
server.port=9000
|
||||||
|
server.servlet-path=/
|
||||||
|
server.context-path=/
|
||||||
|
|
||||||
|
#shiro-spring-boot-config
|
||||||
|
shiro.loginUrl = /login
|
||||||
|
shiro.successUrl = /secure
|
||||||
|
shiro.unauthorizedUrl = /login
|
||||||
|
|
||||||
|
#freemarker
|
||||||
|
spring.freemarker.suffix=.ftl
|
|
@ -0,0 +1,10 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Index</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Welcome Guest!</h1>
|
||||||
|
<br>
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,27 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Login</title>
|
||||||
|
</head>
|
||||||
|
<body style="margin-left: 30px;">
|
||||||
|
<h3>Login</h3>
|
||||||
|
<br>
|
||||||
|
<form action="/login" method="post">
|
||||||
|
<#if (error?length > 0)??>
|
||||||
|
<p style="color:darkred;">${error}</p>
|
||||||
|
<#else>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<br>
|
||||||
|
<input type="text" name="username">
|
||||||
|
<br><br>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<br>
|
||||||
|
<input type="password" name="password">
|
||||||
|
<br><br>
|
||||||
|
<input type="checkbox" name="rememberMe"> Remember Me
|
||||||
|
<br><br>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,15 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Secure</title>
|
||||||
|
</head>
|
||||||
|
<body style="margin-left: 30px;">
|
||||||
|
<h1>Welcome ${username}!</h1>
|
||||||
|
<p><strong>Role</strong>: ${role}</p>
|
||||||
|
<p><strong>Permissions</strong></p>
|
||||||
|
<p>${permission}</p>
|
||||||
|
<br>
|
||||||
|
<form role="form" action="/logout" method="POST">
|
||||||
|
<input type="Submit" value="Logout" />
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -3,11 +3,11 @@ package com.baeldung.concurrent.atomic;
|
||||||
public class SafeCounterWithLock {
|
public class SafeCounterWithLock {
|
||||||
private volatile int counter;
|
private volatile int counter;
|
||||||
|
|
||||||
public int getValue() {
|
int getValue() {
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void increment() {
|
synchronized void increment() {
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,11 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
public class SafeCounterWithoutLock {
|
public class SafeCounterWithoutLock {
|
||||||
private final AtomicInteger counter = new AtomicInteger(0);
|
private final AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
public int getValue() {
|
int getValue() {
|
||||||
return counter.get();
|
return counter.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void increment() {
|
void increment() {
|
||||||
while(true) {
|
while(true) {
|
||||||
int existingValue = getValue();
|
int existingValue = getValue();
|
||||||
int newValue = existingValue + 1;
|
int newValue = existingValue + 1;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package com.baeldung.concurrent.atomic;
|
package com.baeldung.concurrent.atomic;
|
||||||
|
|
||||||
public class UnsafeCounter {
|
public class UnsafeCounter {
|
||||||
int counter;
|
private int counter;
|
||||||
|
|
||||||
public int getValue() {
|
int getValue() {
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void increment() {
|
void increment() {
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,14 @@ package com.baeldung.threadlocal;
|
||||||
public class Context {
|
public class Context {
|
||||||
private final String userName;
|
private final String userName;
|
||||||
|
|
||||||
public Context(String userName) {
|
Context(String userName) {
|
||||||
this.userName = userName;
|
this.userName = userName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Context{" +
|
return "Context{" +
|
||||||
"userNameSecret='" + userName + '\'' +
|
"userNameSecret='" + userName + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,11 @@ import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class SharedMapWithUserContext implements Runnable {
|
public class SharedMapWithUserContext implements Runnable {
|
||||||
public final static Map<Integer, Context> userContextPerUserId = new ConcurrentHashMap<>();
|
final static Map<Integer, Context> userContextPerUserId = new ConcurrentHashMap<>();
|
||||||
private final Integer userId;
|
private final Integer userId;
|
||||||
private UserRepository userRepository = new UserRepository();
|
private UserRepository userRepository = new UserRepository();
|
||||||
|
|
||||||
public SharedMapWithUserContext(Integer userId) {
|
SharedMapWithUserContext(Integer userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ public class ThreadLocalWithUserContext implements Runnable {
|
||||||
private final Integer userId;
|
private final Integer userId;
|
||||||
private UserRepository userRepository = new UserRepository();
|
private UserRepository userRepository = new UserRepository();
|
||||||
|
|
||||||
public ThreadLocalWithUserContext(Integer userId) {
|
ThreadLocalWithUserContext(Integer userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import java.util.UUID;
|
||||||
|
|
||||||
|
|
||||||
public class UserRepository {
|
public class UserRepository {
|
||||||
public String getUserNameForUserId(Integer userId) {
|
String getUserNameForUserId(Integer userId) {
|
||||||
return UUID.randomUUID().toString();
|
return UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,21 @@ package com.baeldung.threadpool;
|
||||||
|
|
||||||
import java.util.concurrent.ForkJoinTask;
|
import java.util.concurrent.ForkJoinTask;
|
||||||
import java.util.concurrent.RecursiveTask;
|
import java.util.concurrent.RecursiveTask;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class CountingTask extends RecursiveTask<Integer> {
|
public class CountingTask extends RecursiveTask<Integer> {
|
||||||
|
|
||||||
private final TreeNode node;
|
private final TreeNode node;
|
||||||
|
|
||||||
public CountingTask(TreeNode node) {
|
CountingTask(TreeNode node) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Integer compute() {
|
protected Integer compute() {
|
||||||
return node.value + node.children.stream().map(childNode -> new CountingTask(childNode).fork()).collect(Collectors.summingInt(ForkJoinTask::join));
|
return node.getValue() + node.getChildren().stream()
|
||||||
|
.map(childNode -> new CountingTask(childNode).fork())
|
||||||
|
.mapToInt(ForkJoinTask::join)
|
||||||
|
.sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,10 @@ public class Consumer implements Runnable {
|
||||||
|
|
||||||
private final TransferQueue<String> transferQueue;
|
private final TransferQueue<String> transferQueue;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final int numberOfMessagesToConsume;
|
final int numberOfMessagesToConsume;
|
||||||
public final AtomicInteger numberOfConsumedMessages = new AtomicInteger();
|
final AtomicInteger numberOfConsumedMessages = new AtomicInteger();
|
||||||
|
|
||||||
public Consumer(TransferQueue<String> transferQueue, String name, int numberOfMessagesToConsume) {
|
Consumer(TransferQueue<String> transferQueue, String name, int numberOfMessagesToConsume) {
|
||||||
this.transferQueue = transferQueue;
|
this.transferQueue = transferQueue;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.numberOfMessagesToConsume = numberOfMessagesToConsume;
|
this.numberOfMessagesToConsume = numberOfMessagesToConsume;
|
||||||
|
|
|
@ -12,10 +12,10 @@ public class Producer implements Runnable {
|
||||||
|
|
||||||
private final TransferQueue<String> transferQueue;
|
private final TransferQueue<String> transferQueue;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final Integer numberOfMessagesToProduce;
|
final Integer numberOfMessagesToProduce;
|
||||||
public final AtomicInteger numberOfProducedMessages = new AtomicInteger();
|
final AtomicInteger numberOfProducedMessages = new AtomicInteger();
|
||||||
|
|
||||||
public Producer(TransferQueue<String> transferQueue, String name, Integer numberOfMessagesToProduce) {
|
Producer(TransferQueue<String> transferQueue, String name, Integer numberOfMessagesToProduce) {
|
||||||
this.transferQueue = transferQueue;
|
this.transferQueue = transferQueue;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.numberOfMessagesToProduce = numberOfMessagesToProduce;
|
this.numberOfMessagesToProduce = numberOfMessagesToProduce;
|
||||||
|
|
|
@ -4,7 +4,11 @@ import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ public class CountdownLatchExampleIntegrationTest {
|
||||||
// Given
|
// Given
|
||||||
List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
|
List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(5);
|
CountDownLatch countDownLatch = new CountDownLatch(5);
|
||||||
List<Thread> workers = Stream.generate(() -> new Thread(new Worker(outputScraper, countDownLatch))).limit(5).collect(toList());
|
List<Thread> workers = Stream.generate(() -> new Thread(new Worker(outputScraper, countDownLatch)))
|
||||||
|
.limit(5)
|
||||||
|
.collect(toList());
|
||||||
|
|
||||||
// When
|
// When
|
||||||
workers.forEach(Thread::start);
|
workers.forEach(Thread::start);
|
||||||
|
@ -26,7 +28,6 @@ public class CountdownLatchExampleIntegrationTest {
|
||||||
outputScraper.add("Latch released");
|
outputScraper.add("Latch released");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
outputScraper.forEach(Object::toString);
|
|
||||||
assertThat(outputScraper).containsExactly("Counted down", "Counted down", "Counted down", "Counted down", "Counted down", "Latch released");
|
assertThat(outputScraper).containsExactly("Counted down", "Counted down", "Counted down", "Counted down", "Counted down", "Latch released");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +36,9 @@ public class CountdownLatchExampleIntegrationTest {
|
||||||
// Given
|
// Given
|
||||||
List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
|
List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(5);
|
CountDownLatch countDownLatch = new CountDownLatch(5);
|
||||||
List<Thread> workers = Stream.generate(() -> new Thread(new BrokenWorker(outputScraper, countDownLatch))).limit(5).collect(toList());
|
List<Thread> workers = Stream.generate(() -> new Thread(new BrokenWorker(outputScraper, countDownLatch)))
|
||||||
|
.limit(5)
|
||||||
|
.collect(toList());
|
||||||
|
|
||||||
// When
|
// When
|
||||||
workers.forEach(Thread::start);
|
workers.forEach(Thread::start);
|
||||||
|
@ -63,7 +66,6 @@ public class CountdownLatchExampleIntegrationTest {
|
||||||
outputScraper.add("Workers complete");
|
outputScraper.add("Workers complete");
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
outputScraper.forEach(Object::toString);
|
|
||||||
assertThat(outputScraper).containsExactly("Workers ready", "Counted down", "Counted down", "Counted down", "Counted down", "Counted down", "Workers complete");
|
assertThat(outputScraper).containsExactly("Workers ready", "Counted down", "Counted down", "Counted down", "Counted down", "Counted down", "Workers complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ public class SquareCalculatorIntegrationTest {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SquareCalculatorIntegrationTest.class);
|
private static final Logger LOG = LoggerFactory.getLogger(SquareCalculatorIntegrationTest.class);
|
||||||
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public TestName name = new TestName();
|
public TestName name = new TestName();
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,7 @@ public class SynchronizedHashMapWithRWLockManualTest {
|
||||||
|
|
||||||
private void executeReaderThreads(SynchronizedHashMapWithRWLock object, int threadCount, ExecutorService service) {
|
private void executeReaderThreads(SynchronizedHashMapWithRWLock object, int threadCount, ExecutorService service) {
|
||||||
for (int i = 0; i < threadCount; i++)
|
for (int i = 0; i < threadCount; i++)
|
||||||
service.execute(() -> {
|
service.execute(() -> object.get("key" + threadCount));
|
||||||
object.get("key" + threadCount);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
public class ConcurrentMapNullKeyValueManualTest {
|
public class ConcurrentMapNullKeyValueManualTest {
|
||||||
|
|
||||||
ConcurrentMap<String, Object> concurrentMap;
|
private ConcurrentMap<String, Object> concurrentMap;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
|
@ -18,7 +18,7 @@ public class ConcurrentNavigableMapManualTest {
|
||||||
public void givenSkipListMap_whenAccessInMultiThreads_thenOrderingStable() throws InterruptedException {
|
public void givenSkipListMap_whenAccessInMultiThreads_thenOrderingStable() throws InterruptedException {
|
||||||
NavigableMap<Integer, String> skipListMap = new ConcurrentSkipListMap<>();
|
NavigableMap<Integer, String> skipListMap = new ConcurrentSkipListMap<>();
|
||||||
|
|
||||||
updateMapConcurrently(skipListMap, 4);
|
updateMapConcurrently(skipListMap);
|
||||||
|
|
||||||
Iterator<Integer> skipListIter = skipListMap.keySet().iterator();
|
Iterator<Integer> skipListIter = skipListMap.keySet().iterator();
|
||||||
int previous = skipListIter.next();
|
int previous = skipListIter.next();
|
||||||
|
@ -28,9 +28,9 @@ public class ConcurrentNavigableMapManualTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMapConcurrently(NavigableMap<Integer, String> navigableMap, int concurrencyLevel) throws InterruptedException {
|
private void updateMapConcurrently(NavigableMap<Integer, String> navigableMap) throws InterruptedException {
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(concurrencyLevel);
|
ExecutorService executorService = Executors.newFixedThreadPool(4);
|
||||||
for (int i = 0; i < concurrencyLevel; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
executorService.execute(() -> {
|
executorService.execute(() -> {
|
||||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
for (int j = 0; j < 10000; j++) {
|
for (int j = 0; j < 10000; j++) {
|
||||||
|
@ -45,26 +45,26 @@ public class ConcurrentNavigableMapManualTest {
|
||||||
@Test
|
@Test
|
||||||
public void givenSkipListMap_whenNavConcurrently_thenCountCorrect() throws InterruptedException {
|
public void givenSkipListMap_whenNavConcurrently_thenCountCorrect() throws InterruptedException {
|
||||||
NavigableMap<Integer, Integer> skipListMap = new ConcurrentSkipListMap<>();
|
NavigableMap<Integer, Integer> skipListMap = new ConcurrentSkipListMap<>();
|
||||||
int count = countMapElementByPollingFirstEntry(skipListMap, 10000, 4);
|
int count = countMapElementByPollingFirstEntry(skipListMap);
|
||||||
assertEquals(10000 * 4, count);
|
assertEquals(10000 * 4, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenTreeMap_whenNavConcurrently_thenCountError() throws InterruptedException {
|
public void givenTreeMap_whenNavConcurrently_thenCountError() throws InterruptedException {
|
||||||
NavigableMap<Integer, Integer> treeMap = new TreeMap<>();
|
NavigableMap<Integer, Integer> treeMap = new TreeMap<>();
|
||||||
int count = countMapElementByPollingFirstEntry(treeMap, 10000, 4);
|
int count = countMapElementByPollingFirstEntry(treeMap);
|
||||||
assertNotEquals(10000 * 4, count);
|
assertNotEquals(10000 * 4, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int countMapElementByPollingFirstEntry(NavigableMap<Integer, Integer> navigableMap, int elementCount, int concurrencyLevel) throws InterruptedException {
|
private int countMapElementByPollingFirstEntry(NavigableMap<Integer, Integer> navigableMap) throws InterruptedException {
|
||||||
for (int i = 0; i < elementCount * concurrencyLevel; i++) {
|
for (int i = 0; i < 10000 * 4; i++) {
|
||||||
navigableMap.put(i, i);
|
navigableMap.put(i, i);
|
||||||
}
|
}
|
||||||
AtomicInteger counter = new AtomicInteger(0);
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(concurrencyLevel);
|
ExecutorService executorService = Executors.newFixedThreadPool(4);
|
||||||
for (int j = 0; j < concurrencyLevel; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
executorService.execute(() -> {
|
executorService.execute(() -> {
|
||||||
for (int i = 0; i < elementCount; i++) {
|
for (int i = 0; i < 10000; i++) {
|
||||||
if (navigableMap.pollFirstEntry() != null) {
|
if (navigableMap.pollFirstEntry() != null) {
|
||||||
counter.incrementAndGet();
|
counter.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.baeldung.java.concurrentmodification;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.ConcurrentModificationException;
|
import java.util.ConcurrentModificationException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -28,9 +27,9 @@ public class ConcurrentModificationUnitTest {
|
||||||
|
|
||||||
List<Integer> integers = newArrayList(1, 2, 3);
|
List<Integer> integers = newArrayList(1, 2, 3);
|
||||||
|
|
||||||
for (Iterator<Integer> iterator = integers.iterator(); iterator.hasNext();) {
|
for (Iterator<Integer> iterator = integers.iterator(); iterator.hasNext(); ) {
|
||||||
Integer integer = iterator.next();
|
Integer integer = iterator.next();
|
||||||
if(integer == 2) {
|
if (integer == 2) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +44,7 @@ public class ConcurrentModificationUnitTest {
|
||||||
List<Integer> toRemove = newArrayList();
|
List<Integer> toRemove = newArrayList();
|
||||||
|
|
||||||
for (Integer integer : integers) {
|
for (Integer integer : integers) {
|
||||||
if(integer == 2) {
|
if (integer == 2) {
|
||||||
toRemove.add(integer);
|
toRemove.add(integer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,10 +68,10 @@ public class ConcurrentModificationUnitTest {
|
||||||
Collection<Integer> integers = newArrayList(1, 2, 3);
|
Collection<Integer> integers = newArrayList(1, 2, 3);
|
||||||
|
|
||||||
List<String> collected = integers
|
List<String> collected = integers
|
||||||
.stream()
|
.stream()
|
||||||
.filter(i -> i != 2)
|
.filter(i -> i != 2)
|
||||||
.map(Object::toString)
|
.map(Object::toString)
|
||||||
.collect(toList());
|
.collect(toList());
|
||||||
|
|
||||||
assertThat(collected).containsExactly("1", "3");
|
assertThat(collected).containsExactly("1", "3");
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ public class Java8ExecutorServiceIntegrationTest {
|
||||||
|
|
||||||
assertTrue(threadPoolExecutor.isShutdown());
|
assertTrue(threadPoolExecutor.isShutdown());
|
||||||
assertFalse(notExecutedTasks.isEmpty());
|
assertFalse(notExecutedTasks.isEmpty());
|
||||||
assertTrue(notExecutedTasks.size() > 0 && notExecutedTasks.size() < 98);
|
assertTrue(notExecutedTasks.size() < 98);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Runnable> smartShutdown(ExecutorService executorService) {
|
private List<Runnable> smartShutdown(ExecutorService executorService) {
|
||||||
|
|
|
@ -23,7 +23,10 @@ public class ThreadPoolInParallelStreamIntegrationTest {
|
||||||
List<Long> aList = LongStream.rangeClosed(firstNum, lastNum).boxed().collect(Collectors.toList());
|
List<Long> aList = LongStream.rangeClosed(firstNum, lastNum).boxed().collect(Collectors.toList());
|
||||||
|
|
||||||
ForkJoinPool customThreadPool = new ForkJoinPool(4);
|
ForkJoinPool customThreadPool = new ForkJoinPool(4);
|
||||||
long actualTotal = customThreadPool.submit(() -> aList.parallelStream().reduce(0L, Long::sum)).get();
|
long actualTotal = customThreadPool
|
||||||
|
.submit(() -> aList.parallelStream()
|
||||||
|
.reduce(0L, Long::sum))
|
||||||
|
.get();
|
||||||
|
|
||||||
assertEquals((lastNum + firstNum) * lastNum / 2, actualTotal);
|
assertEquals((lastNum + firstNum) * lastNum / 2, actualTotal);
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,3 +119,6 @@
|
||||||
- [Guide to UUID in Java](http://www.baeldung.com/java-uuid)
|
- [Guide to UUID in Java](http://www.baeldung.com/java-uuid)
|
||||||
- [How to Get the Last Element of a Stream in Java?](http://www.baeldung.com/java-stream-last-element)
|
- [How to Get the Last Element of a Stream in Java?](http://www.baeldung.com/java-stream-last-element)
|
||||||
- [Guide to Escaping Characters in Java RegExps](http://www.baeldung.com/java-regexp-escape-char)
|
- [Guide to Escaping Characters in Java RegExps](http://www.baeldung.com/java-regexp-escape-char)
|
||||||
|
- [Period and Duration in Java](http://www.baeldung.com/java-period-duration)
|
||||||
|
- [Introduction to the Java 8 Date/Time API](http://www.baeldung.com/java-8-date-time-intro)
|
||||||
|
- [Migrating to the New Java 8 Date Time API](http://www.baeldung.com/migrating-to-java-8-date-time-api)
|
||||||
|
|
|
@ -186,6 +186,16 @@
|
||||||
<artifactId>fscontext</artifactId>
|
<artifactId>fscontext</artifactId>
|
||||||
<version>${fscontext.version}</version>
|
<version>${fscontext.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>joda-time</groupId>
|
||||||
|
<artifactId>joda-time</artifactId>
|
||||||
|
<version>${joda-time.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.darwinsys</groupId>
|
||||||
|
<artifactId>hirondelle-date4j</artifactId>
|
||||||
|
<version>${hirondelle-date4j.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -408,6 +418,8 @@
|
||||||
<grep4j.version>1.8.7</grep4j.version>
|
<grep4j.version>1.8.7</grep4j.version>
|
||||||
<lombok.version>1.16.12</lombok.version>
|
<lombok.version>1.16.12</lombok.version>
|
||||||
<fscontext.version>4.6-b01</fscontext.version>
|
<fscontext.version>4.6-b01</fscontext.version>
|
||||||
|
<joda-time.version>2.9.9</joda-time.version>
|
||||||
|
<hirondelle-date4j.version>1.5.1</hirondelle-date4j.version>
|
||||||
|
|
||||||
<!-- testing -->
|
<!-- testing -->
|
||||||
<org.hamcrest.version>1.3</org.hamcrest.version>
|
<org.hamcrest.version>1.3</org.hamcrest.version>
|
||||||
|
@ -416,9 +428,9 @@
|
||||||
<assertj.version>3.6.1</assertj.version>
|
<assertj.version>3.6.1</assertj.version>
|
||||||
<avaitility.version>1.7.0</avaitility.version>
|
<avaitility.version>1.7.0</avaitility.version>
|
||||||
|
|
||||||
|
|
||||||
<!-- maven plugins -->
|
<!-- maven plugins -->
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
||||||
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||||
|
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
package com.baeldung.numberofdigits;
|
||||||
|
|
||||||
|
import static com.baeldung.designpatterns.util.LogerUtil.LOG;;
|
||||||
|
|
||||||
|
public class Benchmarking {;
|
||||||
|
|
||||||
|
private static final int LOWER_BOUND = 1;
|
||||||
|
private static final int UPPER_BOUND = 999999999;
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
LOG.info("Testing all methods...");
|
||||||
|
|
||||||
|
long length = test_stringBasedSolution();
|
||||||
|
LOG.info("String Based Solution : " + length);
|
||||||
|
|
||||||
|
length = test_logarithmicApproach();
|
||||||
|
LOG.info("Logarithmic Approach : " + length);
|
||||||
|
|
||||||
|
length = test_repeatedMultiplication();
|
||||||
|
LOG.info("Repeated Multiplication : " + length);
|
||||||
|
|
||||||
|
length = test_shiftOperators();
|
||||||
|
LOG.info("Shift Operators : " + length);
|
||||||
|
|
||||||
|
length = test_dividingWithPowersOf2();
|
||||||
|
LOG.info("Dividing with Powers of 2 : " + length);
|
||||||
|
|
||||||
|
length = test_divideAndConquer();
|
||||||
|
LOG.info("Divide And Conquer : " + length);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long test_stringBasedSolution() {
|
||||||
|
|
||||||
|
long startTime, stopTime, elapsedTime;
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
for (int i = LOWER_BOUND; i <= UPPER_BOUND; i++) {
|
||||||
|
total += NumberOfDigits.stringBasedSolution(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTime = System.currentTimeMillis();
|
||||||
|
elapsedTime = stopTime - startTime;
|
||||||
|
|
||||||
|
return elapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long test_logarithmicApproach() {
|
||||||
|
|
||||||
|
long startTime, stopTime, elapsedTime;
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
for (int i = LOWER_BOUND; i <= UPPER_BOUND; i++) {
|
||||||
|
total += NumberOfDigits.logarithmicApproach(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTime = System.currentTimeMillis();
|
||||||
|
elapsedTime = stopTime - startTime;
|
||||||
|
|
||||||
|
return elapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long test_repeatedMultiplication() {
|
||||||
|
|
||||||
|
long startTime, stopTime, elapsedTime;
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
for (int i = LOWER_BOUND; i <= UPPER_BOUND; i++) {
|
||||||
|
total += NumberOfDigits.repeatedMultiplication(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTime = System.currentTimeMillis();
|
||||||
|
elapsedTime = stopTime - startTime;
|
||||||
|
|
||||||
|
return elapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long test_shiftOperators() {
|
||||||
|
|
||||||
|
long startTime, stopTime, elapsedTime;
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
for (int i = LOWER_BOUND; i <= UPPER_BOUND; i++) {
|
||||||
|
total += NumberOfDigits.shiftOperators(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTime = System.currentTimeMillis();
|
||||||
|
elapsedTime = stopTime - startTime;
|
||||||
|
|
||||||
|
return elapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long test_dividingWithPowersOf2() {
|
||||||
|
|
||||||
|
long startTime, stopTime, elapsedTime;
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
for (int i = LOWER_BOUND; i <= UPPER_BOUND; i++) {
|
||||||
|
total += NumberOfDigits.dividingWithPowersOf2(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTime = System.currentTimeMillis();
|
||||||
|
elapsedTime = stopTime - startTime;
|
||||||
|
|
||||||
|
return elapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long test_divideAndConquer() {
|
||||||
|
|
||||||
|
long startTime, stopTime, elapsedTime;
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
for (int i = LOWER_BOUND; i <= UPPER_BOUND; i++) {
|
||||||
|
total += NumberOfDigits.divideAndConquer(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTime = System.currentTimeMillis();
|
||||||
|
elapsedTime = stopTime - startTime;
|
||||||
|
|
||||||
|
return elapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package com.baeldung.numberofdigits;
|
||||||
|
|
||||||
|
public class NumberOfDigits {
|
||||||
|
public static int stringBasedSolution(int number) {
|
||||||
|
int length = String.valueOf(number).length();
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int logarithmicApproach(int number) {
|
||||||
|
int length = (int) Math.log10(number) + 1;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int repeatedMultiplication(int number) {
|
||||||
|
int length = 0;
|
||||||
|
long temp = 1;
|
||||||
|
while(temp <= number) {
|
||||||
|
length++;
|
||||||
|
temp *= 10;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int shiftOperators(int number) {
|
||||||
|
int length = 0;
|
||||||
|
long temp = 1;
|
||||||
|
while(temp <= number) {
|
||||||
|
length++;
|
||||||
|
temp = (temp << 3) + (temp << 1);
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int dividingWithPowersOf2(int number) {
|
||||||
|
int length = 1;
|
||||||
|
if (number >= 100000000) {
|
||||||
|
length += 8;
|
||||||
|
number /= 100000000;
|
||||||
|
}
|
||||||
|
if (number >= 10000) {
|
||||||
|
length += 4;
|
||||||
|
number /= 10000;
|
||||||
|
}
|
||||||
|
if (number >= 100) {
|
||||||
|
length += 2;
|
||||||
|
number /= 100;
|
||||||
|
}
|
||||||
|
if (number >= 10) {
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int divideAndConquer(int number) {
|
||||||
|
if (number < 100000){
|
||||||
|
// 5 digits or less
|
||||||
|
if (number < 100){
|
||||||
|
// 1 or 2
|
||||||
|
if (number < 10)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 2;
|
||||||
|
}else{
|
||||||
|
// 3 to 5 digits
|
||||||
|
if (number < 1000)
|
||||||
|
return 3;
|
||||||
|
else{
|
||||||
|
// 4 or 5 digits
|
||||||
|
if (number < 10000)
|
||||||
|
return 4;
|
||||||
|
else
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 6 digits or more
|
||||||
|
if (number < 10000000) {
|
||||||
|
// 6 or 7 digits
|
||||||
|
if (number < 1000000)
|
||||||
|
return 6;
|
||||||
|
else
|
||||||
|
return 7;
|
||||||
|
} else {
|
||||||
|
// 8 to 10 digits
|
||||||
|
if (number < 100000000)
|
||||||
|
return 8;
|
||||||
|
else {
|
||||||
|
// 9 or 10 digits
|
||||||
|
if (number < 1000000000)
|
||||||
|
return 9;
|
||||||
|
else
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.baeldung.numberofdigits;
|
||||||
|
|
||||||
|
import static com.baeldung.designpatterns.util.LogerUtil.LOG;
|
||||||
|
|
||||||
|
public class NumberOfDigitsDriver {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
LOG.info("Testing all methods...");
|
||||||
|
|
||||||
|
long length = NumberOfDigits.stringBasedSolution(602);
|
||||||
|
LOG.info("String Based Solution : " + length);
|
||||||
|
|
||||||
|
length = NumberOfDigits.logarithmicApproach(602);
|
||||||
|
LOG.info("Logarithmic Approach : " + length);
|
||||||
|
|
||||||
|
length = NumberOfDigits.repeatedMultiplication(602);
|
||||||
|
LOG.info("Repeated Multiplication : " + length);
|
||||||
|
|
||||||
|
length = NumberOfDigits.shiftOperators(602);
|
||||||
|
LOG.info("Shift Operators : " + length);
|
||||||
|
|
||||||
|
length = NumberOfDigits.dividingWithPowersOf2(602);
|
||||||
|
LOG.info("Dividing with Powers of 2 : " + length);
|
||||||
|
|
||||||
|
length = NumberOfDigits.divideAndConquer(602);
|
||||||
|
LOG.info("Divide And Conquer : " + length);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package com.baeldung;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class DateDiffUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix() throws ParseException {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
|
||||||
|
Date firstDate = sdf.parse("06/24/2017");
|
||||||
|
Date secondDate = sdf.parse("06/30/2017");
|
||||||
|
|
||||||
|
long diffInMillies = Math.abs(secondDate.getTime() - firstDate.getTime());
|
||||||
|
long diff = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDatesInJava8_whenDifferentiating_thenWeGetSix() {
|
||||||
|
LocalDate now = LocalDate.now();
|
||||||
|
LocalDate sixDaysBehind = now.minusDays(6);
|
||||||
|
|
||||||
|
Duration duration = Duration.between(now, sixDaysBehind);
|
||||||
|
long diff = Math.abs(duration.toDays());
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDateTimesInJava8_whenDifferentiating_thenWeGetSix() {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
LocalDateTime sixMinutesBehind = now.minusMinutes(6);
|
||||||
|
|
||||||
|
Duration duration = Duration.between(now, sixMinutesBehind);
|
||||||
|
long diff = Math.abs(duration.toMinutes());
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix() {
|
||||||
|
org.joda.time.LocalDate now = org.joda.time.LocalDate.now();
|
||||||
|
org.joda.time.LocalDate sixDaysBehind = now.minusDays(6);
|
||||||
|
|
||||||
|
org.joda.time.Period period = new org.joda.time.Period(now, sixDaysBehind);
|
||||||
|
long diff = Math.abs(period.getDays());
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDateTimesInJodaTime_whenDifferentiating_thenWeGetSix() {
|
||||||
|
org.joda.time.LocalDateTime now = org.joda.time.LocalDateTime.now();
|
||||||
|
org.joda.time.LocalDateTime sixMinutesBehind = now.minusMinutes(6);
|
||||||
|
|
||||||
|
org.joda.time.Period period = new org.joda.time.Period(now, sixMinutesBehind);
|
||||||
|
long diff = Math.abs(period.getDays());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix() {
|
||||||
|
hirondelle.date4j.DateTime now = hirondelle.date4j.DateTime.now(TimeZone.getDefault());
|
||||||
|
hirondelle.date4j.DateTime sixDaysBehind = now.minusDays(6);
|
||||||
|
|
||||||
|
long diff = Math.abs(now.numDaysFrom(sixDaysBehind));
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
package com.baeldung.numberofdigits;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Assume;
|
||||||
|
import org.junit.experimental.theories.DataPoints;
|
||||||
|
import org.junit.experimental.theories.Theories;
|
||||||
|
import org.junit.experimental.theories.Theory;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(Theories.class)
|
||||||
|
public class NumberOfDigitsIntegrationTest {
|
||||||
|
|
||||||
|
@DataPoints
|
||||||
|
public static int[][] lowestIntegers()
|
||||||
|
{
|
||||||
|
return new int[][]{
|
||||||
|
{1, 1},
|
||||||
|
{2, 10},
|
||||||
|
{3, 100},
|
||||||
|
{4, 1000},
|
||||||
|
{5, 10000},
|
||||||
|
{6, 100000},
|
||||||
|
{7, 1000000},
|
||||||
|
{8, 10000000},
|
||||||
|
{9, 100000000},
|
||||||
|
{10, 1000000000}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@DataPoints
|
||||||
|
public static int[][] highestIntegers()
|
||||||
|
{
|
||||||
|
return new int[][]{
|
||||||
|
{1, 9},
|
||||||
|
{2, 99},
|
||||||
|
{3, 999},
|
||||||
|
{4, 9999},
|
||||||
|
{5, 99999},
|
||||||
|
{6, 999999},
|
||||||
|
{7, 9999999},
|
||||||
|
{8, 99999999},
|
||||||
|
{9, 999999999},
|
||||||
|
{10, Integer.MAX_VALUE}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@DataPoints
|
||||||
|
public static int[][] randomIntegers()
|
||||||
|
{
|
||||||
|
return new int[][]{
|
||||||
|
{1, 1},
|
||||||
|
{2, 14},
|
||||||
|
{3, 549},
|
||||||
|
{4, 1136},
|
||||||
|
{5, 25340},
|
||||||
|
{6, 134321},
|
||||||
|
{7, 1435432},
|
||||||
|
{8, 54234129},
|
||||||
|
{9, 113683912},
|
||||||
|
{10, 1534031982}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Theory
|
||||||
|
public void givenDataPoints_whenStringBasedSolutionInvoked_thenAllPointsMatch(final int[] entry) {
|
||||||
|
Assume.assumeTrue(entry[0] > 0 && entry[1] > 0);
|
||||||
|
Assert.assertEquals(entry[0], NumberOfDigits.stringBasedSolution(entry[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Theory
|
||||||
|
public void givenDataPoints_whenLogarithmicApproachInvoked_thenAllPointsMatch(final int[] entry) {
|
||||||
|
Assume.assumeTrue(entry[0] > 0 && entry[1] > 0);
|
||||||
|
Assert.assertEquals(entry[0], NumberOfDigits.logarithmicApproach(entry[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Theory
|
||||||
|
public void givenDataPoints_whenRepeatedMultiplicationInvoked_thenAllPointsMatch(final int[] entry) {
|
||||||
|
Assume.assumeTrue(entry[0] > 0 && entry[1] > 0);
|
||||||
|
Assert.assertEquals(entry[0], NumberOfDigits.repeatedMultiplication(entry[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Theory
|
||||||
|
public void givenDataPoints_whenShiftOperatorsInvoked_thenAllPointsMatch(final int[] entry) {
|
||||||
|
Assume.assumeTrue(entry[0] > 0 && entry[1] > 0);
|
||||||
|
Assert.assertEquals(entry[0], NumberOfDigits.shiftOperators(entry[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Theory
|
||||||
|
public void givenDataPoints_whenDividingWithPowersOf2Invoked_thenAllPointsMatch(final int[] entry) {
|
||||||
|
Assume.assumeTrue(entry[0] > 0 && entry[1] > 0);
|
||||||
|
Assert.assertEquals(entry[0], NumberOfDigits.dividingWithPowersOf2(entry[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Theory
|
||||||
|
public void givenDataPoints_whenDivideAndConquerInvoked_thenAllPointsMatch(final int[] entry) {
|
||||||
|
Assume.assumeTrue(entry[0] > 0 && entry[1] > 0);
|
||||||
|
Assert.assertEquals(entry[0], NumberOfDigits.divideAndConquer(entry[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
## Relevant articles:
|
||||||
|
|
||||||
|
- [Period and Duration in Java](http://www.baeldung.com/java-period-duration)
|
||||||
|
- [Introduction to the Java 8 Date/Time API](http://www.baeldung.com/java-8-date-time-intro)
|
||||||
|
- [Migrating to the New Java 8 Date Time API](http://www.baeldung.com/migrating-to-java-8-date-time-api)
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?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/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>java-difference-date</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>java-difference-date</name>
|
||||||
|
<description>Difference between two dates in java</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-modules</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>joda-time</groupId>
|
||||||
|
<artifactId>joda-time</artifactId>
|
||||||
|
<version>${joda-time.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.darwinsys</groupId>
|
||||||
|
<artifactId>hirondelle-date4j</artifactId>
|
||||||
|
<version>${hirondelle-date4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>${junit.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<target>1.8</target>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<junit.version>4.12</junit.version>
|
||||||
|
<joda-time.version>2.9.9</joda-time.version>
|
||||||
|
<hirondelle-date4j.version>1.5.1</hirondelle-date4j.version>
|
||||||
|
</properties>
|
||||||
|
</project>
|
|
@ -0,0 +1,61 @@
|
||||||
|
package com.baeldung;
|
||||||
|
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class DateDiffTest {
|
||||||
|
@Test
|
||||||
|
public void givenTwoDatesBeforeJava8_whenDifferentiating_thenWeGetSix() throws ParseException {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
|
||||||
|
Date firstDate = sdf.parse("06/24/2017");
|
||||||
|
Date secondDate = sdf.parse("06/30/2017");
|
||||||
|
|
||||||
|
long diffInMillies = Math.abs(secondDate.getTime() - firstDate.getTime());
|
||||||
|
long diff = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDatesInJava8_whenDifferentiating_thenWeGetSix() {
|
||||||
|
ZonedDateTime now = ZonedDateTime.now();
|
||||||
|
ZonedDateTime sixDaysBehind = now.minusDays(6);
|
||||||
|
|
||||||
|
Duration duration = Duration.between(now, sixDaysBehind);
|
||||||
|
long diff = Math.abs(duration.toDays());
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDatesInJodaTime_whenDifferentiating_thenWeGetSix() {
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
DateTime sixDaysBehind = now.minusDays(6);
|
||||||
|
|
||||||
|
org.joda.time.Duration duration = new org.joda.time.Duration(now, sixDaysBehind);
|
||||||
|
long diff = Math.abs(duration.getStandardDays());
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTwoDatesInDate4j_whenDifferentiating_thenWeGetSix() {
|
||||||
|
hirondelle.date4j.DateTime now = hirondelle.date4j.DateTime.now(TimeZone.getDefault());
|
||||||
|
hirondelle.date4j.DateTime sixDaysBehind = now.minusDays(6);
|
||||||
|
|
||||||
|
long diff = Math.abs(now.numDaysFrom(sixDaysBehind));
|
||||||
|
|
||||||
|
assertEquals(diff, 6);
|
||||||
|
}
|
||||||
|
}
|
1
pom.xml
1
pom.xml
|
@ -43,6 +43,7 @@
|
||||||
<module>cdi</module>
|
<module>cdi</module>
|
||||||
<!-- <module>core-java-9</module> -->
|
<!-- <module>core-java-9</module> -->
|
||||||
<module>core-java</module>
|
<module>core-java</module>
|
||||||
|
<module>core-java-concurrency</module>
|
||||||
<module>couchbase-sdk</module>
|
<module>couchbase-sdk</module>
|
||||||
|
|
||||||
<module>deltaspike</module>
|
<module>deltaspike</module>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.functional;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
public class MyService {
|
||||||
|
|
||||||
|
public int getRandomNumber(){
|
||||||
|
return (new Random().nextInt(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.baeldung.functional;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||||
|
|
||||||
|
import com.baeldung.Spring5Application;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = Spring5Application.class)
|
||||||
|
public class BeanRegistrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GenericWebApplicationContext context;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRegisterBean_thenOk() {
|
||||||
|
context.registerBean(MyService.class, () -> new MyService());
|
||||||
|
MyService myService = (MyService) context.getBean("com.baeldung.functional.MyService");
|
||||||
|
assertTrue(myService.getRandomNumber() < 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRegisterBeanWithName_thenOk() {
|
||||||
|
context.registerBean("mySecondService", MyService.class, () -> new MyService());
|
||||||
|
MyService mySecondService = (MyService) context.getBean("mySecondService");
|
||||||
|
assertTrue(mySecondService.getRandomNumber() < 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRegisterBeanWithCallback_thenOk() {
|
||||||
|
context.registerBean("myCallbackService", MyService.class, () -> new MyService(), bd -> bd.setAutowireCandidate(false));
|
||||||
|
MyService myCallbackService = (MyService) context.getBean("myCallbackService");
|
||||||
|
assertTrue(myCallbackService.getRandomNumber() < 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,9 +35,15 @@
|
||||||
<version>4.3.10.RELEASE</version>
|
<version>4.3.10.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.servlet</groupId>
|
<groupId>org.thymeleaf</groupId>
|
||||||
<artifactId>jstl</artifactId>
|
<artifactId>thymeleaf</artifactId>
|
||||||
<version>1.2</version>
|
<version>3.0.7.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.thymeleaf</groupId>
|
||||||
|
<artifactId>thymeleaf-spring4</artifactId>
|
||||||
|
<version>3.0.7.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package com.baeldung.kotlin.mvc
|
package com.baeldung.kotlin.mvc
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContext
|
||||||
|
import org.springframework.context.ApplicationContextAware
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.web.servlet.ViewResolver
|
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
|
||||||
import org.springframework.web.servlet.view.InternalResourceViewResolver
|
import org.thymeleaf.spring4.SpringTemplateEngine
|
||||||
import org.springframework.web.servlet.view.JstlView
|
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver
|
||||||
|
import org.thymeleaf.spring4.view.ThymeleafViewResolver
|
||||||
|
import org.thymeleaf.templatemode.TemplateMode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +18,13 @@ import org.springframework.web.servlet.view.JstlView
|
||||||
|
|
||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
@Configuration
|
@Configuration
|
||||||
open class ApplicationWebConfig: WebMvcConfigurerAdapter() {
|
open class ApplicationWebConfig: WebMvcConfigurerAdapter(), ApplicationContextAware {
|
||||||
|
|
||||||
|
private var applicationContext: ApplicationContext? = null
|
||||||
|
|
||||||
|
override fun setApplicationContext(applicationContext: ApplicationContext?) {
|
||||||
|
this.applicationContext = applicationContext
|
||||||
|
}
|
||||||
|
|
||||||
override fun addViewControllers(registry: ViewControllerRegistry?) {
|
override fun addViewControllers(registry: ViewControllerRegistry?) {
|
||||||
super.addViewControllers(registry)
|
super.addViewControllers(registry)
|
||||||
|
@ -24,14 +33,28 @@ open class ApplicationWebConfig: WebMvcConfigurerAdapter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
open fun viewResolver(): ViewResolver {
|
open fun templateResolver(): SpringResourceTemplateResolver {
|
||||||
val bean = InternalResourceViewResolver()
|
val templateResolver = SpringResourceTemplateResolver()
|
||||||
|
templateResolver.prefix = "/WEB-INF/view/"
|
||||||
|
templateResolver.suffix = ".html"
|
||||||
|
templateResolver.templateMode = TemplateMode.HTML
|
||||||
|
templateResolver.setApplicationContext(this.applicationContext);
|
||||||
|
return templateResolver
|
||||||
|
}
|
||||||
|
|
||||||
bean.setViewClass(JstlView::class.java)
|
@Bean
|
||||||
bean.setPrefix("/WEB-INF/view/")
|
open fun templateEngine(): SpringTemplateEngine {
|
||||||
bean.setSuffix(".jsp")
|
val templateEngine = SpringTemplateEngine()
|
||||||
|
templateEngine.setTemplateResolver(templateResolver())
|
||||||
|
return templateEngine
|
||||||
|
}
|
||||||
|
|
||||||
return bean
|
@Bean
|
||||||
|
open fun viewResolver(): ThymeleafViewResolver {
|
||||||
|
val viewResolver = ThymeleafViewResolver()
|
||||||
|
viewResolver.templateEngine = templateEngine()
|
||||||
|
viewResolver.order = 1
|
||||||
|
return viewResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -12,13 +12,26 @@
|
||||||
|
|
||||||
<context:component-scan base-package="com.baeldung.kotlin.mvc" />
|
<context:component-scan base-package="com.baeldung.kotlin.mvc" />
|
||||||
|
|
||||||
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
|
||||||
<property name="prefix" value="/WEB-INF/view/"/>
|
|
||||||
<property name="suffix" value=".jsp"/>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<mvc:view-controller path="/welcome.html"/>
|
<mvc:view-controller path="/welcome.html"/>
|
||||||
|
|
||||||
<mvc:annotation-driven />
|
<mvc:annotation-driven />
|
||||||
|
|
||||||
|
<bean id="templateResolver"
|
||||||
|
class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
|
||||||
|
<property name="prefix" value="/WEB-INF/view/" />
|
||||||
|
<property name="suffix" value=".html" />
|
||||||
|
<property name="templateMode" value="HTML" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="templateEngine"
|
||||||
|
class="org.thymeleaf.spring4.SpringTemplateEngine">
|
||||||
|
<property name="templateResolver" ref="templateResolver" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
|
||||||
|
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
|
||||||
|
<property name="templateEngine" ref="templateEngine" />
|
||||||
|
<property name="order" value="1" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
|
@ -40,6 +40,13 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.awaitility</groupId>
|
||||||
|
<artifactId>awaitility</artifactId>
|
||||||
|
<version>${awaitility.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
@ -69,6 +76,7 @@
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<vavr.version>0.9.0</vavr.version>
|
<vavr.version>0.9.0</vavr.version>
|
||||||
<junit.version>4.12</junit.version>
|
<junit.version>4.12</junit.version>
|
||||||
|
<awaitility.version>3.0.0</awaitility.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
package com.baeldung.vavr.future;
|
||||||
|
|
||||||
|
import static io.vavr.API.$;
|
||||||
|
import static io.vavr.API.Case;
|
||||||
|
import static io.vavr.API.Match;
|
||||||
|
import static io.vavr.Predicates.exists;
|
||||||
|
import static io.vavr.Predicates.forAll;
|
||||||
|
import static org.awaitility.Awaitility.await;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import io.vavr.collection.List;
|
||||||
|
import io.vavr.concurrent.Future;
|
||||||
|
|
||||||
|
public class FutureUnitTest {
|
||||||
|
|
||||||
|
private final String SUCCESS = "Success";
|
||||||
|
private final String FAILURE = "Failure";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenFunctionReturnInteger_WhenCallWithFuture_ShouldReturnFunctionValue() {
|
||||||
|
Future<Integer> future = Future.of(() -> 1);
|
||||||
|
|
||||||
|
assertEquals(1, future.get()
|
||||||
|
.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenFunctionGetRemoteHttpResourceAsString_WhenCallSuccessWithFuture_ShouldReturnContentValueAsString() {
|
||||||
|
String url = "http://resource";
|
||||||
|
String content = "Content from " + url;
|
||||||
|
Future<String> future = Future.of(() -> getResource(url));
|
||||||
|
|
||||||
|
assertEquals(content, future.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenFunctionThrowException_WhenCallWithFuture_ShouldReturnFailure() {
|
||||||
|
Future<String> future = Future.of(() -> getResourceThrowException(""));
|
||||||
|
future.await();
|
||||||
|
|
||||||
|
assertTrue(future.isFailure());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAFutureReturnZero_WhenCheckFutureWithExistEvenValue_ShouldReturnRight() {
|
||||||
|
Future<Integer> future = Future.of(() -> 2);
|
||||||
|
boolean result = future.exists(i -> i % 2 == 0);
|
||||||
|
|
||||||
|
assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenFunction_WhenCallWithFutureAndRegisterConsumerForSuccess_ShouldCallConsumerToStoreValue() {
|
||||||
|
final int[] store = new int[] { 0 };
|
||||||
|
Future<Integer> future = Future.of(() -> 1);
|
||||||
|
future.onSuccess(i -> {
|
||||||
|
store[0] = i;
|
||||||
|
});
|
||||||
|
await().until(() -> store[0] == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenFunctionThrowException_WhenCallWithFutureAndRegisterConsumerForFailer_ShouldCallConsumerToStoreException() {
|
||||||
|
final Throwable[] store = new Throwable[] { null };
|
||||||
|
Future<String> future = Future.of(() -> getResourceThrowException(""));
|
||||||
|
future.onFailure(err -> store[0] = err);
|
||||||
|
await().until(() -> RuntimeException.class.isInstance(store[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAFuture_WhenAddAndThenConsumer_ShouldCallConsumerWithResultOfFutureAction() {
|
||||||
|
int[] store1 = new int[1];
|
||||||
|
int[] store2 = new int[1];
|
||||||
|
Future<Integer> future = Future.of(() -> 1);
|
||||||
|
Future<Integer> andThenFuture = future.andThen(i -> store1[0] = i.get() + 1)
|
||||||
|
.andThen(i -> store2[0] = store1[0] + 1);
|
||||||
|
andThenFuture.await();
|
||||||
|
|
||||||
|
assertEquals(2, store1[0]);
|
||||||
|
assertEquals(3, store2[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAFailureFuture_WhenCallOrElseFunction_ShouldReturnNewFuture() {
|
||||||
|
Future<Integer> future = Future.failed(new RuntimeException());
|
||||||
|
Future<Integer> future2 = future.orElse(Future.of(() -> 2));
|
||||||
|
|
||||||
|
assertEquals(2, future2.get()
|
||||||
|
.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CancellationException.class)
|
||||||
|
public void givenAFuture_WhenCallCancel_ShouldReturnCancellationException() {
|
||||||
|
long waitTime = 1000;
|
||||||
|
Future<Integer> future = Future.of(() -> {
|
||||||
|
Thread.sleep(waitTime);
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
future.cancel();
|
||||||
|
future.await();
|
||||||
|
future.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAFuture_WhenCallFallBackWithSuccessFuture_ShouldReturnFutureResult() {
|
||||||
|
String expectedResult = "take this";
|
||||||
|
Future<String> future = Future.of(() -> expectedResult);
|
||||||
|
Future<String> secondFuture = Future.of(() -> "take that");
|
||||||
|
Future<String> futureResult = future.fallbackTo(secondFuture);
|
||||||
|
futureResult.await();
|
||||||
|
|
||||||
|
assertEquals(expectedResult, futureResult.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAFuture_WhenCallFallBackWithFailureFuture_ShouldReturnValueOfFallBackFuture() {
|
||||||
|
String expectedResult = "take that";
|
||||||
|
Future<String> future = Future.failed(new RuntimeException());
|
||||||
|
Future<String> fallbackFuture = Future.of(() -> expectedResult);
|
||||||
|
Future<String> futureResult = future.fallbackTo(fallbackFuture);
|
||||||
|
futureResult.await();
|
||||||
|
|
||||||
|
assertEquals(expectedResult, futureResult.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenGetResourceWithFuture_WhenWaitAndMatchWithPredicate_ShouldReturnSuccess() {
|
||||||
|
String url = "http://resource";
|
||||||
|
Future<String> future = Future.of(() -> getResource(url));
|
||||||
|
future.await();
|
||||||
|
String s = Match(future).of(Case($(future0 -> future0.isSuccess()), SUCCESS), Case($(), FAILURE));
|
||||||
|
|
||||||
|
assertEquals(SUCCESS, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAFailedFuture_WhenWaitAndMatchWithPredicateCheckSuccess_ShouldReturnFailed() {
|
||||||
|
Future<Integer> future = Future.failed(new RuntimeException());
|
||||||
|
future.await();
|
||||||
|
String s = Match(future).of(Case($(future0 -> future0.isSuccess()), SUCCESS), Case($(), FAILURE));
|
||||||
|
|
||||||
|
assertEquals(FAILURE, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAFuture_WhenMatchWithFuturePredicate_ShouldReturnSuccess() {
|
||||||
|
Future<Integer> future = Future.of(() -> {
|
||||||
|
Thread.sleep(10);
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
Predicate<Future<Integer>> predicate = f -> f.exists(i -> i % 2 == 1);
|
||||||
|
String s = Match(future).of(Case($(predicate), "Even"), Case($(), "Odd"));
|
||||||
|
|
||||||
|
assertEquals("Even", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAListOfFutureReturnFist3Integers_WhenMatchWithExistEvenNumberPredicate_ShouldReturnSuccess() {
|
||||||
|
List<Future<Integer>> futures = getFutureOfFirst3Number();
|
||||||
|
Predicate<Future<Integer>> predicate0 = future -> future.exists(i -> i % 2 == 0);
|
||||||
|
String s = Match(futures).of(Case($(exists(predicate0)), "Even"), Case($(), "Odd"));
|
||||||
|
|
||||||
|
assertEquals("Even", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAListOfFutureReturnFist3Integers_WhenMatchWithForAllNumberBiggerThanZeroPredicate_ShouldReturnSuccess() {
|
||||||
|
List<Future<Integer>> futures = getFutureOfFirst3Number();
|
||||||
|
Predicate<Future<Integer>> predicate0 = future -> future.exists(i -> i > 0);
|
||||||
|
String s = Match(futures).of(Case($(forAll(predicate0)), "Positive numbers"), Case($(), "None"));
|
||||||
|
|
||||||
|
assertEquals("Positive numbers", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenAListOfFutureReturnFist3Integers_WhenMatchWithForAllNumberSmallerThanZeroPredicate_ShouldReturnFailed() {
|
||||||
|
List<Future<Integer>> futures = getFutureOfFirst3Number();
|
||||||
|
Predicate<Future<Integer>> predicate0 = future -> future.exists(i -> i < 0);
|
||||||
|
String s = Match(futures).of(Case($(forAll(predicate0)), "Negative numbers"), Case($(), "None"));
|
||||||
|
|
||||||
|
assertEquals("None", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getResource(String url) throws InterruptedException {
|
||||||
|
Thread.sleep(10);
|
||||||
|
return "Content from " + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getResourceThrowException(String url) {
|
||||||
|
throw new RuntimeException("Exception when get resource " + url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Future<Integer>> getFutureOfFirst3Number() {
|
||||||
|
List<Future<Integer>> futures = List.of(Future.of(() -> 1), Future.of(() -> 2), Future.of(() -> 3));
|
||||||
|
return futures;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue