Merge branch 'master' of https://github.com/eugenp/tutorials
This commit is contained in:
commit
f6bced487a
|
@ -0,0 +1,59 @@
|
|||
package com.baeldung.algorithms.prime;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class PrimeGenerator {
|
||||
public static List<Integer> sieveOfEratosthenes(int n) {
|
||||
final boolean prime[] = new boolean[n + 1];
|
||||
Arrays.fill(prime, true);
|
||||
|
||||
for (int p = 2; p * p <= n; p++) {
|
||||
if (prime[p]) {
|
||||
for (int i = p * 2; i <= n; i += p)
|
||||
prime[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
final List<Integer> primes = new LinkedList<>();
|
||||
for (int i = 2; i <= n; i++) {
|
||||
if (prime[i])
|
||||
primes.add(i);
|
||||
}
|
||||
return primes;
|
||||
}
|
||||
|
||||
public static List<Integer> primeNumbersBruteForce(int max) {
|
||||
final List<Integer> primeNumbers = new LinkedList<Integer>();
|
||||
for (int i = 2; i <= max; i++) {
|
||||
if (isPrimeBruteForce(i)) {
|
||||
primeNumbers.add(i);
|
||||
}
|
||||
}
|
||||
return primeNumbers;
|
||||
}
|
||||
|
||||
private static boolean isPrimeBruteForce(int x) {
|
||||
for (int i = 2; i < x; i++) {
|
||||
if (x % i == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<Integer> primeNumbersTill(int max) {
|
||||
return IntStream.rangeClosed(2, max)
|
||||
.filter(x -> isPrime(x))
|
||||
.boxed()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static boolean isPrime(int x) {
|
||||
return IntStream.rangeClosed(2, (int) (Math.sqrt(x)))
|
||||
.allMatch(n -> x % n != 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.algorithms.prime;
|
||||
|
||||
import static com.baeldung.algorithms.prime.PrimeGenerator.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class PrimeGeneratorTest {
|
||||
@Test
|
||||
public void whenBruteForced_returnsSuccessfully() {
|
||||
final List<Integer> primeNumbers = primeNumbersBruteForce(20);
|
||||
assertEquals(Arrays.asList(new Integer[] { 2, 3, 5, 7, 11, 13, 17, 19 }), primeNumbers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOptimized_returnsSuccessfully() {
|
||||
final List<Integer> primeNumbers = primeNumbersTill(20);
|
||||
assertEquals(Arrays.asList(new Integer[] { 2, 3, 5, 7, 11, 13, 17, 19 }), primeNumbers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSieveOfEratosthenes_returnsSuccessfully() {
|
||||
final List<Integer> primeNumbers = sieveOfEratosthenes(20);
|
||||
assertEquals(Arrays.asList(new Integer[] { 2, 3, 5, 7, 11, 13, 17, 19 }), primeNumbers);
|
||||
}
|
||||
}
|
|
@ -40,14 +40,14 @@ public class CasSecuredAppApplication {
|
|||
@Primary
|
||||
public AuthenticationEntryPoint authenticationEntryPoint(ServiceProperties sP) {
|
||||
CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
|
||||
entryPoint.setLoginUrl("https://localhost:8443/cas/login");
|
||||
entryPoint.setLoginUrl("https://localhost:6443/cas/login");
|
||||
entryPoint.setServiceProperties(sP);
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TicketValidator ticketValidator() {
|
||||
return new Cas30ServiceTicketValidator("https://localhost:8443/cas");
|
||||
return new Cas30ServiceTicketValidator("https://localhost:6443/cas");
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -71,7 +71,7 @@ public class CasSecuredAppApplication {
|
|||
@Bean
|
||||
public LogoutFilter logoutFilter() {
|
||||
LogoutFilter logoutFilter = new LogoutFilter(
|
||||
"https://localhost:8443/cas/logout", securityContextLogoutHandler());
|
||||
"https://localhost:6443/cas/logout", securityContextLogoutHandler());
|
||||
logoutFilter.setFilterProcessesUrl("/logout/cas");
|
||||
return logoutFilter;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class CasSecuredAppApplication {
|
|||
@Bean
|
||||
public SingleSignOutFilter singleSignOutFilter() {
|
||||
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
|
||||
singleSignOutFilter.setCasServerUrlPrefix("https://localhost:8443/cas");
|
||||
singleSignOutFilter.setCasServerUrlPrefix("https://localhost:6443/cas");
|
||||
singleSignOutFilter.setIgnoreInitConfiguration(true);
|
||||
return singleSignOutFilter;
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -2,9 +2,9 @@
|
|||
# CAS Server Context Configuration
|
||||
#
|
||||
server.context-path=/cas
|
||||
server.port=8443
|
||||
server.port=6443
|
||||
|
||||
server.ssl.key-store=file:/etc/cas/thekeystore
|
||||
server.ssl.key-store=classpath:/etc/cas/thekeystore
|
||||
server.ssl.key-store-password=changeit
|
||||
server.ssl.key-password=changeit
|
||||
# server.ssl.ciphers=
|
||||
|
@ -40,6 +40,12 @@ spring.http.encoding.charset=UTF-8
|
|||
spring.http.encoding.enabled=true
|
||||
spring.http.encoding.force=true
|
||||
|
||||
##
|
||||
#CAS CONFIG LOCATION
|
||||
#
|
||||
cas.standalone.config=classpath:/etc/cas/config
|
||||
|
||||
|
||||
##
|
||||
# CAS Cloud Bus Configuration
|
||||
#
|
||||
|
@ -82,6 +88,7 @@ spring.thymeleaf.mode=HTML
|
|||
# CAS Log4j Configuration
|
||||
#
|
||||
# logging.config=file:/etc/cas/log4j2.xml
|
||||
|
||||
server.context-parameters.isLog4jAutoInitializationDisabled=true
|
||||
|
||||
##
|
||||
|
@ -104,9 +111,10 @@ cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.MySQLDialect
|
|||
cas.authn.jdbc.query[0].user=root
|
||||
cas.authn.jdbc.query[0].password=
|
||||
cas.authn.jdbc.query[0].ddlAuto=none
|
||||
cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver
|
||||
#cas.authn.jdbc.query[0].driverClass=com.mysql.jdbc.Driver
|
||||
cas.authn.jdbc.query[0].driverClass=com.mysql.cj.jdbc.Driver
|
||||
cas.authn.jdbc.query[0].fieldPassword=password
|
||||
cas.authn.jdbc.query[0].passwordEncoder.type=BCRYPT
|
||||
cas.authn.jdbc.query[0].passwordEncoder.type=NONE
|
||||
|
||||
|
||||
##
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
cas.server.name: https://localhost:8443
|
||||
cas.server.prefix: https://localhost:8443/cas
|
||||
cas.server.name: https://localhost:6443
|
||||
cas.server.prefix: https://localhost:643/cas
|
||||
|
||||
cas.adminPagesSecurity.ip=127\.0\.0\.1
|
||||
|
||||
logging.config: file:/etc/cas/config/log4j2.xml
|
||||
|
||||
cas.serviceRegistry.initFromJson=true
|
||||
cas.serviceRegistry.config.location=classpath:/services
|
||||
|
||||
cas.authn.accept.users=
|
||||
cas.authn.accept.name=
|
||||
|
||||
|
||||
#CAS Database Authentication Property
|
||||
|
||||
# cas.authn.jdbc.query[0].healthQuery=
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
info:
|
||||
description: CAS Configuration
|
|
@ -0,0 +1,7 @@
|
|||
cas.server.name: https://cas.example.org:8443
|
||||
cas.server.prefix: https://cas.example.org:8443/cas
|
||||
|
||||
cas.adminPagesSecurity.ip=127\.0\.0\.1
|
||||
|
||||
logging.config: file:/etc/cas/config/log4j2.xml
|
||||
# cas.serviceRegistry.config.location: classpath:/services
|
|
@ -0,0 +1,117 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!-- Specify the refresh internal in seconds. -->
|
||||
<Configuration monitorInterval="5" packages="org.apereo.cas.logging">
|
||||
<Properties>
|
||||
<!--
|
||||
Default log directory is the current directory but that can be overridden with -Dcas.log.dir=<logdir>
|
||||
Or you can change this property to a new default
|
||||
-->
|
||||
<Property name="cas.log.dir" >.</Property>
|
||||
<!-- To see more CAS specific logging, adjust this property to info or debug or run server with -Dcas.log.leve=debug -->
|
||||
<Property name="cas.log.level" >warn</Property>
|
||||
</Properties>
|
||||
<Appenders>
|
||||
<Console name="console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d %p [%c] - <%m>%n"/>
|
||||
</Console>
|
||||
<RollingFile name="file" fileName="${sys:cas.log.dir}/cas.log" append="true"
|
||||
filePattern="${sys:cas.log.dir}/cas-%d{yyyy-MM-dd-HH}-%i.log">
|
||||
<PatternLayout pattern="%d %p [%c] - <%m>%n"/>
|
||||
<Policies>
|
||||
<OnStartupTriggeringPolicy />
|
||||
<SizeBasedTriggeringPolicy size="10 MB"/>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
</Policies>
|
||||
</RollingFile>
|
||||
<RollingFile name="auditlogfile" fileName="${sys:cas.log.dir}/cas_audit.log" append="true"
|
||||
filePattern="${sys:cas.log.dir}/cas_audit-%d{yyyy-MM-dd-HH}-%i.log">
|
||||
<PatternLayout pattern="%d %p [%c] - %m%n"/>
|
||||
<Policies>
|
||||
<OnStartupTriggeringPolicy />
|
||||
<SizeBasedTriggeringPolicy size="10 MB"/>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
</Policies>
|
||||
</RollingFile>
|
||||
|
||||
<RollingFile name="perfFileAppender" fileName="${sys:cas.log.dir}/perfStats.log" append="true"
|
||||
filePattern="${sys:cas.log.dir}/perfStats-%d{yyyy-MM-dd-HH}-%i.log">
|
||||
<PatternLayout pattern="%m%n"/>
|
||||
<Policies>
|
||||
<OnStartupTriggeringPolicy />
|
||||
<SizeBasedTriggeringPolicy size="10 MB"/>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
</Policies>
|
||||
</RollingFile>
|
||||
|
||||
<CasAppender name="casAudit">
|
||||
<AppenderRef ref="auditlogfile" />
|
||||
</CasAppender>
|
||||
<CasAppender name="casFile">
|
||||
<AppenderRef ref="file" />
|
||||
</CasAppender>
|
||||
<CasAppender name="casConsole">
|
||||
<AppenderRef ref="console" />
|
||||
</CasAppender>
|
||||
<CasAppender name="casPerf">
|
||||
<AppenderRef ref="perfFileAppender" />
|
||||
</CasAppender>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<!-- If adding a Logger with level set higher than warn, make category as selective as possible -->
|
||||
<!-- Loggers inherit appenders from Root Logger unless additivity is false -->
|
||||
<AsyncLogger name="org.apereo" level="${sys:cas.log.level}" includeLocation="true"/>
|
||||
<AsyncLogger name="org.apereo.services.persondir" level="${sys:cas.log.level}" includeLocation="true"/>
|
||||
<AsyncLogger name="org.apereo.cas.web.flow" level="info" includeLocation="true"/>
|
||||
<AsyncLogger name="org.apache" level="warn" />
|
||||
<AsyncLogger name="org.apache.http" level="error" />
|
||||
<AsyncLogger name="org.springframework" level="warn" />
|
||||
<AsyncLogger name="org.springframework.cloud.server" level="warn" />
|
||||
<AsyncLogger name="org.springframework.cloud.client" level="warn" />
|
||||
<AsyncLogger name="org.springframework.cloud.bus" level="warn" />
|
||||
<AsyncLogger name="org.springframework.aop" level="warn" />
|
||||
<AsyncLogger name="org.springframework.boot" level="warn" />
|
||||
<AsyncLogger name="org.springframework.boot.actuate.autoconfigure" level="warn" />
|
||||
<AsyncLogger name="org.springframework.webflow" level="warn" />
|
||||
<AsyncLogger name="org.springframework.session" level="warn" />
|
||||
<AsyncLogger name="org.springframework.amqp" level="error" />
|
||||
<AsyncLogger name="org.springframework.integration" level="warn" />
|
||||
<AsyncLogger name="org.springframework.messaging" level="warn" />
|
||||
<AsyncLogger name="org.springframework.web" level="warn" />
|
||||
<AsyncLogger name="org.springframework.orm.jpa" level="warn" />
|
||||
<AsyncLogger name="org.springframework.scheduling" level="warn" />
|
||||
<AsyncLogger name="org.springframework.context.annotation" level="error" />
|
||||
<AsyncLogger name="org.springframework.boot.devtools" level="error" />
|
||||
<AsyncLogger name="org.springframework.web.socket" level="warn" />
|
||||
<AsyncLogger name="org.thymeleaf" level="warn" />
|
||||
<AsyncLogger name="org.pac4j" level="warn" />
|
||||
<AsyncLogger name="org.opensaml" level="warn"/>
|
||||
<AsyncLogger name="net.sf.ehcache" level="warn" />
|
||||
<AsyncLogger name="com.couchbase" level="warn" includeLocation="true"/>
|
||||
<AsyncLogger name="com.ryantenney.metrics" level="warn" />
|
||||
<AsyncLogger name="net.jradius" level="warn" />
|
||||
<AsyncLogger name="org.openid4java" level="warn" />
|
||||
<AsyncLogger name="org.ldaptive" level="warn" />
|
||||
<AsyncLogger name="com.hazelcast" level="warn" />
|
||||
<AsyncLogger name="org.jasig.spring" level="warn" />
|
||||
|
||||
<!-- Log perf stats only to perfStats.log -->
|
||||
<AsyncLogger name="perfStatsLogger" level="info" additivity="false" includeLocation="true">
|
||||
<AppenderRef ref="casPerf"/>
|
||||
</AsyncLogger>
|
||||
|
||||
<!-- Log audit to all root appenders, and also to audit log (additivity is not false) -->
|
||||
<AsyncLogger name="org.apereo.inspektr.audit.support" level="info" includeLocation="true" >
|
||||
<AppenderRef ref="casAudit"/>
|
||||
</AsyncLogger>
|
||||
|
||||
<!-- All Loggers inherit appenders specified here, unless additivity="false" on the Logger -->
|
||||
<AsyncRoot level="warn">
|
||||
<AppenderRef ref="casFile"/>
|
||||
<!--
|
||||
For deployment to an application server running as service,
|
||||
delete the casConsole appender below
|
||||
-->
|
||||
<AppenderRef ref="casConsole"/>
|
||||
</AsyncRoot>
|
||||
</Loggers>
|
||||
</Configuration>
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,59 @@
|
|||
package com.baeldung.prime;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class PrimeGenerator {
|
||||
public static List<Integer> sieveOfEratosthenes(int n) {
|
||||
final boolean prime[] = new boolean[n + 1];
|
||||
Arrays.fill(prime, true);
|
||||
|
||||
for (int p = 2; p * p <= n; p++) {
|
||||
if (prime[p]) {
|
||||
for (int i = p * 2; i <= n; i += p)
|
||||
prime[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
final List<Integer> primes = new LinkedList<>();
|
||||
for (int i = 2; i <= n; i++) {
|
||||
if (prime[i])
|
||||
primes.add(i);
|
||||
}
|
||||
return primes;
|
||||
}
|
||||
|
||||
public static List<Integer> primeNumbersBruteForce(int max) {
|
||||
final List<Integer> primeNumbers = new LinkedList<Integer>();
|
||||
for (int i = 2; i <= max; i++) {
|
||||
if (isPrimeBruteForce(i)) {
|
||||
primeNumbers.add(i);
|
||||
}
|
||||
}
|
||||
return primeNumbers;
|
||||
}
|
||||
|
||||
private static boolean isPrimeBruteForce(int x) {
|
||||
for (int i = 2; i < x; i++) {
|
||||
if (x % i == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<Integer> primeNumbersTill(int max) {
|
||||
return IntStream.rangeClosed(2, max)
|
||||
.filter(x -> isPrime(x))
|
||||
.boxed()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static boolean isPrime(int x) {
|
||||
return IntStream.rangeClosed(2, (int) (Math.sqrt(x)))
|
||||
.allMatch(n -> x % n != 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.prime;
|
||||
|
||||
import static com.baeldung.prime.PrimeGenerator.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class PrimeGeneratorTest {
|
||||
@Test
|
||||
public void whenBruteForced_returnsSuccessfully() {
|
||||
final List<Integer> primeNumbers = primeNumbersBruteForce(20);
|
||||
assertEquals(Arrays.asList(new Integer[] { 2, 3, 5, 7, 11, 13, 17, 19 }), primeNumbers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOptimized_returnsSuccessfully() {
|
||||
final List<Integer> primeNumbers = primeNumbersTill(20);
|
||||
assertEquals(Arrays.asList(new Integer[] { 2, 3, 5, 7, 11, 13, 17, 19 }), primeNumbers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSieveOfEratosthenes_returnsSuccessfully() {
|
||||
final List<Integer> primeNumbers = sieveOfEratosthenes(20);
|
||||
assertEquals(Arrays.asList(new Integer[] { 2, 3, 5, 7, 11, 13, 17, 19 }), primeNumbers);
|
||||
}
|
||||
}
|
|
@ -3,8 +3,18 @@ package com.baeldung.concurrent.daemon;
|
|||
public class NewThread extends Thread {
|
||||
|
||||
public void run() {
|
||||
while (true)
|
||||
for (int i = 0; i < 10; i++)
|
||||
System.out.println("New Thread is running...");
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (true) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
System.out.println("New Thread is running..." + i);
|
||||
}
|
||||
|
||||
// prevent the Thread to run forever. It will finish it's execution after 2 seconds
|
||||
if (System.currentTimeMillis() - startTime > 2000) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package com.baeldung.concurrent.executorservice;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class DelayedCallable implements Callable<String> {
|
||||
|
||||
private String name;
|
||||
private long period;
|
||||
private CountDownLatch latch;
|
||||
|
||||
public DelayedCallable(String name, long period, CountDownLatch latch) {
|
||||
this(name, period);
|
||||
this.latch = latch;
|
||||
}
|
||||
|
||||
public DelayedCallable(String name, long period) {
|
||||
this.name = name;
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public String call() {
|
||||
|
||||
try {
|
||||
Thread.sleep(period);
|
||||
|
||||
if (latch != null) {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
} catch (InterruptedException ex) {
|
||||
// handle exception
|
||||
ex.printStackTrace();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
|
@ -3,11 +3,13 @@ package com.baeldung.concurrent.daemon;
|
|||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DaemonThreadTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void whenCallIsDaemon_thenCorrect() {
|
||||
NewThread daemonThread = new NewThread();
|
||||
NewThread userThread = new NewThread();
|
||||
|
@ -20,6 +22,7 @@ public class DaemonThreadTest {
|
|||
}
|
||||
|
||||
@Test(expected = IllegalThreadStateException.class)
|
||||
@Ignore
|
||||
public void givenUserThread_whenSetDaemonWhileRunning_thenIllegalThreadStateException() {
|
||||
NewThread daemonThread = new NewThread();
|
||||
daemonThread.start();
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
package com.baeldung.concurrent.executorservice;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class WaitingForThreadsToFinishTest {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WaitingForThreadsToFinishTest.class);
|
||||
private final static ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10);
|
||||
|
||||
public void awaitTerminationAfterShutdown(ExecutorService threadPool) {
|
||||
threadPool.shutdown();
|
||||
try {
|
||||
if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
|
||||
threadPool.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
threadPool.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleThreads_whenUsingCountDownLatch_thenMainShoudWaitForAllToFinish() {
|
||||
|
||||
ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10);
|
||||
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// create a CountDownLatch that waits for the 2 threads to finish
|
||||
CountDownLatch latch = new CountDownLatch(2);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
WORKER_THREAD_POOL.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
latch.countDown();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// wait for the latch to be decremented by the two threads
|
||||
latch.await();
|
||||
|
||||
long processingTime = System.currentTimeMillis() - startTime;
|
||||
assertTrue(processingTime >= 1000);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
awaitTerminationAfterShutdown(WORKER_THREAD_POOL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleThreads_whenInvokeAll_thenMainThreadShouldWaitForAllToFinish() {
|
||||
|
||||
ExecutorService WORKER_THREAD_POOL = Executors.newFixedThreadPool(10);
|
||||
|
||||
List<Callable<String>> callables = Arrays.asList(
|
||||
new DelayedCallable("fast thread", 100),
|
||||
new DelayedCallable("slow thread", 3000));
|
||||
|
||||
try {
|
||||
long startProcessingTime = System.currentTimeMillis();
|
||||
List<Future<String>> futures = WORKER_THREAD_POOL.invokeAll(callables);
|
||||
|
||||
awaitTerminationAfterShutdown(WORKER_THREAD_POOL);
|
||||
|
||||
try {
|
||||
WORKER_THREAD_POOL.submit(new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
fail("This thread should have been rejected !");
|
||||
Thread.sleep(1000000);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException ex) {
|
||||
//
|
||||
}
|
||||
|
||||
long totalProcessingTime = System.currentTimeMillis() - startProcessingTime;
|
||||
assertTrue(totalProcessingTime >= 3000);
|
||||
|
||||
String firstThreadResponse = futures.get(0)
|
||||
.get();
|
||||
assertTrue("First response should be from the fast thread", "fast thread".equals(firstThreadResponse));
|
||||
|
||||
String secondThreadResponse = futures.get(1)
|
||||
.get();
|
||||
assertTrue("Last response should be from the slow thread", "slow thread".equals(secondThreadResponse));
|
||||
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleThreads_whenUsingCompletionService_thenMainThreadShouldWaitForAllToFinish() {
|
||||
|
||||
CompletionService<String> service = new ExecutorCompletionService<>(WORKER_THREAD_POOL);
|
||||
|
||||
List<Callable<String>> callables = Arrays.asList(
|
||||
new DelayedCallable("fast thread", 100),
|
||||
new DelayedCallable("slow thread", 3000));
|
||||
|
||||
for (Callable<String> callable : callables) {
|
||||
service.submit(callable);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
long startProcessingTime = System.currentTimeMillis();
|
||||
|
||||
Future<String> future = service.take();
|
||||
String firstThreadResponse = future.get();
|
||||
long totalProcessingTime = System.currentTimeMillis() - startProcessingTime;
|
||||
|
||||
assertTrue("First response should be from the fast thread", "fast thread".equals(firstThreadResponse));
|
||||
assertTrue(totalProcessingTime >= 100 && totalProcessingTime < 1000);
|
||||
LOG.debug("Thread finished after: " + totalProcessingTime + " milliseconds");
|
||||
|
||||
future = service.take();
|
||||
String secondThreadResponse = future.get();
|
||||
totalProcessingTime = System.currentTimeMillis() - startProcessingTime;
|
||||
|
||||
assertTrue("Last response should be from the slow thread", "slow thread".equals(secondThreadResponse));
|
||||
assertTrue(totalProcessingTime >= 3000 && totalProcessingTime < 4000);
|
||||
LOG.debug("Thread finished after: " + totalProcessingTime + " milliseconds");
|
||||
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
awaitTerminationAfterShutdown(WORKER_THREAD_POOL);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleThreads_whenUsingCompletableFutures_thenMainThreadShouldWaitForAllToFinish() {
|
||||
|
||||
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
|
||||
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "Hello";
|
||||
});
|
||||
|
||||
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
|
||||
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "Beautiful";
|
||||
});
|
||||
|
||||
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "World";
|
||||
});
|
||||
|
||||
long startProcessingTime = System.currentTimeMillis();
|
||||
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2, future3);
|
||||
combinedFuture.join();
|
||||
|
||||
long totalProcessingTime = System.currentTimeMillis() - startProcessingTime;
|
||||
assertTrue(totalProcessingTime >= 5000 && totalProcessingTime < 6000);
|
||||
|
||||
LOG.debug("Responses from all threads are available after " + totalProcessingTime + " milliseconds");
|
||||
|
||||
try {
|
||||
String thread1Response = future1.get();
|
||||
assertTrue(thread1Response.equals("Hello"));
|
||||
|
||||
String thread2Response = future2.get();
|
||||
assertTrue(thread2Response.equals("Beautiful"));
|
||||
|
||||
String thread3Response = future3.get();
|
||||
assertTrue(thread3Response.equals("World"));
|
||||
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
awaitTerminationAfterShutdown(WORKER_THREAD_POOL);
|
||||
}
|
||||
}
|
|
@ -1,24 +1,21 @@
|
|||
package com.baeldung.concurrent.runnable;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class RunnableVsThreadTest {
|
||||
public class RunnableVsThreadLiveTest {
|
||||
|
||||
private static Logger log =
|
||||
LoggerFactory.getLogger(RunnableVsThreadTest.class);
|
||||
LoggerFactory.getLogger(RunnableVsThreadLiveTest.class);
|
||||
|
||||
private static ExecutorService executorService;
|
||||
|
||||
|
@ -77,9 +74,7 @@ public class RunnableVsThreadTest {
|
|||
public void givenACallableAsLambda_whenSubmitToES_thenResult()
|
||||
throws Exception {
|
||||
|
||||
Future<Integer> future = executorService.submit(() -> {
|
||||
return RandomUtils.nextInt(0, 100);
|
||||
});
|
||||
Future<Integer> future = executorService.submit(() -> RandomUtils.nextInt(0, 100));
|
||||
|
||||
log.info("Result from callable: {}", future.get());
|
||||
}
|
||||
|
@ -99,7 +94,7 @@ class SimpleThread extends Thread{
|
|||
|
||||
private String message;
|
||||
|
||||
public SimpleThread(String message) {
|
||||
SimpleThread(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
@ -116,7 +111,7 @@ class SimpleRunnable implements Runnable {
|
|||
|
||||
private String message;
|
||||
|
||||
public SimpleRunnable(String message) {
|
||||
SimpleRunnable(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
|
@ -114,4 +114,5 @@
|
|||
- [StringBuilder and StringBuffer in Java](http://www.baeldung.com/java-string-builder-string-buffer)
|
||||
- [Number of Digits in an Integer in Java](http://www.baeldung.com/java-number-of-digits-in-int)
|
||||
- [Proxy, Decorator, Adapter and Bridge Patterns](http://www.baeldung.com/java-structural-design-patterns)
|
||||
- [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin)
|
||||
|
||||
|
|
|
@ -216,6 +216,13 @@
|
|||
<artifactId>spring-web</artifactId>
|
||||
<version>4.3.4.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun</groupId>
|
||||
<artifactId>tools</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${java.home}/../lib/tools.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -249,7 +256,7 @@
|
|||
<exclude>**/*LongRunningUnitTest.java</exclude>
|
||||
<exclude>**/*ManualTest.java</exclude>
|
||||
</excludes>
|
||||
<testFailureIgnore>true</testFailureIgnore>
|
||||
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
package com.baeldung.breakcontinue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* @author Santosh
|
||||
*
|
||||
*/
|
||||
public class BreakContinue {
|
||||
|
||||
public static int unlabeledBreak() {
|
||||
String searchName = "Wilson";
|
||||
int counter = 0;
|
||||
List<String> names = Arrays.asList("John", "Peter", "Robert", "Wilson", "Anthony", "Donald", "Richard");
|
||||
|
||||
for (String name : names) {
|
||||
counter++;
|
||||
if (name.equalsIgnoreCase(searchName)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
public static int unlabeledBreakNestedLoops() {
|
||||
String searchName = "Wilson";
|
||||
int counter = 0;
|
||||
Map<String, List<String>> nameMap = new HashMap<>();
|
||||
nameMap.put("Grade1", Arrays.asList("John", "Peter", "Robert", "Wilson"));
|
||||
nameMap.put("Grade2", Arrays.asList("Anthony", "Donald", "Richard", "Arnold"));
|
||||
nameMap.put("Grade3", Arrays.asList("Wilson", "Michael", "Stephen", "Ryan"));
|
||||
|
||||
Iterator<Entry<String, List<String>>> iterator = nameMap.entrySet()
|
||||
.iterator();
|
||||
Entry<String, List<String>> entry = null;
|
||||
List<String> names = null;
|
||||
while (iterator.hasNext()) {
|
||||
entry = iterator.next();
|
||||
names = entry.getValue();
|
||||
for (String name : names) {
|
||||
if (name.equalsIgnoreCase(searchName)) {
|
||||
counter++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
public static int labeledBreak() {
|
||||
String searchName = "Wilson";
|
||||
int counter = 0;
|
||||
Map<String, List<String>> nameMap = new HashMap<>();
|
||||
nameMap.put("Grade1", Arrays.asList("John", "Peter", "Robert", "Wilson"));
|
||||
nameMap.put("Grade2", Arrays.asList("Anthony", "Donald", "Richard", "Arnold"));
|
||||
nameMap.put("Grade3", Arrays.asList("Wilson", "Michael", "Stephen", "Ryan"));
|
||||
|
||||
Iterator<Entry<String, List<String>>> iterator = nameMap.entrySet()
|
||||
.iterator();
|
||||
Entry<String, List<String>> entry = null;
|
||||
List<String> names = null;
|
||||
compare:
|
||||
while (iterator.hasNext()) {
|
||||
entry = iterator.next();
|
||||
names = entry.getValue();
|
||||
for (String name : names) {
|
||||
if (name.equalsIgnoreCase(searchName)) {
|
||||
counter++;
|
||||
break compare;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
public static int unlabeledContinue() {
|
||||
String searchName = "Wilson";
|
||||
int counter = 0;
|
||||
Map<String, List<String>> nameMap = new HashMap<>();
|
||||
nameMap.put("Grade1", Arrays.asList("John", "Wilson", "Robert", "Wilson"));
|
||||
nameMap.put("Grade2", Arrays.asList("Anthony", "Donald", "Wilson", "Arnold"));
|
||||
nameMap.put("Grade3", Arrays.asList("Wilson", "Michael", "Wilson", "Ryan"));
|
||||
|
||||
Iterator<Entry<String, List<String>>> iterator = nameMap.entrySet()
|
||||
.iterator();
|
||||
Entry<String, List<String>> entry = null;
|
||||
List<String> names = null;
|
||||
while (iterator.hasNext()) {
|
||||
entry = iterator.next();
|
||||
names = entry.getValue();
|
||||
for (String name : names) {
|
||||
if (!name.equalsIgnoreCase(searchName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
public static int labeledContinue() {
|
||||
String searchName = "Wilson";
|
||||
int counter = 0;
|
||||
Map<String, List<String>> nameMap = new HashMap<>();
|
||||
nameMap.put("Grade1", Arrays.asList("John", "Wilson", "Robert", "Wilson"));
|
||||
nameMap.put("Grade2", Arrays.asList("Anthony", "Donald", "Wilson", "Arnold"));
|
||||
nameMap.put("Grade3", Arrays.asList("Wilson", "Michael", "Wilson", "Ryan"));
|
||||
|
||||
Iterator<Entry<String, List<String>>> iterator = nameMap.entrySet()
|
||||
.iterator();
|
||||
Entry<String, List<String>> entry = null;
|
||||
List<String> names = null;
|
||||
compare:
|
||||
while (iterator.hasNext()) {
|
||||
entry = iterator.next();
|
||||
names = entry.getValue();
|
||||
for (String name : names) {
|
||||
if (name.equalsIgnoreCase(searchName)) {
|
||||
counter++;
|
||||
continue compare;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,8 @@ import java.util.Set;
|
|||
|
||||
public class EchoServer {
|
||||
|
||||
private static final String POISON_PILL = "POISON_PILL";
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
Selector selector = Selector.open();
|
||||
ServerSocketChannel serverSocket = ServerSocketChannel.open();
|
||||
|
@ -30,23 +32,36 @@ public class EchoServer {
|
|||
SelectionKey key = iter.next();
|
||||
|
||||
if (key.isAcceptable()) {
|
||||
SocketChannel client = serverSocket.accept();
|
||||
client.configureBlocking(false);
|
||||
client.register(selector, SelectionKey.OP_READ);
|
||||
register(selector, serverSocket);
|
||||
}
|
||||
|
||||
if (key.isReadable()) {
|
||||
SocketChannel client = (SocketChannel) key.channel();
|
||||
client.read(buffer);
|
||||
buffer.flip();
|
||||
client.write(buffer);
|
||||
buffer.clear();
|
||||
answerWithEcho(buffer, key);
|
||||
}
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void answerWithEcho(ByteBuffer buffer, SelectionKey key) throws IOException {
|
||||
SocketChannel client = (SocketChannel) key.channel();
|
||||
client.read(buffer);
|
||||
if (new String(buffer.array()).trim().equals(POISON_PILL)) {
|
||||
client.close();
|
||||
System.out.println("Not accepting client messages anymore");
|
||||
}
|
||||
|
||||
buffer.flip();
|
||||
client.write(buffer);
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
private static void register(Selector selector, ServerSocketChannel serverSocket) throws IOException {
|
||||
SocketChannel client = serverSocket.accept();
|
||||
client.configureBlocking(false);
|
||||
client.register(selector, SelectionKey.OP_READ);
|
||||
}
|
||||
|
||||
public static Process start() throws IOException, InterruptedException {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target({ElementType.PARAMETER})
|
||||
public @interface Positive {
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.*;
|
||||
import com.sun.tools.javac.api.BasicJavacTask;
|
||||
import com.sun.tools.javac.code.TypeTag;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.sun.tools.javac.util.List.nil;
|
||||
|
||||
/**
|
||||
* A {@link JavaCompiler javac} plugin which inserts {@code >= 0} checks into resulting {@code *.class} files
|
||||
* for numeric method parameters marked by {@link Positive}
|
||||
*/
|
||||
public class SampleJavacPlugin implements Plugin {
|
||||
|
||||
public static final String NAME = "MyPlugin";
|
||||
|
||||
private static Set<String> TARGET_TYPES = new HashSet<>(Arrays.asList(
|
||||
// Use only primitive types for simplicity
|
||||
byte.class.getName(), short.class.getName(), char.class.getName(),
|
||||
int.class.getName(), long.class.getName(), float.class.getName(), double.class.getName()));
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(JavacTask task, String... args) {
|
||||
Context context = ((BasicJavacTask) task).getContext();
|
||||
task.addTaskListener(new TaskListener() {
|
||||
@Override
|
||||
public void started(TaskEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finished(TaskEvent e) {
|
||||
if (e.getKind() != TaskEvent.Kind.PARSE) {
|
||||
return;
|
||||
}
|
||||
e.getCompilationUnit()
|
||||
.accept(new TreeScanner<Void, Void>() {
|
||||
@Override
|
||||
public Void visitMethod(MethodTree method, Void v) {
|
||||
List<VariableTree> parametersToInstrument = method.getParameters()
|
||||
.stream()
|
||||
.filter(SampleJavacPlugin.this::shouldInstrument)
|
||||
.collect(Collectors.toList());
|
||||
if (!parametersToInstrument.isEmpty()) {
|
||||
// There is a possible case that more than one argument is marked by @Positive,
|
||||
// as the checks are added to the method's body beginning, we process parameters RTL
|
||||
// to ensure correct order.
|
||||
Collections.reverse(parametersToInstrument);
|
||||
parametersToInstrument.forEach(p -> addCheck(method, p, context));
|
||||
}
|
||||
// There is a possible case that there is a nested class declared in a method's body,
|
||||
// hence, we want to proceed with method body AST as well.
|
||||
return super.visitMethod(method, v);
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean shouldInstrument(VariableTree parameter) {
|
||||
return TARGET_TYPES.contains(parameter.getType().toString())
|
||||
&& parameter.getModifiers().getAnnotations()
|
||||
.stream()
|
||||
.anyMatch(a -> Positive.class.getSimpleName().equals(a.getAnnotationType().toString()));
|
||||
}
|
||||
|
||||
private void addCheck(MethodTree method, VariableTree parameter, Context context) {
|
||||
JCTree.JCIf check = createCheck(parameter, context);
|
||||
JCTree.JCBlock body = (JCTree.JCBlock) method.getBody();
|
||||
body.stats = body.stats.prepend(check);
|
||||
}
|
||||
|
||||
private static JCTree.JCIf createCheck(VariableTree parameter, Context context) {
|
||||
TreeMaker factory = TreeMaker.instance(context);
|
||||
Names symbolsTable = Names.instance(context);
|
||||
|
||||
return factory.at(((JCTree) parameter).pos)
|
||||
.If(factory.Parens(createIfCondition(factory, symbolsTable, parameter)),
|
||||
createIfBlock(factory, symbolsTable, parameter),
|
||||
null);
|
||||
}
|
||||
|
||||
private static JCTree.JCBinary createIfCondition(TreeMaker factory, Names symbolsTable, VariableTree parameter) {
|
||||
Name parameterId = symbolsTable.fromString(parameter.getName().toString());
|
||||
return factory.Binary(JCTree.Tag.LE,
|
||||
factory.Ident(parameterId),
|
||||
factory.Literal(TypeTag.INT, 0));
|
||||
}
|
||||
|
||||
private static JCTree.JCBlock createIfBlock(TreeMaker factory, Names symbolsTable, VariableTree parameter) {
|
||||
String parameterName = parameter.getName().toString();
|
||||
Name parameterId = symbolsTable.fromString(parameterName);
|
||||
|
||||
String errorMessagePrefix = String.format("Argument '%s' of type %s is marked by @%s but got '",
|
||||
parameterName, parameter.getType(), Positive.class.getSimpleName());
|
||||
String errorMessageSuffix = "' for it";
|
||||
|
||||
return factory.Block(0, com.sun.tools.javac.util.List.of(
|
||||
factory.Throw(
|
||||
factory.NewClass(null, nil(),
|
||||
factory.Ident(symbolsTable.fromString(IllegalArgumentException.class.getSimpleName())),
|
||||
com.sun.tools.javac.util.List.of(factory.Binary(JCTree.Tag.PLUS,
|
||||
factory.Binary(JCTree.Tag.PLUS, factory.Literal(TypeTag.CLASS, errorMessagePrefix),
|
||||
factory.Ident(parameterId)),
|
||||
factory.Literal(TypeTag.CLASS, errorMessageSuffix))), null))));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
com.baeldung.javac.SampleJavacPlugin
|
|
@ -0,0 +1,39 @@
|
|||
package com.baeldung.breakcontinue;
|
||||
|
||||
import static com.baeldung.breakcontinue.BreakContinue.labeledBreak;
|
||||
import static com.baeldung.breakcontinue.BreakContinue.labeledContinue;
|
||||
import static com.baeldung.breakcontinue.BreakContinue.unlabeledBreak;
|
||||
import static com.baeldung.breakcontinue.BreakContinue.unlabeledBreakNestedLoops;
|
||||
import static com.baeldung.breakcontinue.BreakContinue.unlabeledContinue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class BreakContinueTest {
|
||||
|
||||
@Test
|
||||
public void whenUnlabeledBreak_ThenEqual() {
|
||||
assertEquals(4, unlabeledBreak());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUnlabeledBreakNestedLoops_ThenEqual() {
|
||||
assertEquals(2, unlabeledBreakNestedLoops());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenLabeledBreak_ThenEqual() {
|
||||
assertEquals(1, labeledBreak());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUnlabeledContinue_ThenEqual() {
|
||||
assertEquals(5, unlabeledContinue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenLabeledContinue_ThenEqual() {
|
||||
assertEquals(3, labeledContinue());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SampleJavacPluginIntegrationTest {
|
||||
|
||||
private static final String CLASS_TEMPLATE =
|
||||
"package com.baeldung.javac;\n" +
|
||||
"\n" +
|
||||
"public class Test {\n" +
|
||||
" public static %1$s service(@Positive %1$s i) {\n" +
|
||||
" return i;\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"";
|
||||
|
||||
private TestCompiler compiler = new TestCompiler();
|
||||
private TestRunner runner = new TestRunner();
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void givenInt_whenNegative_thenThrowsException() throws Throwable {
|
||||
compileAndRun(double.class,-1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void givenInt_whenZero_thenThrowsException() throws Throwable {
|
||||
compileAndRun(int.class,0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInt_whenPositive_thenSuccess() throws Throwable {
|
||||
assertEquals(1, compileAndRun(int.class, 1));
|
||||
}
|
||||
|
||||
private Object compileAndRun(Class<?> argumentType, Object argument) throws Throwable {
|
||||
String qualifiedClassName = "com.baeldung.javac.Test";
|
||||
byte[] byteCode = compiler.compile(qualifiedClassName, String.format(CLASS_TEMPLATE, argumentType.getName()));
|
||||
return runner.run(byteCode, qualifiedClassName, "service", new Class[] {argumentType}, argument);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
|
||||
/** Holds compiled byte code in a byte array */
|
||||
public class SimpleClassFile extends SimpleJavaFileObject {
|
||||
|
||||
private ByteArrayOutputStream out;
|
||||
|
||||
public SimpleClassFile(URI uri) {
|
||||
super(uri, Kind.CLASS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutputStream() throws IOException {
|
||||
return out = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
public byte[] getCompiledBinaries() {
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Adapts {@link SimpleClassFile} to the {@link JavaCompiler} */
|
||||
public class SimpleFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
|
||||
|
||||
private final List<SimpleClassFile> compiled = new ArrayList<>();
|
||||
|
||||
public SimpleFileManager(StandardJavaFileManager delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForOutput(Location location,
|
||||
String className,
|
||||
JavaFileObject.Kind kind,
|
||||
FileObject sibling)
|
||||
{
|
||||
SimpleClassFile result = new SimpleClassFile(URI.create("string://" + className));
|
||||
compiled.add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return compiled binaries processed by the current class
|
||||
*/
|
||||
public List<SimpleClassFile> getCompiled() {
|
||||
return compiled;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import java.net.URI;
|
||||
|
||||
/** Exposes given test source to the compiler. */
|
||||
public class SimpleSourceFile extends SimpleJavaFileObject {
|
||||
|
||||
private final String content;
|
||||
|
||||
public SimpleSourceFile(String qualifiedClassName, String testSource) {
|
||||
super(URI.create(String.format("file://%s%s",
|
||||
qualifiedClassName.replaceAll("\\.", "/"),
|
||||
Kind.SOURCE.extension)),
|
||||
Kind.SOURCE);
|
||||
content = testSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return content;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.ToolProvider;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
public class TestCompiler {
|
||||
public byte[] compile(String qualifiedClassName, String testSource) {
|
||||
StringWriter output = new StringWriter();
|
||||
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
SimpleFileManager fileManager = new SimpleFileManager(compiler.getStandardFileManager(
|
||||
null,
|
||||
null,
|
||||
null
|
||||
));
|
||||
List<SimpleSourceFile> compilationUnits = singletonList(new SimpleSourceFile(qualifiedClassName, testSource));
|
||||
List<String> arguments = new ArrayList<>();
|
||||
arguments.addAll(asList("-classpath", System.getProperty("java.class.path"),
|
||||
"-Xplugin:" + SampleJavacPlugin.NAME));
|
||||
JavaCompiler.CompilationTask task = compiler.getTask(output,
|
||||
fileManager,
|
||||
null,
|
||||
arguments,
|
||||
null,
|
||||
compilationUnits);
|
||||
task.call();
|
||||
return fileManager.getCompiled().iterator().next().getCompiledBinaries();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.javac;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TestRunner {
|
||||
|
||||
public Object run(byte[] byteCode,
|
||||
String qualifiedClassName,
|
||||
String methodName,
|
||||
Class<?>[] argumentTypes,
|
||||
Object... args)
|
||||
throws Throwable
|
||||
{
|
||||
ClassLoader classLoader = new ClassLoader() {
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
return defineClass(name, byteCode, 0, byteCode.length);
|
||||
}
|
||||
};
|
||||
Class<?> clazz;
|
||||
try {
|
||||
clazz = classLoader.loadClass(qualifiedClassName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Can't load compiled test class", e);
|
||||
}
|
||||
|
||||
Method method;
|
||||
try {
|
||||
method = clazz.getMethod(methodName, argumentTypes);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Can't find the 'main()' method in the compiled test class", e);
|
||||
}
|
||||
|
||||
try {
|
||||
return method.invoke(null, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package com.baeldung.stack;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.junit.Test;
|
||||
public class StackUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenStackIsCreated_thenItHasSize0() {
|
||||
Stack intStack = new Stack();
|
||||
assertEquals(0, intStack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStack_whenElementIsPushed_thenStackSizeisIncreased() {
|
||||
Stack intStack = new Stack();
|
||||
intStack.push(1);
|
||||
assertEquals(1, intStack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmptyStack_whenMultipleElementsArePushed_thenStackSizeisIncreased() {
|
||||
Stack intStack = new Stack();
|
||||
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
|
||||
boolean result = intStack.addAll(intList);
|
||||
assertTrue(result);
|
||||
assertEquals(7, intList.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenElementIsPoppedFromStack_thenElementIsRemovedAndSizeChanges() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
intStack.push(5);
|
||||
intStack.pop();
|
||||
assertTrue(intStack.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenElementIsPeeked_thenElementIsNotRemovedAndSizeDoesNotChange() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
intStack.push(5);
|
||||
intStack.peek();
|
||||
assertEquals(1, intStack.search(5));
|
||||
assertEquals(1, intStack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenElementIsOnStack_thenSearchReturnsItsDistanceFromTheTop() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
intStack.push(5);
|
||||
assertEquals(1, intStack.search(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenElementIsOnStack_thenIndexOfReturnsItsIndex() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
intStack.push(5);
|
||||
int indexOf = intStack.indexOf(5);
|
||||
assertEquals(0, indexOf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMultipleElementsAreOnStack_thenIndexOfReturnsLastElementIndex() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
intStack.push(5);
|
||||
intStack.push(5);
|
||||
intStack.push(5);
|
||||
int lastIndexOf = intStack.lastIndexOf(5);
|
||||
assertEquals(2, lastIndexOf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenElementOnStack_whenRemoveElementIsInvoked_thenElementIsRemoved() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
intStack.push(5);
|
||||
intStack.push(5);
|
||||
intStack.removeElement(5);
|
||||
assertEquals(1, intStack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenElementOnStack_whenRemoveElementAtIsInvoked_thenElementIsRemoved() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
intStack.push(5);
|
||||
intStack.push(7);
|
||||
intStack.removeElementAt(1);
|
||||
assertEquals(-1, intStack.search(7));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenElementsOnStack_whenRemoveAllElementsIsInvoked_thenAllElementsAreRemoved() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
intStack.push(5);
|
||||
intStack.push(7);
|
||||
intStack.removeAllElements();
|
||||
assertTrue(intStack.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenElementsOnStack_whenRemoveAllIsInvoked_thenAllElementsFromCollectionAreRemoved() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
|
||||
intStack.addAll(intList);
|
||||
intStack.add(500);
|
||||
intStack.removeAll(intList);
|
||||
assertEquals(1, intStack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenElementsOnStack_whenRemoveIfIsInvoked_thenAllElementsSatysfyingConditionAreRemoved() {
|
||||
Stack<Integer> intStack = new Stack();
|
||||
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
|
||||
intStack.addAll(intList);
|
||||
intStack.removeIf(element -> element < 6);
|
||||
assertEquals(2, intStack.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAnotherStackCreatedWhileTraversingStack_thenStacksAreEqual() {
|
||||
Stack<Integer> intStack = new Stack<>();
|
||||
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
|
||||
intStack.addAll(intList);
|
||||
ListIterator<Integer> it = intStack.listIterator();
|
||||
Stack<Integer> result = new Stack();
|
||||
while(it.hasNext()) {
|
||||
result.push(it.next());
|
||||
}
|
||||
|
||||
assertThat(result, equalTo(intStack));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package com.baeldung.string.formatter;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Formatter;
|
||||
import java.util.GregorianCalendar;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
|
||||
public class StringFormatterExampleTests {
|
||||
|
||||
@Test
|
||||
public void givenString_whenFormatSpecifierForCalendar_thenGotExpected() {
|
||||
//Syntax of Format Specifiers for Date/Time Representation
|
||||
Calendar c = new GregorianCalendar(2017, 11, 10);
|
||||
String s = String.format("The date is: %1$tm %1$te,%1$tY", c);
|
||||
|
||||
assertEquals("The date is: 12 10,2017", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenGeneralConversion_thenConvertedString() {
|
||||
//General Conversions
|
||||
String s = String.format("The correct answer is %s", false);
|
||||
assertEquals("The correct answer is false", s);
|
||||
|
||||
s = String.format("The correct answer is %b", null);
|
||||
assertEquals("The correct answer is false", s);
|
||||
|
||||
s = String.format("The correct answer is %B", true);
|
||||
assertEquals("The correct answer is TRUE", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenCharConversion_thenConvertedString() {
|
||||
//Character Conversions
|
||||
String s = String.format("The correct answer is %c", 'a');
|
||||
assertEquals("The correct answer is a", s);
|
||||
|
||||
s = String.format("The correct answer is %c", null);
|
||||
assertEquals("The correct answer is null", s);
|
||||
|
||||
s = String.format("The correct answer is %C", 'b');
|
||||
assertEquals("The correct answer is B", s);
|
||||
|
||||
s = String.format("The valid unicode character: %c", 0x0400);
|
||||
assertTrue(Character.isValidCodePoint(0x0400));
|
||||
assertEquals("The valid unicode character: Ѐ", s);
|
||||
}
|
||||
|
||||
@Test(expected = java.util.IllegalFormatCodePointException.class)
|
||||
public void givenString_whenIllegalCodePointForConversion_thenError() {
|
||||
String s = String.format("The valid unicode character: %c", 0x11FFFF);
|
||||
assertFalse(Character.isValidCodePoint(0x11FFFF));
|
||||
assertEquals("The valid unicode character: Ā", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenNumericIntegralConversion_thenConvertedString() {
|
||||
//Numeric Integral Conversions
|
||||
String s = String.format("The number 25 in decimal = %d", 25);
|
||||
assertEquals("The number 25 in decimal = 25", s);
|
||||
|
||||
s = String.format("The number 25 in octal = %o", 25);
|
||||
assertEquals("The number 25 in octal = 31", s);
|
||||
|
||||
s = String.format("The number 25 in hexadecimal = %x", 25);
|
||||
assertEquals("The number 25 in hexadecimal = 19", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenNumericFloatingConversion_thenConvertedString() {
|
||||
//Numeric Floating-point Conversions
|
||||
String s = String.format("The computerized scientific format of 10000.00 "
|
||||
+ "= %e", 10000.00);
|
||||
assertEquals("The computerized scientific format of 10000.00 = 1.000000e+04", s);
|
||||
|
||||
s = String.format("The decimal format of 10.019 = %f", 10.019);
|
||||
assertEquals("The decimal format of 10.019 = 10.019000", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenLineSeparatorConversion_thenConvertedString() {
|
||||
//Line Separator Conversion
|
||||
String s = String.format("First Line %nSecond Line");
|
||||
assertEquals("First Line \n"
|
||||
+ "Second Line", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenSpecifyFlag_thenGotFormattedString() {
|
||||
//Without left-justified flag
|
||||
String s = String.format("Without left justified flag: %5d", 25);
|
||||
assertEquals("Without left justified flag: 25", s);
|
||||
|
||||
//Using left-justified flag
|
||||
s = String.format("With left justified flag: %-5d", 25);
|
||||
assertEquals("With left justified flag: 25 ", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenSpecifyPrecision_thenGotExpected() {
|
||||
|
||||
//Precision
|
||||
String s = String.format("Output of 25.09878 with Precision 2: %.2f", 25.09878);
|
||||
assertEquals("Output of 25.09878 with Precision 2: 25.10", s);
|
||||
|
||||
s = String.format("Output of general conversion type with Precision 2: %.2b", true);
|
||||
assertEquals("Output of general conversion type with Precision 2: tr", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenSpecifyArgumentIndex_thenGotExpected() {
|
||||
Calendar c = new GregorianCalendar(2017, 11, 10);
|
||||
//Argument_Index
|
||||
String s = String.format("The date is: %1$tm %1$te,%1$tY", c);
|
||||
assertEquals("The date is: 12 10,2017", s);
|
||||
|
||||
s = String.format("The date is: %1$tm %<te,%<tY", c);
|
||||
assertEquals("The date is: 12 10,2017", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAppendable_whenCreateFormatter_thenFormatterWorksOnAppendable() {
|
||||
//Using String Formatter with Appendable
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Formatter formatter = new Formatter(sb);
|
||||
formatter.format("I am writting to a %1$s Instance.", sb.getClass());
|
||||
|
||||
assertEquals("I am writting to a class java.lang.StringBuilder Instance.", sb.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenNoArguments_thenExpected() {
|
||||
//Using String Formatter without arguments
|
||||
String s = String.format("John scored 90%% in Fall semester");
|
||||
assertEquals("John scored 90% in Fall semester", s);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.stringpool;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
public class StringPoolUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenCreatingConstantStrings_thenTheirAddressesAreEqual() {
|
||||
String constantString1 = "Baeldung";
|
||||
String constantString2 = "Baeldung";
|
||||
|
||||
assertThat(constantString1).isSameAs(constantString2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCreatingStringsWithTheNewOperator_thenTheirAddressesAreDifferent() {
|
||||
String newString1 = new String("Baeldung");
|
||||
String newString2 = new String("Baeldung");
|
||||
|
||||
assertThat(newString1).isNotSameAs(newString2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenComparingConstantAndNewStrings_thenTheirAddressesAreDifferent() {
|
||||
String constantString = "Baeldung";
|
||||
String newString = new String("Baeldung");
|
||||
|
||||
assertThat(constantString).isNotSameAs(newString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenInterningAStringWithIdenticalValueToAnother_thenTheirAddressesAreEqual() {
|
||||
String constantString = "interned Baeldung";
|
||||
String newString = new String("interned Baeldung");
|
||||
|
||||
assertThat(constantString).isNotSameAs(newString);
|
||||
|
||||
String internedString = newString.intern();
|
||||
|
||||
assertThat(constantString).isSameAs(internedString);
|
||||
}
|
||||
}
|
|
@ -15,5 +15,6 @@
|
|||
- [Data Classes in Kotlin](http://www.baeldung.com/kotlin-data-classes)
|
||||
- [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)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
### Relevant Articles:
|
||||
- [Introduction to Drools](http://www.baeldung.com/drools)
|
||||
- [Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)
|
||||
- [Drools Using Rules from Excel Files](http://www.baeldung.com/drools-excel)
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
<?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>
|
||||
|
||||
<artifactId>drools-backward-chaining</artifactId>
|
||||
<version>1.0</version>
|
||||
<name>drools-backward-chaining</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<runtime.version>6.4.0.Final</runtime.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.kie</groupId>
|
||||
<artifactId>kie-api</artifactId>
|
||||
<version>${runtime.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-core</artifactId>
|
||||
<version>${runtime.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-decisiontables</artifactId>
|
||||
<version>${runtime.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,28 +0,0 @@
|
|||
package com.baeldung;
|
||||
|
||||
import org.kie.api.KieServices;
|
||||
import org.kie.api.runtime.KieContainer;
|
||||
import org.kie.api.runtime.KieSession;
|
||||
|
||||
import com.baeldung.model.Beatle;
|
||||
|
||||
public class BackwardChainingBeatles {
|
||||
public static void main(String[] args) {
|
||||
|
||||
KieServices ks = KieServices.Factory.get();
|
||||
KieContainer kContainer = ks.getKieClasspathContainer();
|
||||
KieSession kSession = kContainer.newKieSession("ksession-backward-chaining");
|
||||
// drools session base on the xml configuration (<strong>kmodule.xml</strong>)
|
||||
|
||||
// graph population
|
||||
kSession.insert(new Beatle("Starr", "drums"));
|
||||
kSession.insert(new Beatle("McCartney", "bass"));
|
||||
kSession.insert(new Beatle("Lennon", "guitar"));
|
||||
kSession.insert(new Beatle("Harrison", "guitar"));
|
||||
|
||||
kSession.insert("Ringo"); // invoke the rule that calls the query implentation of backward chaining
|
||||
kSession.fireAllRules(); // invoke all the rules
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package com.baeldung.model;
|
||||
|
||||
import org.kie.api.definition.type.Position;
|
||||
|
||||
public class Beatle {
|
||||
|
||||
@Position(0)
|
||||
private String lastName;
|
||||
@Position(1)
|
||||
private String instrument;
|
||||
|
||||
public Beatle(String lastName, String instrument) {
|
||||
this.lastName = lastName;
|
||||
this.instrument = instrument;
|
||||
}
|
||||
|
||||
public String getInstrument() {
|
||||
return instrument;
|
||||
}
|
||||
|
||||
public void setInstrument(String instrument) {
|
||||
this.instrument = instrument;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
|
||||
<kbase name="backward_chaining" packages="backward_chaining">
|
||||
<ksession name="ksession-backward-chaining"/>
|
||||
</kbase>
|
||||
</kmodule>
|
|
@ -1,44 +0,0 @@
|
|||
package com.baeldung
|
||||
|
||||
import com.baeldung.model.Beatle;
|
||||
|
||||
|
||||
query whichBeatle(String lastName, String instrument)
|
||||
Beatle(lastName, instrument;)
|
||||
or
|
||||
(Beatle(lastName, null;)
|
||||
and
|
||||
whichBeatle(null, instrument;)) //recursive call to the function that allows to search in a derivation tree structure
|
||||
end
|
||||
|
||||
rule "Ringo"
|
||||
when
|
||||
String(this == "Ringo")
|
||||
whichBeatle("Starr", "drums";)
|
||||
then
|
||||
System.out.println("The beatle is Ringo Starr");
|
||||
end
|
||||
|
||||
rule "Paul"
|
||||
when
|
||||
String(this == "Paul")
|
||||
whichBeatle("McCartney", "bass";)
|
||||
then
|
||||
System.out.println("The beatle is Paul McCartney");
|
||||
end
|
||||
|
||||
rule "John"
|
||||
when
|
||||
String(this == "John")
|
||||
whichBeatle("Lennon", "guitar";)
|
||||
then
|
||||
System.out.println("The beatle is John Lennon");
|
||||
end
|
||||
|
||||
rule "George"
|
||||
when
|
||||
String(this == "George")
|
||||
whichBeatle("Harrison", "guitar";)
|
||||
then
|
||||
System.out.println("The beatle is George Harrison");
|
||||
end
|
121
drools/pom.xml
121
drools/pom.xml
|
@ -1,71 +1,68 @@
|
|||
<?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>
|
||||
<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>drools</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<artifactId>drools</artifactId>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<properties>
|
||||
<http-component-version>4.4.6</http-component-version>
|
||||
<drools-version>7.4.1.Final</drools-version>
|
||||
<apache-poi-version>3.13</apache-poi-version>
|
||||
</properties>
|
||||
|
||||
<properties>
|
||||
<http-component-version>4.4.6</http-component-version>
|
||||
<drools-version>7.1.0.Beta2</drools-version>
|
||||
<apache-poi-version>3.13</apache-poi-version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
<version>${http-component-version}</version>
|
||||
</dependency>
|
||||
<!-- ... -->
|
||||
<dependency>
|
||||
<groupId>org.kie</groupId>
|
||||
<artifactId>kie-ci</artifactId>
|
||||
<version>${drools-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-decisiontables</artifactId>
|
||||
<version>${drools-version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
<version>${http-component-version}</version>
|
||||
</dependency>
|
||||
<!-- ... -->
|
||||
<dependency>
|
||||
<groupId>org.kie</groupId>
|
||||
<artifactId>kie-ci</artifactId>
|
||||
<version>${drools-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-decisiontables</artifactId>
|
||||
<version>${drools-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-core</artifactId>
|
||||
<version>${drools-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-compiler</artifactId>
|
||||
<version>${drools-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>${apache-poi-version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-core</artifactId>
|
||||
<version>${drools-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.drools</groupId>
|
||||
<artifactId>drools-compiler</artifactId>
|
||||
<version>${drools-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>${apache-poi-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${apache-poi-version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>${apache-poi-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.3.6.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>4.3.6.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.drools.backward_chaining;
|
||||
|
||||
import org.kie.api.runtime.KieSession;
|
||||
|
||||
import com.baeldung.drools.config.DroolsBeanFactory;
|
||||
import com.baeldung.drools.model.Fact;
|
||||
import com.baeldung.drools.model.Result;
|
||||
|
||||
public class BackwardChaining {
|
||||
public static void main(String[] args) {
|
||||
Result result = new BackwardChaining().backwardChaining();
|
||||
System.out.println(result.getValue());
|
||||
result.getFacts()
|
||||
.stream()
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
|
||||
public Result backwardChaining() {
|
||||
Result result = new Result();
|
||||
KieSession ksession = new DroolsBeanFactory().getKieSession();
|
||||
ksession.setGlobal("result", result);
|
||||
ksession.insert(new Fact("Asia", "Planet Earth"));
|
||||
ksession.insert(new Fact("China", "Asia"));
|
||||
ksession.insert(new Fact("Great Wall of China", "China"));
|
||||
|
||||
ksession.fireAllRules();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ package com.baeldung.drools.config;
|
|||
import org.drools.decisiontable.DecisionTableProviderImpl;
|
||||
import org.kie.api.KieServices;
|
||||
import org.kie.api.builder.*;
|
||||
import org.kie.api.io.KieResources;
|
||||
import org.kie.api.io.Resource;
|
||||
import org.kie.api.runtime.KieContainer;
|
||||
import org.kie.api.runtime.KieSession;
|
||||
|
@ -22,7 +21,7 @@ public class DroolsBeanFactory {
|
|||
|
||||
private KieFileSystem getKieFileSystem() throws IOException{
|
||||
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
|
||||
List<String> rules=Arrays.asList("SuggestApplicant.drl","Product_rules.xls");
|
||||
List<String> rules=Arrays.asList("BackwardChaining.drl","SuggestApplicant.drl","Product_rules.xls");
|
||||
for(String rule:rules){
|
||||
kieFileSystem.write(ResourceFactory.newClassPathResource(rule));
|
||||
}
|
||||
|
@ -56,9 +55,11 @@ public class DroolsBeanFactory {
|
|||
getKieRepository();
|
||||
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
|
||||
|
||||
kieFileSystem.write(ResourceFactory.newClassPathResource("com/baeldung/drools/rules/BackwardChaining.drl"));
|
||||
kieFileSystem.write(ResourceFactory.newClassPathResource("com/baeldung/drools/rules/SuggestApplicant.drl"));
|
||||
kieFileSystem.write(ResourceFactory.newClassPathResource("com/baeldung/drools/rules/Product_rules.xls"));
|
||||
|
||||
|
||||
|
||||
KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
|
||||
kb.buildAll();
|
||||
KieModule kieModule = kb.getKieModule();
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package com.baeldung.drools.model;
|
||||
|
||||
import org.kie.api.definition.type.Position;
|
||||
|
||||
public class Fact {
|
||||
|
||||
@Position(0)
|
||||
private String element;
|
||||
|
||||
@Position(1)
|
||||
private String place;
|
||||
|
||||
public Fact(String element, String place) {
|
||||
this.element = element;
|
||||
this.place = place;
|
||||
}
|
||||
|
||||
public String getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
public void setElement(String element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
public String getPlace() {
|
||||
return place;
|
||||
}
|
||||
|
||||
public void setPlace(String place) {
|
||||
this.place = place;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((element == null) ? 0 : element.hashCode());
|
||||
result = prime * result + ((place == null) ? 0 : place.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Fact other = (Fact) obj;
|
||||
if (element == null) {
|
||||
if (other.element != null)
|
||||
return false;
|
||||
} else if (!element.equals(other.element))
|
||||
return false;
|
||||
if (place == null) {
|
||||
if (other.place != null)
|
||||
return false;
|
||||
} else if (!place.equals(other.place))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Fact{" + "element='" + element + '\'' + ", place='" + place + '\'' + '}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.baeldung.drools.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Result {
|
||||
private String value;
|
||||
private List<String> facts = new ArrayList<>();
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public List<String> getFacts() {
|
||||
return facts;
|
||||
}
|
||||
|
||||
public void setFacts(List<String> facts) {
|
||||
this.facts = facts;
|
||||
}
|
||||
|
||||
public void addFact(String fact) {
|
||||
this.facts.add(fact);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.drools.rules
|
||||
|
||||
import com.baeldung.drools.model.Fact;
|
||||
|
||||
global com.baeldung.drools.model.Result result;
|
||||
|
||||
dialect "mvel"
|
||||
|
||||
query belongsTo(String x, String y)
|
||||
Fact(x, y;)
|
||||
or
|
||||
(Fact(z, y;) and belongsTo(x, z;))
|
||||
end
|
||||
|
||||
rule "Great Wall of China BELONGS TO Planet Earth"
|
||||
when
|
||||
belongsTo("Great Wall of China", "Planet Earth";)
|
||||
then
|
||||
result.setValue("Decision one taken: Great Wall of China BELONGS TO Planet Earth");
|
||||
end
|
||||
|
||||
rule "print all facts"
|
||||
when
|
||||
belongsTo(element, place;)
|
||||
then
|
||||
result.addFact(element + " IS ELEMENT OF " + place);
|
||||
end
|
|
@ -0,0 +1,36 @@
|
|||
package com.baeldung.drools.backward_chaining;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.kie.api.runtime.KieSession;
|
||||
|
||||
import com.baeldung.drools.config.DroolsBeanFactory;
|
||||
import com.baeldung.drools.model.Fact;
|
||||
import com.baeldung.drools.model.Result;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
|
||||
public class BackwardChainingTest {
|
||||
private Result result;
|
||||
private KieSession ksession;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
result = new Result();
|
||||
ksession = new DroolsBeanFactory().getKieSession();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenWallOfChinaIsGiven_ThenItBelongsToPlanetEarth() {
|
||||
|
||||
ksession.setGlobal("result", result);
|
||||
ksession.insert(new Fact("Asia", "Planet Earth"));
|
||||
ksession.insert(new Fact("China", "Asia"));
|
||||
ksession.insert(new Fact("Great Wall of China", "China"));
|
||||
|
||||
ksession.fireAllRules();
|
||||
|
||||
// Assert Decision one
|
||||
assertEquals(result.getValue(), "Decision one taken: Great Wall of China BELONGS TO Planet Earth");
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.EJB;
|
||||
|
@ -15,7 +16,6 @@ import wildfly.beans.UserBeanLocal;
|
|||
* Servlet implementation class TestEJBServlet
|
||||
*/
|
||||
public class TestEJBServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@EJB
|
||||
private UserBeanLocal userBean;
|
||||
|
@ -23,8 +23,19 @@ public class TestEJBServlet extends HttpServlet {
|
|||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
List<User> users = userBean.getUsers();
|
||||
|
||||
response.getWriter()
|
||||
.append("The number of users is: " + users.size());
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
out.println("<html>");
|
||||
out.println("<head><title>Users</title></head>");
|
||||
out.println("<body>");
|
||||
out.println("<center><h1>List of users:</h1>");
|
||||
out.println("<table border=\"1\" align=\"center\" style=\"width:50%\">");
|
||||
for (User user : users) {
|
||||
out.println("<tr>");
|
||||
out.print("<td>" + user.getUsername() + "</td>");
|
||||
out.print("<td>" + user.getEmail() + "</td>");
|
||||
out.println("</tr>");
|
||||
}
|
||||
}
|
||||
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
## Guava Modules
|
||||
|
|
@ -4,13 +4,14 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>guava18</artifactId>
|
||||
<artifactId>guava-18</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
|
@ -4,13 +4,14 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>guava19</artifactId>
|
||||
<artifactId>guava-19</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
|
@ -4,13 +4,14 @@
|
|||
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>
|
||||
|
||||
<artifactId>guava21</artifactId>
|
||||
<artifactId>guava-21</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
|
@ -0,0 +1,17 @@
|
|||
## Building
|
||||
|
||||
To build the module, use Maven's `package` goal:
|
||||
|
||||
```
|
||||
mvn clean package
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
To run the application, use Spring Boot's `run` goal:
|
||||
|
||||
```
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
The application will be accessible at [http://localhost:8080/](http://localhost:8080/)
|
|
@ -3,7 +3,7 @@
|
|||
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.forketyfork.guest</groupId>
|
||||
<groupId>com.stackify.guest</groupId>
|
||||
<artifactId>spring-mvc</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package com.forketyfork.guest.springmvc;
|
||||
package com.stackify.guest.springmvc;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackages = {"com.forketyfork.guest.springmvc"})
|
||||
@ComponentScan(basePackages = {"com.stackify.guest.springmvc"})
|
||||
public class Spring5Application {
|
||||
|
||||
public static void main(String[] args) {
|
|
@ -1,4 +1,4 @@
|
|||
package com.forketyfork.guest.springmvc.model;
|
||||
package com.stackify.guest.springmvc.model;
|
||||
|
||||
public class LoginData {
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.forketyfork.guest.springmvc.web;
|
||||
package com.stackify.guest.springmvc.web;
|
||||
|
||||
import com.forketyfork.guest.springmvc.model.LoginData;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
@ -8,6 +7,8 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.stackify.guest.springmvc.model.LoginData;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@Controller
|
|
@ -1,4 +1,4 @@
|
|||
package com.forketyfork.guest.springmvc.web;
|
||||
package com.stackify.guest.springmvc.web;
|
||||
|
||||
public class MyInputResource {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.forketyfork.guest.springmvc.web;
|
||||
package com.stackify.guest.springmvc.web;
|
||||
|
||||
public class MyOutputResource {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.forketyfork.guest.springmvc.web;
|
||||
package com.stackify.guest.springmvc.web;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
|
@ -0,0 +1,17 @@
|
|||
## Building
|
||||
|
||||
To build the module, use Maven's `package` goal:
|
||||
|
||||
```
|
||||
mvn clean package
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
To run the application, use Spring Boot's `run` goal:
|
||||
|
||||
```
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
The application will be accessible at [http://localhost:8080/](http://localhost:8080/)
|
|
@ -0,0 +1,77 @@
|
|||
<?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.stackify.guest</groupId>
|
||||
<artifactId>spring-security</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.0.M6</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<name>spring-security</name>
|
||||
<description>Spring Security Sample Project</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf</groupId>
|
||||
<artifactId>thymeleaf-spring5</artifactId>
|
||||
<version>3.0.8.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,15 @@
|
|||
package com.stackify.guest.springsecurity;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackages = {"com.stackify.guest.springsecurity"})
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.stackify.guest.springsecurity.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebMvcConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/customLogin").setViewName("customLogin");
|
||||
registry.addViewController("/loginSuccess").setViewName("index");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.stackify.guest.springsecurity.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.provisioning.JdbcUserDetailsManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
public UserDetailsService jdbcUserDetailsService(DataSource dataSource) {
|
||||
JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
|
||||
manager.setDataSource(dataSource);
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
.antMatchers("/css/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and().formLogin()
|
||||
.loginPage("/customLogin")
|
||||
.defaultSuccessUrl("/loginSuccess", true)
|
||||
.permitAll();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
INSERT INTO users VALUES ('jill', '$2a$04$qUlqAEEYF1YvrpJMosodoewgL6aO.qgHytl2k5L7kdXEWnJsFdxvq', TRUE);
|
||||
INSERT INTO authorities VALUES ('jill', 'USERS');
|
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE users (
|
||||
username VARCHAR(256) PRIMARY KEY,
|
||||
password VARCHAR(256),
|
||||
enabled BOOLEAN
|
||||
);
|
||||
|
||||
CREATE TABLE authorities (
|
||||
username VARCHAR(256) REFERENCES users (username),
|
||||
authority VARCHAR(256)
|
||||
);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue