Merge branch 'master' of https://github.com/eugenp/tutorials
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+39
@@ -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
@@ -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();
|
||||
|
||||
+215
@@ -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);
|
||||
}
|
||||
}
|
||||
+5
-10
@@ -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)
|
||||
|
||||
|
||||
+8
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user