Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
b7ab9c3dea
@ -2,46 +2,48 @@ package com.baeldung.spliteratorAPI;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class RelatedAuthorSpliterator implements Spliterator<Author> {
|
||||
private final List<Author> list;
|
||||
private int current = 0;
|
||||
private final List<Author> list;
|
||||
AtomicInteger current = new AtomicInteger();
|
||||
|
||||
public RelatedAuthorSpliterator(List<Author> list) {
|
||||
this.list = list;
|
||||
}
|
||||
public RelatedAuthorSpliterator(List<Author> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super Author> action) {
|
||||
action.accept(list.get(current++));
|
||||
return current < list.size();
|
||||
}
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super Author> action) {
|
||||
|
||||
@Override
|
||||
public Spliterator<Author> trySplit() {
|
||||
int currentSize = list.size() - current;
|
||||
if (currentSize < 10) {
|
||||
return null;
|
||||
}
|
||||
for (int splitPos = currentSize / 2 + current; splitPos < list.size(); splitPos++) {
|
||||
if (list.get(splitPos)
|
||||
.getRelatedArticleId() == 0) {
|
||||
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(list.subList(current, splitPos));
|
||||
current = splitPos;
|
||||
return spliterator;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
action.accept(list.get(current.getAndIncrement()));
|
||||
return current.get() < list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() {
|
||||
return list.size() - current;
|
||||
}
|
||||
@Override
|
||||
public Spliterator<Author> trySplit() {
|
||||
int currentSize = list.size() - current.get();
|
||||
if (currentSize < 10) {
|
||||
return null;
|
||||
}
|
||||
for (int splitPos = currentSize / 2 + current.intValue(); splitPos < list.size(); splitPos++) {
|
||||
if (list.get(splitPos).getRelatedArticleId() == 0) {
|
||||
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(list.subList(current.get(), splitPos));
|
||||
current.set(splitPos);
|
||||
return spliterator;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() {
|
||||
return list.size() - current.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return CONCURRENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return SIZED + CONCURRENT;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.baeldung.concurrent.waitandnotify;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class Data {
|
||||
private String packet;
|
||||
|
||||
@ -11,7 +13,9 @@ public class Data {
|
||||
while (transfer) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {}
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Thread Interrupted");
|
||||
}
|
||||
}
|
||||
transfer = true;
|
||||
|
||||
@ -23,7 +27,9 @@ public class Data {
|
||||
while (!transfer) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {}
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Thread Interrupted");
|
||||
}
|
||||
}
|
||||
transfer = false;
|
||||
|
||||
|
@ -19,7 +19,9 @@ public class Receiver implements Runnable {
|
||||
//Thread.sleep() to mimic heavy server-side processing
|
||||
try {
|
||||
Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 5000));
|
||||
} catch (InterruptedException e) {}
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Thread Interrupted");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,11 +11,11 @@ public class Sender implements Runnable {
|
||||
|
||||
public void run() {
|
||||
String packets[] = {
|
||||
"First packet",
|
||||
"Second packet",
|
||||
"Third packet",
|
||||
"Fourth packet",
|
||||
"End"
|
||||
"First packet",
|
||||
"Second packet",
|
||||
"Third packet",
|
||||
"Fourth packet",
|
||||
"End"
|
||||
};
|
||||
|
||||
for (String packet : packets) {
|
||||
@ -24,7 +24,9 @@ public class Sender implements Runnable {
|
||||
//Thread.sleep() to mimic heavy server-side processing
|
||||
try {
|
||||
Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 5000));
|
||||
} catch (InterruptedException e) {}
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("Thread Interrupted");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,38 +13,38 @@ import org.junit.Test;
|
||||
|
||||
public class NetworkIntegrationTest {
|
||||
|
||||
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
|
||||
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
|
||||
private String expected;
|
||||
|
||||
@Before
|
||||
public void setUpStreams() {
|
||||
System.setOut(new PrintStream(outContent));
|
||||
System.setErr(new PrintStream(errContent));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUpExpectedOutput() {
|
||||
StringWriter expectedStringWriter = new StringWriter();
|
||||
|
||||
PrintWriter printWriter = new PrintWriter(expectedStringWriter);
|
||||
printWriter.println("First packet");
|
||||
printWriter.println("Second packet");
|
||||
printWriter.println("Third packet");
|
||||
printWriter.println("Fourth packet");
|
||||
printWriter.close();
|
||||
|
||||
expected = expectedStringWriter.toString();
|
||||
}
|
||||
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
|
||||
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
|
||||
private String expected;
|
||||
|
||||
@Before
|
||||
public void setUpStreams() {
|
||||
System.setOut(new PrintStream(outContent));
|
||||
System.setErr(new PrintStream(errContent));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUpExpectedOutput() {
|
||||
StringWriter expectedStringWriter = new StringWriter();
|
||||
|
||||
PrintWriter printWriter = new PrintWriter(expectedStringWriter);
|
||||
printWriter.println("First packet");
|
||||
printWriter.println("Second packet");
|
||||
printWriter.println("Third packet");
|
||||
printWriter.println("Fourth packet");
|
||||
printWriter.close();
|
||||
|
||||
expected = expectedStringWriter.toString();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUpStreams() {
|
||||
System.setOut(null);
|
||||
System.setErr(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSenderAndReceiver_whenSendingPackets_thenNetworkSynchronized() {
|
||||
@After
|
||||
public void cleanUpStreams() {
|
||||
System.setOut(null);
|
||||
System.setErr(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSenderAndReceiver_whenSendingPackets_thenNetworkSynchronized() {
|
||||
Data data = new Data();
|
||||
Thread sender = new Thread(new Sender(data));
|
||||
Thread receiver = new Thread(new Receiver(data));
|
||||
@ -54,12 +54,12 @@ public class NetworkIntegrationTest {
|
||||
|
||||
//wait for sender and receiver to finish before we test against expected
|
||||
try {
|
||||
sender.join();
|
||||
receiver.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
assertEquals(expected, outContent.toString());
|
||||
}
|
||||
sender.join();
|
||||
receiver.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
assertEquals(expected, outContent.toString());
|
||||
}
|
||||
}
|
||||
|
@ -126,3 +126,4 @@
|
||||
- [A Guide to Inner Interfaces in Java](http://www.baeldung.com/java-inner-interfaces)
|
||||
- [Polymorphism in Java](http://www.baeldung.com/java-polymorphism)
|
||||
- [Recursion In Java](http://www.baeldung.com/java-recursion)
|
||||
- [A Guide to the finalize Method in Java](http://www.baeldung.com/java-finalize)
|
||||
|
@ -49,6 +49,11 @@
|
||||
<artifactId>kotlin-stdlib-jre8</artifactId>
|
||||
<version>${kotlin-stdlib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>khttp</groupId>
|
||||
<artifactId>khttp</artifactId>
|
||||
<version>0.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test-junit</artifactId>
|
||||
|
@ -0,0 +1,153 @@
|
||||
package com.baeldung.kotlin.khttp
|
||||
|
||||
import khttp.structures.files.FileLike
|
||||
import org.json.JSONObject
|
||||
import org.junit.Test
|
||||
import java.beans.ExceptionListener
|
||||
import java.beans.XMLEncoder
|
||||
import java.io.*
|
||||
import java.lang.Exception
|
||||
import java.net.ConnectException
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
class KhttpTest {
|
||||
|
||||
@Test
|
||||
fun whenHttpGetRequestIsMade_thenArgsAreReturned() {
|
||||
val response = khttp.get(
|
||||
url = "http://httpbin.org/get",
|
||||
params = mapOf("p1" to "1", "p2" to "2"))
|
||||
val args = response.jsonObject.getJSONObject("args")
|
||||
|
||||
assertEquals("1", args["p1"])
|
||||
assertEquals("2", args["p2"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenAlternateHttpGetRequestIsMade_thenArgsAreReturned() {
|
||||
val response = khttp.request(
|
||||
method = "GET",
|
||||
url = "http://httpbin.org/get",
|
||||
params = mapOf("p1" to "1", "p2" to "2"))
|
||||
val args = response.jsonObject.getJSONObject("args")
|
||||
|
||||
assertEquals("1", args["p1"])
|
||||
assertEquals("2", args["p2"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenHeadersAreSet_thenHeadersAreSent() {
|
||||
val response = khttp.get(
|
||||
url = "http://httpbin.org/get",
|
||||
headers = mapOf("header1" to "1", "header2" to "2"))
|
||||
val headers = response.jsonObject.getJSONObject("headers")
|
||||
|
||||
assertEquals("1", headers["Header1"])
|
||||
assertEquals("2", headers["Header2"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenHttpPostRequestIsMadeWithJson_thenBodyIsReturned() {
|
||||
val response = khttp.post(
|
||||
url = "http://httpbin.org/post",
|
||||
params = mapOf("p1" to "1", "p2" to "2"),
|
||||
json = mapOf("pr1" to "1", "pr2" to "2"))
|
||||
|
||||
val args = response.jsonObject.getJSONObject("args")
|
||||
|
||||
assertEquals("1", args["p1"])
|
||||
assertEquals("2", args["p2"])
|
||||
|
||||
val json = response.jsonObject.getJSONObject("json")
|
||||
|
||||
assertEquals("1", json["pr1"])
|
||||
assertEquals("2", json["pr2"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenHttpPostRequestIsMadeWithMapData_thenBodyIsReturned() {
|
||||
val response = khttp.post(
|
||||
url = "http://httpbin.org/post",
|
||||
params = mapOf("p1" to "1", "p2" to "2"),
|
||||
data = mapOf("pr1" to "1", "pr2" to "2"))
|
||||
|
||||
val args = response.jsonObject.getJSONObject("args")
|
||||
|
||||
assertEquals("1", args["p1"])
|
||||
assertEquals("2", args["p2"])
|
||||
|
||||
val form = response.jsonObject.getJSONObject("form")
|
||||
|
||||
assertEquals("1", form["pr1"])
|
||||
assertEquals("2", form["pr2"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenHttpPostRequestIsMadeWithFiles_thenBodyIsReturned() {
|
||||
val response = khttp.post(
|
||||
url = "http://httpbin.org/post",
|
||||
params = mapOf("p1" to "1", "p2" to "2"),
|
||||
files = listOf(
|
||||
FileLike("file1", "content1"),
|
||||
FileLike("file2", javaClass.getResource("KhttpTest.class").openStream().readBytes())))
|
||||
|
||||
val args = response.jsonObject.getJSONObject("args")
|
||||
|
||||
assertEquals("1", args["p1"])
|
||||
assertEquals("2", args["p2"])
|
||||
|
||||
val files = response.jsonObject.getJSONObject("files")
|
||||
|
||||
assertEquals("content1", files["file1"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenHttpPostRequestIsMadeWithInputStream_thenBodyIsReturned() {
|
||||
val response = khttp.post(
|
||||
url = "http://httpbin.org/post",
|
||||
params = mapOf("p1" to "1", "p2" to "2"),
|
||||
data = ByteArrayInputStream("content!".toByteArray()))
|
||||
|
||||
val args = response.jsonObject.getJSONObject("args")
|
||||
|
||||
assertEquals("1", args["p1"])
|
||||
assertEquals("2", args["p2"])
|
||||
|
||||
assertEquals("content!", response.jsonObject["data"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenHttpPostStreamingRequestIsMade_thenBodyIsReturnedInChunks() {
|
||||
val response = khttp.post(
|
||||
url = "http://httpbin.org/post",
|
||||
stream = true,
|
||||
json = mapOf("pr1" to "1", "pr2" to "2"))
|
||||
|
||||
val baos = ByteArrayOutputStream()
|
||||
response.contentIterator(chunkSize = 10).forEach { arr : ByteArray -> baos.write(arr) }
|
||||
val json = JSONObject(String(baos.toByteArray())).getJSONObject("json")
|
||||
|
||||
assertEquals("1", json["pr1"])
|
||||
assertEquals("2", json["pr2"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenHttpRequestFails_thenExceptionIsThrown() {
|
||||
try {
|
||||
khttp.get(url = "http://localhost/nothing/to/see/here")
|
||||
|
||||
fail("Should have thrown an exception")
|
||||
} catch (e : ConnectException) {
|
||||
//Ok
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenHttpNotFound_thenExceptionIsThrown() {
|
||||
val response = khttp.get(url = "http://httpbin.org/nothing/to/see/here")
|
||||
|
||||
assertEquals(404, response.statusCode)
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.baeldung.guava.memoizer;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CostlySupplier {
|
||||
|
||||
public static BigInteger generateBigNumber() {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
return new BigInteger("12345");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.baeldung.guava.memoizer;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class Factorial {
|
||||
|
||||
private static LoadingCache<Integer, BigInteger> memo = CacheBuilder.newBuilder()
|
||||
.build(CacheLoader.from(Factorial::getFactorial));
|
||||
|
||||
public static BigInteger getFactorial(int n) {
|
||||
if (n == 0) {
|
||||
return BigInteger.ONE;
|
||||
} else {
|
||||
return BigInteger.valueOf(n).multiply(memo.getUnchecked(n - 1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.baeldung.guava.memoizer;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FibonacciSequence {
|
||||
|
||||
private static LoadingCache<Integer, BigInteger> memo = CacheBuilder.newBuilder()
|
||||
.maximumSize(100)
|
||||
.build(CacheLoader.from(FibonacciSequence::getFibonacciNumber));
|
||||
|
||||
public static BigInteger getFibonacciNumber(int n) {
|
||||
if (n == 0) {
|
||||
return BigInteger.ZERO;
|
||||
} else if (n == 1) {
|
||||
return BigInteger.ONE;
|
||||
} else {
|
||||
return memo.getUnchecked(n - 1).add(memo.getUnchecked(n - 2));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package org.baeldung.guava;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import org.baeldung.guava.memoizer.CostlySupplier;
|
||||
import org.baeldung.guava.memoizer.Factorial;
|
||||
import org.baeldung.guava.memoizer.FibonacciSequence;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
import static org.hamcrest.number.IsCloseTo.closeTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class GuavaMemoizerUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenInteger_whenGetFibonacciNumber_thenShouldCalculateFibonacciNumber() {
|
||||
// given
|
||||
int n = 95;
|
||||
|
||||
// when
|
||||
BigInteger fibonacciNumber = FibonacciSequence.getFibonacciNumber(n);
|
||||
|
||||
// then
|
||||
BigInteger expectedFibonacciNumber = new BigInteger("31940434634990099905");
|
||||
assertThat(fibonacciNumber, is(equalTo(expectedFibonacciNumber)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInteger_whenGetFactorial_thenShouldCalculateFactorial() {
|
||||
// given
|
||||
int n = 95;
|
||||
|
||||
// when
|
||||
BigInteger factorial = new Factorial().getFactorial(n);
|
||||
|
||||
// then
|
||||
BigInteger expectedFactorial = new BigInteger("10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000");
|
||||
assertThat(factorial, is(equalTo(expectedFactorial)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMemoizedSupplier_whenGet_thenSubsequentGetsAreFast() {
|
||||
Supplier<BigInteger> memoizedSupplier;
|
||||
memoizedSupplier = Suppliers.memoize(CostlySupplier::generateBigNumber);
|
||||
|
||||
Instant start = Instant.now();
|
||||
BigInteger bigNumber = memoizedSupplier.get();
|
||||
Long durationInMs = Duration.between(start, Instant.now()).toMillis();
|
||||
assertThat(bigNumber, is(equalTo(new BigInteger("12345"))));
|
||||
assertThat(durationInMs.doubleValue(), is(closeTo(2000D, 100D)));
|
||||
|
||||
start = Instant.now();
|
||||
bigNumber = memoizedSupplier.get().add(BigInteger.ONE);
|
||||
durationInMs = Duration.between(start, Instant.now()).toMillis();
|
||||
assertThat(bigNumber, is(equalTo(new BigInteger("12346"))));
|
||||
assertThat(durationInMs.doubleValue(), is(closeTo(0D, 100D)));
|
||||
|
||||
start = Instant.now();
|
||||
bigNumber = memoizedSupplier.get().add(BigInteger.TEN);
|
||||
durationInMs = Duration.between(start, Instant.now()).toMillis();
|
||||
assertThat(bigNumber, is(equalTo(new BigInteger("12355"))));
|
||||
assertThat(durationInMs.doubleValue(), is(closeTo(0D, 100D)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMemoizedSupplierWithExpiration_whenGet_thenSubsequentGetsBeforeExpiredAreFast() throws InterruptedException {
|
||||
Supplier<BigInteger> memoizedSupplier;
|
||||
memoizedSupplier = Suppliers.memoizeWithExpiration(CostlySupplier::generateBigNumber, 3, TimeUnit.SECONDS);
|
||||
|
||||
Instant start = Instant.now();
|
||||
BigInteger bigNumber = memoizedSupplier.get();
|
||||
Long durationInMs = Duration.between(start, Instant.now()).toMillis();
|
||||
assertThat(bigNumber, is(equalTo(new BigInteger("12345"))));
|
||||
assertThat(durationInMs.doubleValue(), is(closeTo(2000D, 100D)));
|
||||
|
||||
start = Instant.now();
|
||||
bigNumber = memoizedSupplier.get().add(BigInteger.ONE);
|
||||
durationInMs = Duration.between(start, Instant.now()).toMillis();
|
||||
assertThat(bigNumber, is(equalTo(new BigInteger("12346"))));
|
||||
assertThat(durationInMs.doubleValue(), is(closeTo(0D, 100D)));
|
||||
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
|
||||
start = Instant.now();
|
||||
bigNumber = memoizedSupplier.get().add(BigInteger.TEN);
|
||||
durationInMs = Duration.between(start, Instant.now()).toMillis();
|
||||
assertThat(bigNumber, is(equalTo(new BigInteger("12355"))));
|
||||
assertThat(durationInMs.doubleValue(), is(closeTo(2000D, 100D)));
|
||||
}
|
||||
|
||||
}
|
20
java-rmi/pom.xml
Normal file
20
java-rmi/pom.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.baeldung.rmi</groupId>
|
||||
<artifactId>java-rmi</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
36
java-rmi/src/main/java/com/baeldung/rmi/Message.java
Normal file
36
java-rmi/src/main/java/com/baeldung/rmi/Message.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.baeldung.rmi;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Message implements Serializable {
|
||||
|
||||
private String messageText;
|
||||
|
||||
private String contentType;
|
||||
|
||||
public Message() {
|
||||
}
|
||||
|
||||
public Message(String messageText, String contentType) {
|
||||
|
||||
this.messageText = messageText;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public String getMessageText() {
|
||||
return messageText;
|
||||
}
|
||||
|
||||
public void setMessageText(String messageText) {
|
||||
this.messageText = messageText;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.baeldung.rmi;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
public interface MessengerService extends Remote {
|
||||
|
||||
public String sendMessage(String clientMessage) throws RemoteException;
|
||||
|
||||
public Message sendMessage(Message clientMessage) throws RemoteException;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.baeldung.rmi;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
|
||||
public class MessengerServiceImpl implements MessengerService {
|
||||
|
||||
public String sendMessage(String clientMessage) {
|
||||
|
||||
String serverMessage = null;
|
||||
if (clientMessage.equals("Client Message")) {
|
||||
serverMessage = "Server Message";
|
||||
}
|
||||
|
||||
return serverMessage;
|
||||
}
|
||||
|
||||
public void createStubAndBind() throws RemoteException {
|
||||
|
||||
MessengerService stub = (MessengerService) UnicastRemoteObject.exportObject((MessengerService) this, 0);
|
||||
Registry registry = LocateRegistry.createRegistry(1099);
|
||||
registry.rebind("MessengerService", stub);
|
||||
}
|
||||
|
||||
public Message sendMessage(Message clientMessage) throws RemoteException {
|
||||
|
||||
Message serverMessage = null;
|
||||
if (clientMessage.getMessageText().equals("Client Message")) {
|
||||
serverMessage = new Message("Server Message", "text/plain");
|
||||
}
|
||||
|
||||
return serverMessage;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.baeldung.rmi;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.rmi.NotBoundException;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class JavaRMIIntegrationTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void whenRunServer_thenServerStarts() {
|
||||
|
||||
try {
|
||||
MessengerServiceImpl server = new MessengerServiceImpl();
|
||||
server.createStubAndBind();
|
||||
} catch (RemoteException e) {
|
||||
fail("Exception Occurred");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenClientSendsMessageToServer_thenServerSendsResponseMessage() {
|
||||
|
||||
try {
|
||||
Registry registry = LocateRegistry.getRegistry();
|
||||
MessengerService server = (MessengerService) registry.lookup("MessengerService");
|
||||
String responseMessage = server.sendMessage("Client Message");
|
||||
|
||||
String expectedMessage = "Server Message";
|
||||
assertEquals(responseMessage, expectedMessage);
|
||||
} catch (RemoteException e) {
|
||||
fail("Exception Occurred");
|
||||
} catch (NotBoundException nb) {
|
||||
fail("Exception Occurred");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -194,6 +194,11 @@
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>rome</groupId>
|
||||
<artifactId>rome</artifactId>
|
||||
@ -741,12 +746,11 @@
|
||||
<assertj.version>3.6.2</assertj.version>
|
||||
<jsonassert.version>1.5.0</jsonassert.version>
|
||||
<javers.version>3.1.0</javers.version>
|
||||
<jetty.version>9.4.3.v20170317</jetty.version>
|
||||
<httpclient.version>4.5.3</httpclient.version>
|
||||
<commons.io.version>2.5</commons.io.version>
|
||||
<commons.dbutils.version>1.6</commons.dbutils.version>
|
||||
<h2.version>1.4.196</h2.version>
|
||||
<jetty.version>9.4.2.v20170220</jetty.version>
|
||||
<jetty.version>9.4.8.v20171121</jetty.version>
|
||||
<httpclient.version>4.5.3</httpclient.version>
|
||||
<commons.io.version>2.5</commons.io.version>
|
||||
<flink.version>1.2.0</flink.version>
|
||||
|
@ -0,0 +1,94 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
* Simple factory for creating Jetty basic instances.
|
||||
*
|
||||
* @author Donato Rimenti
|
||||
*
|
||||
*/
|
||||
public class JettyServerFactory {
|
||||
|
||||
/**
|
||||
* Exposed context of the app.
|
||||
*/
|
||||
public final static String APP_PATH = "/myApp";
|
||||
|
||||
/**
|
||||
* The server port.
|
||||
*/
|
||||
public final static int SERVER_PORT = 13133;
|
||||
|
||||
/**
|
||||
* Private constructor to avoid instantiation.
|
||||
*/
|
||||
private JettyServerFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a simple server listening on port 80 with a timeout of 30 seconds
|
||||
* for connections and no handlers.
|
||||
*
|
||||
* @return a server
|
||||
*/
|
||||
public static Server createBaseServer() {
|
||||
Server server = new Server();
|
||||
|
||||
// Adds a connector for port 80 with a timeout of 30 seconds.
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(SERVER_PORT);
|
||||
connector.setHost("127.0.0.1");
|
||||
connector.setIdleTimeout(30000);
|
||||
server.addConnector(connector);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a server which delegates the request handling to a web
|
||||
* application.
|
||||
*
|
||||
* @return a server
|
||||
*/
|
||||
public static Server createWebAppServer() {
|
||||
// Adds an handler to a server and returns it.
|
||||
Server server = createBaseServer();
|
||||
String webAppFolderPath = JettyServerFactory.class.getClassLoader().getResource("jetty-embedded-demo-app.war")
|
||||
.getPath();
|
||||
Handler webAppHandler = new WebAppContext(webAppFolderPath, APP_PATH);
|
||||
server.setHandler(webAppHandler);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a server which delegates the request handling to both a logging
|
||||
* handler and to a web application, in this order.
|
||||
*
|
||||
* @return a server
|
||||
*/
|
||||
public static Server createMultiHandlerServer() {
|
||||
Server server = createBaseServer();
|
||||
|
||||
// Creates the handlers and adds them to the server.
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
|
||||
String webAppFolderPath = JettyServerFactory.class.getClassLoader().getResource("jetty-embedded-demo-app.war")
|
||||
.getPath();
|
||||
Handler customRequestHandler = new WebAppContext(webAppFolderPath, APP_PATH);
|
||||
handlers.addHandler(customRequestHandler);
|
||||
|
||||
Handler loggingRequestHandler = new LoggingRequestHandler();
|
||||
handlers.addHandler(loggingRequestHandler);
|
||||
|
||||
server.setHandler(handlers);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler implementation which simply logs that a request has been received.
|
||||
*
|
||||
* @author Donato Rimenti
|
||||
*/
|
||||
public class LoggingRequestHandler implements Handler {
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private final static Logger LOG = LoggerFactory.getLogger(LoggingRequestHandler.class);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#addLifeCycleListener(org.
|
||||
* eclipse.jetty.util.component.LifeCycle.Listener)
|
||||
*/
|
||||
@Override
|
||||
public void addLifeCycleListener(Listener arg0) {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isFailed()
|
||||
*/
|
||||
@Override
|
||||
public boolean isFailed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isRunning()
|
||||
*/
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isStarted()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStarted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isStarting()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStarting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isStopped()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStopped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isStopping()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStopping() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.jetty.util.component.LifeCycle#removeLifeCycleListener(org.
|
||||
* eclipse.jetty.util.component.LifeCycle.Listener)
|
||||
*/
|
||||
@Override
|
||||
public void removeLifeCycleListener(Listener arg0) {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#stop()
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.server.Handler#destroy()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.server.Handler#getServer()
|
||||
*/
|
||||
@Override
|
||||
public Server getServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.server.Handler#handle(java.lang.String,
|
||||
* org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
|
||||
* javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
@Override
|
||||
public void handle(String arg0, Request arg1, HttpServletRequest arg2, HttpServletResponse arg3)
|
||||
throws IOException, ServletException {
|
||||
LOG.info("Received a new request");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.server.Handler#setServer(org.eclipse.jetty.server.
|
||||
* Server)
|
||||
*/
|
||||
@Override
|
||||
public void setServer(Server server) {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test for {@link JettyServerFactory}.
|
||||
*
|
||||
* @author Donato Rimenti
|
||||
*
|
||||
*/
|
||||
public class JettyServerFactoryUnitTest {
|
||||
|
||||
/**
|
||||
* Tests that when a base server is provided a request returns a status 404.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void givenBaseServer_whenHttpRequest_thenStatus404() throws Exception {
|
||||
Server server = JettyServerFactory.createBaseServer();
|
||||
server.start();
|
||||
|
||||
int statusCode = sendGetRequest();
|
||||
|
||||
Assert.assertEquals(404, statusCode);
|
||||
server.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when a web app server is provided a request returns a status
|
||||
* 200.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void givenWebAppServer_whenHttpRequest_thenStatus200() throws Exception {
|
||||
Server server = JettyServerFactory.createWebAppServer();
|
||||
server.start();
|
||||
|
||||
int statusCode = sendGetRequest();
|
||||
|
||||
Assert.assertEquals(200, statusCode);
|
||||
server.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when a multi handler server is provided a request returns a
|
||||
* status 200.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void givenMultiHandlerServerServer_whenHttpRequest_thenStatus200() throws Exception {
|
||||
Server server = JettyServerFactory.createMultiHandlerServer();
|
||||
server.start();
|
||||
|
||||
int statusCode = sendGetRequest();
|
||||
|
||||
Assert.assertEquals(200, statusCode);
|
||||
server.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a default HTTP GET request to the server and returns the response
|
||||
* status code.
|
||||
*
|
||||
* @return the status code of the response
|
||||
* @throws Exception
|
||||
*/
|
||||
private int sendGetRequest() throws Exception {
|
||||
HttpHost target = new HttpHost("localhost", JettyServerFactory.SERVER_PORT);
|
||||
HttpRequest request = new HttpGet(JettyServerFactory.APP_PATH);
|
||||
HttpClient client = HttpClientBuilder.create().build();
|
||||
HttpResponse response = client.execute(target, request);
|
||||
return response.getStatusLine().getStatusCode();
|
||||
}
|
||||
|
||||
}
|
@ -32,9 +32,9 @@ public class PactConsumerDrivenContractUnitTest {
|
||||
headers.put("Content-Type", "application/json");
|
||||
|
||||
return builder
|
||||
.given("test GET ")
|
||||
.given("test GET")
|
||||
.uponReceiving("GET REQUEST")
|
||||
.path("/")
|
||||
.path("/pact")
|
||||
.method("GET")
|
||||
.willRespondWith()
|
||||
.status(200)
|
||||
@ -45,11 +45,9 @@ public class PactConsumerDrivenContractUnitTest {
|
||||
.method("POST")
|
||||
.headers(headers)
|
||||
.body("{\"name\": \"Michael\"}")
|
||||
.path("/create")
|
||||
.path("/pact")
|
||||
.willRespondWith()
|
||||
.status(201)
|
||||
.headers(headers)
|
||||
.body("")
|
||||
.toPact();
|
||||
}
|
||||
|
||||
@ -59,7 +57,7 @@ public class PactConsumerDrivenContractUnitTest {
|
||||
public void givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody() {
|
||||
//when
|
||||
ResponseEntity<String> response
|
||||
= new RestTemplate().getForEntity(mockProvider.getUrl(), String.class);
|
||||
= new RestTemplate().getForEntity(mockProvider.getUrl() + "/pact", String.class);
|
||||
|
||||
//then
|
||||
assertThat(response.getStatusCode().value()).isEqualTo(200);
|
||||
@ -73,7 +71,7 @@ public class PactConsumerDrivenContractUnitTest {
|
||||
|
||||
//when
|
||||
ResponseEntity<String> postResponse = new RestTemplate().exchange(
|
||||
mockProvider.getUrl() + "/create",
|
||||
mockProvider.getUrl() + "/pact",
|
||||
HttpMethod.POST,
|
||||
new HttpEntity<>(jsonBody, httpHeaders),
|
||||
String.class
|
||||
|
BIN
libraries/src/test/resources/jetty-embedded-demo-app.war
Normal file
BIN
libraries/src/test/resources/jetty-embedded-demo-app.war
Normal file
Binary file not shown.
5
pom.xml
5
pom.xml
@ -87,8 +87,9 @@
|
||||
<module>jackson</module>
|
||||
<!-- <module>persistence-modules/java-cassandra</module> -->
|
||||
<module>vavr</module>
|
||||
<module>java-lite</module>
|
||||
<module>java-vavr-stream</module>
|
||||
<module>java-lite</module>
|
||||
<module>java-rmi</module>
|
||||
<module>java-vavr-stream</module>
|
||||
<module>javax-servlets</module>
|
||||
<module>javaxval</module>
|
||||
<module>jaxb</module>
|
||||
|
@ -2,22 +2,25 @@ package com.baeldung.reactive.websocket;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.reactive.socket.WebSocketMessage;
|
||||
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
|
||||
import org.springframework.web.reactive.socket.client.WebSocketClient;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ReactiveJavaClientWebSocket {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
client.execute(URI.create("ws://localhost:8080/event-emitter"), session -> session.send(Mono.just(session.textMessage("event-me-from-spring-reactive-client")))
|
||||
client.execute(
|
||||
URI.create("ws://localhost:8080/event-emitter"),
|
||||
session -> session.send(
|
||||
Mono.just(session.textMessage("event-spring-reactive-client-websocket")))
|
||||
.thenMany(session.receive()
|
||||
.map(WebSocketMessage::getPayloadAsText)
|
||||
.log())
|
||||
.map(WebSocketMessage::getPayloadAsText)
|
||||
.log())
|
||||
.then())
|
||||
.block(Duration.ofSeconds(10L));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,71 +1,41 @@
|
||||
package com.baeldung.reactive.websocket;
|
||||
|
||||
import org.springframework.web.reactive.socket.WebSocketSession;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.socket.WebSocketHandler;
|
||||
import org.springframework.web.reactive.socket.WebSocketMessage;
|
||||
|
||||
import org.springframework.web.reactive.socket.WebSocketSession;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.time.LocalDateTime.now;
|
||||
import static java.util.UUID.randomUUID;
|
||||
|
||||
@Component
|
||||
public class ReactiveWebSocketHandler implements WebSocketHandler {
|
||||
|
||||
private Flux<Event> eventFlux;
|
||||
private Flux<Event> intervalFlux;
|
||||
private static final ObjectMapper json = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* Here we prepare a Flux that will emit a message every second
|
||||
*/
|
||||
@PostConstruct
|
||||
private void init() throws InterruptedException {
|
||||
private Flux<String> eventFlux = Flux.generate(sink -> {
|
||||
Event event = new Event(randomUUID().toString(), now().toString());
|
||||
try {
|
||||
sink.next(json.writeValueAsString(event));
|
||||
} catch (JsonProcessingException e) {
|
||||
sink.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
eventFlux = Flux.generate(e -> {
|
||||
Event event = new Event(UUID.randomUUID()
|
||||
.toString(),
|
||||
LocalDateTime.now()
|
||||
.toString());
|
||||
e.next(event);
|
||||
});
|
||||
private Flux<String> intervalFlux = Flux.interval(Duration.ofMillis(1000L))
|
||||
.zipWith(eventFlux, (time, event) -> event);
|
||||
|
||||
intervalFlux = Flux.interval(Duration.ofMillis(1000L))
|
||||
.zipWith(eventFlux, (time, event) -> event);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* On each new client session, send the message flux to the client.
|
||||
* Spring subscribes to the flux and send every new flux event to the WebSocketSession object
|
||||
* @param session
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
@Override
|
||||
public Mono<Void> handle(WebSocketSession webSocketSession) {
|
||||
ObjectMapper json = new ObjectMapper();
|
||||
return webSocketSession.send(intervalFlux.map(event -> {
|
||||
try {
|
||||
String jsonEvent = json.writeValueAsString(event);
|
||||
System.out.println(jsonEvent);
|
||||
return jsonEvent;
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
})
|
||||
.map(webSocketSession::textMessage))
|
||||
|
||||
.and(webSocketSession.receive()
|
||||
.map(WebSocketMessage::getPayloadAsText)
|
||||
.log());
|
||||
return webSocketSession.send(intervalFlux
|
||||
.map(webSocketSession::textMessage))
|
||||
.and(webSocketSession.receive()
|
||||
.map(WebSocketMessage::getPayloadAsText).log());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||
|
||||
public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain";
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException {
|
||||
|
||||
if (!request.getMethod().equals("POST")) {
|
||||
throw new AuthenticationServiceException("Authentication method not supported: "
|
||||
+ request.getMethod());
|
||||
}
|
||||
|
||||
CustomAuthenticationToken authRequest = getAuthRequest(request);
|
||||
setDetails(request, authRequest);
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
}
|
||||
|
||||
private CustomAuthenticationToken getAuthRequest(HttpServletRequest request) {
|
||||
String username = obtainUsername(request);
|
||||
String password = obtainPassword(request);
|
||||
String domain = obtainDomain(request);
|
||||
|
||||
if (username == null) {
|
||||
username = "";
|
||||
}
|
||||
if (password == null) {
|
||||
password = "";
|
||||
}
|
||||
if (domain == null) {
|
||||
domain = "";
|
||||
}
|
||||
|
||||
return new CustomAuthenticationToken(username, password, domain);
|
||||
}
|
||||
|
||||
private String obtainDomain(HttpServletRequest request) {
|
||||
return request.getParameter(SPRING_SECURITY_FORM_DOMAIN_KEY);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken {
|
||||
|
||||
private String domain;
|
||||
|
||||
public CustomAuthenticationToken(Object principal, Object credentials, String domain) {
|
||||
super(principal, credentials);
|
||||
this.domain = domain;
|
||||
super.setAuthenticated(false);
|
||||
}
|
||||
|
||||
public CustomAuthenticationToken(Object principal, Object credentials, String domain,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
super(principal, credentials, authorities);
|
||||
this.domain = domain;
|
||||
super.setAuthenticated(true); // must use super, as we override
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return this.domain;
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
public class CustomUserDetailsAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
|
||||
|
||||
/**
|
||||
* The plaintext password used to perform
|
||||
* PasswordEncoder#matches(CharSequence, String)} on when the user is
|
||||
* not found to avoid SEC-2056.
|
||||
*/
|
||||
private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
|
||||
|
||||
private PasswordEncoder passwordEncoder;
|
||||
private CustomUserDetailsService userDetailsService;
|
||||
|
||||
/**
|
||||
* The password used to perform
|
||||
* {@link PasswordEncoder#matches(CharSequence, String)} on when the user is
|
||||
* not found to avoid SEC-2056. This is necessary, because some
|
||||
* {@link PasswordEncoder} implementations will short circuit if the password is not
|
||||
* in a valid format.
|
||||
*/
|
||||
private String userNotFoundEncodedPassword;
|
||||
|
||||
public CustomUserDetailsAuthenticationProvider(PasswordEncoder passwordEncoder, CustomUserDetailsService userDetailsService) {
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
|
||||
if (authentication.getCredentials() == null) {
|
||||
logger.debug("Authentication failed: no credentials provided");
|
||||
throw new BadCredentialsException(
|
||||
messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
||||
}
|
||||
|
||||
String presentedPassword = authentication.getCredentials()
|
||||
.toString();
|
||||
|
||||
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
|
||||
logger.debug("Authentication failed: password does not match stored value");
|
||||
throw new BadCredentialsException(
|
||||
messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAfterPropertiesSet() throws Exception {
|
||||
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
|
||||
this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
|
||||
throws AuthenticationException {
|
||||
CustomAuthenticationToken auth = (CustomAuthenticationToken) authentication;
|
||||
UserDetails loadedUser;
|
||||
|
||||
try {
|
||||
loadedUser = this.userDetailsService.loadUserByUsernameAndDomain(auth.getPrincipal()
|
||||
.toString(), auth.getDomain());
|
||||
} catch (UsernameNotFoundException notFound) {
|
||||
if (authentication.getCredentials() != null) {
|
||||
String presentedPassword = authentication.getCredentials()
|
||||
.toString();
|
||||
passwordEncoder.matches(presentedPassword, userNotFoundEncodedPassword);
|
||||
}
|
||||
throw notFound;
|
||||
} catch (Exception repositoryProblem) {
|
||||
throw new InternalAuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
|
||||
}
|
||||
|
||||
if (loadedUser == null) {
|
||||
throw new InternalAuthenticationServiceException("UserDetailsService returned null, "
|
||||
+ "which is an interface contract violation");
|
||||
}
|
||||
return loadedUser;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
public interface CustomUserDetailsService {
|
||||
|
||||
UserDetails loadUserByUsernameAndDomain(String username, String domain) throws UsernameNotFoundException;
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service("userDetailsService")
|
||||
public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {
|
||||
|
||||
private UserRepository userRepository;
|
||||
|
||||
public CustomUserDetailsServiceImpl(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsernameAndDomain(String username, String domain) throws UsernameNotFoundException {
|
||||
if (StringUtils.isAnyBlank(username, domain)) {
|
||||
throw new UsernameNotFoundException("Username and domain must be provided");
|
||||
}
|
||||
User user = userRepository.findUser(username, domain);
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException(
|
||||
String.format("Username not found for domain, username=%s, domain=%s",
|
||||
username, domain));
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
@ -1,13 +1,13 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringExtraLoginFieldsApplication {
|
||||
public class ExtraLoginFieldsApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringExtraLoginFieldsApplication.class, args);
|
||||
SpringApplication.run(ExtraLoginFieldsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
@EnableWebSecurity
|
||||
@PropertySource("classpath:/application-extrafields.properties")
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private CustomUserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
http
|
||||
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.authorizeRequests()
|
||||
.antMatchers("/css/**", "/index").permitAll()
|
||||
.antMatchers("/user/**").authenticated()
|
||||
.and()
|
||||
.formLogin().loginPage("/login")
|
||||
.and()
|
||||
.logout()
|
||||
.logoutUrl("/logout");
|
||||
}
|
||||
|
||||
public CustomAuthenticationFilter authenticationFilter() throws Exception {
|
||||
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
|
||||
filter.setAuthenticationManager(authenticationManagerBean());
|
||||
filter.setAuthenticationFailureHandler(failureHandler());
|
||||
return filter;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.authenticationProvider(authProvider());
|
||||
}
|
||||
|
||||
public AuthenticationProvider authProvider() {
|
||||
CustomUserDetailsAuthenticationProvider provider
|
||||
= new CustomUserDetailsAuthenticationProvider(passwordEncoder(), userDetailsService);
|
||||
return provider;
|
||||
}
|
||||
|
||||
public SimpleUrlAuthenticationFailureHandler failureHandler() {
|
||||
return new SimpleUrlAuthenticationFailureHandler("/login?error=true");
|
||||
}
|
||||
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ -8,7 +8,7 @@ public class User extends org.springframework.security.core.userdetails.User {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String domain;
|
||||
private String domain;
|
||||
|
||||
public User(String username, String domain, String password, boolean enabled,
|
||||
boolean accountNonExpired, boolean credentialsNonExpired,
|
@ -1,4 +1,4 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
public interface UserRepository {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafieldscustom;
|
||||
|
||||
import java.util.Optional;
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.baeldung.loginextrafieldssimple;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ExtraLoginFieldsApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ExtraLoginFieldsApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafieldssimple;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
@ -36,8 +36,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
.logoutUrl("/logout");
|
||||
}
|
||||
|
||||
public CustomAuthenticationFilter authenticationFilter() throws Exception {
|
||||
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
|
||||
public SimpleAuthenticationFilter authenticationFilter() throws Exception {
|
||||
SimpleAuthenticationFilter filter = new SimpleAuthenticationFilter();
|
||||
filter.setAuthenticationManager(authenticationManagerBean());
|
||||
filter.setAuthenticationFailureHandler(failureHandler());
|
||||
return filter;
|
@ -1,4 +1,4 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafieldssimple;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@ -9,7 +9,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||
public class SimpleAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||
|
||||
public static final String SPRING_SECURITY_FORM_DOMAIN_KEY = "domain";
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafieldssimple;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
@ -7,11 +7,11 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service("userDetailsService")
|
||||
public class CustomUserDetailsService implements UserDetailsService {
|
||||
public class SimpleUserDetailsService implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private UserRepository userRepository;
|
||||
|
||||
public CustomUserDetailsService(UserRepository userRepository) {
|
||||
public SimpleUserDetailsService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.baeldung.loginextrafieldssimple;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository("userRepository")
|
||||
public class SimpleUserRepository implements UserRepository {
|
||||
|
||||
@Override
|
||||
public User findUser(String username, String domain) {
|
||||
if (StringUtils.isAnyBlank(username, domain)) {
|
||||
return null;
|
||||
} else {
|
||||
Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
|
||||
User user = new User(username, domain,
|
||||
"$2a$10$U3GhSMpsMSOE8Kqsbn58/edxDBKlVuYMh7qk/7ErApYFjJzi2VG5K", true,
|
||||
true, true, true, authorities);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.baeldung.loginextrafieldssimple;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
public class User extends org.springframework.security.core.userdetails.User {
|
||||
|
||||
private String domain;
|
||||
|
||||
public User(String username, String domain, String password, boolean enabled,
|
||||
boolean accountNonExpired, boolean credentialsNonExpired,
|
||||
boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.baeldung.loginextrafieldssimple;
|
||||
|
||||
public interface UserRepository {
|
||||
|
||||
public User findUser(String username, String domain);
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.baeldung.loginextrafieldssimple;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
public class WebController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String root() {
|
||||
return "redirect:/index";
|
||||
}
|
||||
|
||||
@RequestMapping("/index")
|
||||
public String index(Model model) {
|
||||
getDomain().ifPresent(d -> {
|
||||
model.addAttribute("domain", d);
|
||||
});
|
||||
return "index";
|
||||
}
|
||||
|
||||
@RequestMapping("/user/index")
|
||||
public String userIndex(Model model) {
|
||||
getDomain().ifPresent(d -> {
|
||||
model.addAttribute("domain", d);
|
||||
});
|
||||
return "user/index";
|
||||
}
|
||||
|
||||
@RequestMapping("/login")
|
||||
public String login() {
|
||||
return "login";
|
||||
}
|
||||
|
||||
private Optional<String> getDomain() {
|
||||
Authentication auth = SecurityContextHolder.getContext()
|
||||
.getAuthentication();
|
||||
String domain = null;
|
||||
if (auth != null && !auth.getClass().equals(AnonymousAuthenticationToken.class)) {
|
||||
User user = (User) auth.getPrincipal();
|
||||
domain = user.getDomain();
|
||||
}
|
||||
return Optional.ofNullable(domain);
|
||||
}
|
||||
}
|
@ -1,18 +1,8 @@
|
||||
body {
|
||||
font-family: sans;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
p.error {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.logout {
|
||||
float: right;
|
||||
margin-right: 2em;;
|
||||
}
|
||||
|
||||
.formfield {
|
||||
margin: 0.5em;
|
||||
padding: 0.3em;
|
||||
}
|
@ -1,24 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4" lang="en">
|
||||
<head>
|
||||
<title>Spring Security - Login With Extra Fields</title>
|
||||
<title>Spring Security with Extra Fields</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
||||
<link href="http://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/>
|
||||
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
|
||||
</head>
|
||||
<body>
|
||||
<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
|
||||
Logged in user: <span sec:authentication="name"></span> |
|
||||
domain: <span th:text="${domain}">Some Domain</span>
|
||||
<div class="container">
|
||||
<div class="logout float-right" th:fragment="logout" sec:authorize="isAuthenticated()">
|
||||
<p>Logged in: <span sec:authentication="name"></span> | <span th:text="${domain}">Some Domain</span>
|
||||
</p>
|
||||
<div>
|
||||
<form action="#" th:action="@{/logout}" method="post">
|
||||
<input type="submit" value="Logout" />
|
||||
<button class="btn btn-sm btn-primary btn-block" type="submit">Logout</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<h1>Hello Spring Security</h1>
|
||||
|
||||
<h2>Hello Spring Security</h2>
|
||||
<p>This is an unsecured page, but you can access the secured pages after authenticating.</p>
|
||||
<ul>
|
||||
<li>Go to the <a href="/user/index" th:href="@{/user/index}">secured pages</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,23 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Login page</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Login page</h1>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">
|
||||
<head>
|
||||
<title>Login page</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
||||
<link href="http://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/>
|
||||
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<form class="form-signin" th:action="@{/login}" method="post">
|
||||
<h2 class="form-signin-heading">Please sign in</h2>
|
||||
<p>Example: user / domain / password</p>
|
||||
<p th:if="${param.error}" class="error">Invalid user, password, or domain</p>
|
||||
<form th:action="@{/login}" method="post">
|
||||
<label for="username">Username</label>:
|
||||
<input class="formfield" type="text" id="username" name="username" autofocus="autofocus" /> <br />
|
||||
<label for="domain">Domain</label>:
|
||||
<input class="formfield" type="text" id="domain" name="domain" /> <br />
|
||||
<label for="password">Password</label>:
|
||||
<input class="formfield" type="password" id="password" name="password" /> <br />
|
||||
<input type="submit" value="Log in" />
|
||||
</form>
|
||||
<p>
|
||||
<label for="username" class="sr-only">Username</label>
|
||||
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="domain" class="sr-only">Domain</label>
|
||||
<input type="text" id="domain" name="domain" class="form-control" placeholder="Domain" required autofocus/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="password" class="sr-only">Password</label>
|
||||
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required autofocus/>
|
||||
</p>
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button><br/>
|
||||
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
|
||||
</body>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,13 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>Spring Security - Login With Extra Fields</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
|
||||
</head>
|
||||
<body>
|
||||
<div th:replace="index::logout"></div>
|
||||
<h1>This is a secured page!</h1>
|
||||
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
|
||||
</body>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" lang="en">
|
||||
<head>
|
||||
<title>Secured Page</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
|
||||
<link href="http://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/>
|
||||
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div th:replace="index::logout"></div>
|
||||
<h2>This is a secured page!</h2>
|
||||
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -0,0 +1,46 @@
|
||||
package com.baeldung.loginextrafields;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
public abstract class AbstractExtraLoginFieldsTest {
|
||||
|
||||
@Autowired
|
||||
private FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext wac;
|
||||
|
||||
protected MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
|
||||
.apply(springSecurity(springSecurityFilterChain))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRootPathAccess_thenRedirectToIndex() throws Exception {
|
||||
this.mockMvc.perform(get("/"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrlPattern("/index*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSecuredResource_whenAccessUnauthenticated_thenRequiresAuthentication() throws Exception {
|
||||
this.mockMvc.perform(get("/user/index"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrlPattern("**/login"));
|
||||
}
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
package com.baeldung.securityextrafields;
|
||||
package com.baeldung.loginextrafields;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
|
||||
@ -11,57 +10,26 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.baeldung.loginextrafieldscustom.ExtraLoginFieldsApplication;
|
||||
import com.baeldung.loginextrafieldscustom.User;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringJUnitWebConfig
|
||||
@SpringBootTest(classes = SpringExtraLoginFieldsApplication.class)
|
||||
public class SecurityExtraFieldsTest {
|
||||
|
||||
@Autowired
|
||||
private FilterChainProxy springSecurityFilterChain;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext wac;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
|
||||
.apply(springSecurity(springSecurityFilterChain)).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenRootPathAccess_thenRedirectToIndex() throws Exception {
|
||||
this.mockMvc.perform(get("/"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrlPattern("/index*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSecuredResource_whenAccessUnauthenticated_thenRequiresAuthentication() throws Exception {
|
||||
this.mockMvc.perform(get("/user/index"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrlPattern("**/login"));
|
||||
}
|
||||
@SpringBootTest(classes = ExtraLoginFieldsApplication.class)
|
||||
public class LoginFieldsFullTest extends AbstractExtraLoginFieldsTest {
|
||||
|
||||
@Test
|
||||
public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception {
|
||||
@ -100,4 +68,5 @@ public class SecurityExtraFieldsTest {
|
||||
Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
|
||||
return new User("myusername", "mydomain", "password", true, true, true, true, authorities);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.baeldung.loginextrafields;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
|
||||
import com.baeldung.loginextrafieldssimple.ExtraLoginFieldsApplication;
|
||||
import com.baeldung.loginextrafieldssimple.User;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringJUnitWebConfig
|
||||
@SpringBootTest(classes = ExtraLoginFieldsApplication.class)
|
||||
public class LoginFieldsSimpleTest extends AbstractExtraLoginFieldsTest {
|
||||
|
||||
@Test
|
||||
public void givenAccessSecuredResource_whenAuthenticated_thenAuthHasExtraFields() throws Exception {
|
||||
MockHttpServletRequestBuilder securedResourceAccess = get("/user/index");
|
||||
MvcResult unauthenticatedResult = mockMvc.perform(securedResourceAccess)
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
|
||||
MockHttpSession session = (MockHttpSession) unauthenticatedResult.getRequest()
|
||||
.getSession();
|
||||
String loginUrl = unauthenticatedResult.getResponse()
|
||||
.getRedirectedUrl();
|
||||
|
||||
User user = getUser();
|
||||
|
||||
mockMvc.perform(post(loginUrl)
|
||||
.param("username", user.getUsername())
|
||||
.param("password", user.getPassword())
|
||||
.param("domain", user.getDomain())
|
||||
.session(session)
|
||||
.with(csrf()))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrlPattern("**/user/index"))
|
||||
.andReturn();
|
||||
|
||||
mockMvc.perform(securedResourceAccess.session(session))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
SecurityContext securityContext
|
||||
= (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
|
||||
Authentication auth = securityContext.getAuthentication();
|
||||
assertEquals(((User)auth.getPrincipal()).getDomain(), user.getDomain());
|
||||
}
|
||||
|
||||
private User getUser() {
|
||||
Collection<? extends GrantedAuthority> authorities = new ArrayList<>();
|
||||
return new User("myusername", "mydomain", "password", true, true, true, true, authorities);
|
||||
}
|
||||
|
||||
}
|
@ -37,6 +37,7 @@ public class BasicAuthConfigurationIntegrationTest {
|
||||
@Test
|
||||
public void whenLoggedUserRequestsHomePage_ThenSuccess() throws IllegalStateException, IOException {
|
||||
ResponseEntity<String> response = restTemplate.getForEntity(base.toString(), String.class);
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertTrue(response
|
||||
.getBody()
|
||||
@ -47,6 +48,7 @@ public class BasicAuthConfigurationIntegrationTest {
|
||||
public void whenUserWithWrongCredentialsRequestsHomePage_ThenUnauthorizedPage() throws IllegalStateException, IOException {
|
||||
restTemplate = new TestRestTemplate("user", "wrongpassword");
|
||||
ResponseEntity<String> response = restTemplate.getForEntity(base.toString(), String.class);
|
||||
|
||||
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
|
||||
assertTrue(response
|
||||
.getBody()
|
||||
|
@ -2,10 +2,7 @@ package com.baeldung.springbootsecurity.oauth2server;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
||||
@ -13,7 +10,6 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
@ -21,54 +17,35 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootAuthorizationServerApplication.class)
|
||||
@ActiveProfiles("authz")
|
||||
public class CustomConfigAuthorizationServerIntegrationTest {
|
||||
|
||||
@Value("${local.server.port}") protected int port;
|
||||
public class CustomConfigAuthorizationServerIntegrationTest extends OAuth2IntegrationTestSupport {
|
||||
|
||||
@Test
|
||||
public void whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
|
||||
resourceDetails.setClientId("baeldung");
|
||||
resourceDetails.setClientSecret("baeldung");
|
||||
resourceDetails.setScope(singletonList("read"));
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
public void givenOAuth2Context_whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails("baeldung", singletonList("read"));
|
||||
OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
|
||||
|
||||
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
|
||||
|
||||
assertNotNull(accessToken);
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = OAuth2AccessDeniedException.class)
|
||||
public void whenAccessTokenIsRequestedWithInvalidException_ThenExceptionIsThrown() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
|
||||
resourceDetails.setClientId("baeldung");
|
||||
resourceDetails.setClientSecret("baeldung");
|
||||
resourceDetails.setScope(singletonList("write"));
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
public void givenOAuth2Context_whenAccessTokenIsRequestedWithInvalidException_ThenExceptionIsThrown() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails("baeldung", singletonList("write"));
|
||||
OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
|
||||
|
||||
restTemplate.getAccessToken();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAccessTokenIsRequestedByClientWithWriteScope_ThenAccessTokenIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails();
|
||||
resourceDetails.setClientId("baeldung-admin");
|
||||
resourceDetails.setClientSecret("baeldung");
|
||||
resourceDetails.setScope(singletonList("write"));
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
|
||||
assertNotNull(accessToken);
|
||||
}
|
||||
public void givenOAuth2Context_whenAccessTokenIsRequestedByClientWithWriteScope_ThenAccessTokenIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails("baeldung-admin", singletonList("write"));
|
||||
OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
|
||||
|
||||
private ClientCredentialsResourceDetails getClientCredentialsResourceDetails() {
|
||||
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
|
||||
resourceDetails.setAccessTokenUri(format("http://localhost:%d/oauth/token", port));
|
||||
resourceDetails.setGrantType("client_credentials");
|
||||
return resourceDetails;
|
||||
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
|
||||
|
||||
assertNotNull(accessToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,40 +2,28 @@ package com.baeldung.springbootsecurity.oauth2server;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = SpringBootAuthorizationServerApplication.class,
|
||||
properties = { "security.oauth2.client.client-id=client", "security.oauth2.client.client-secret=secret" })
|
||||
public class DefaultConfigAuthorizationServerIntegrationTest {
|
||||
|
||||
@Value("${local.server.port}") protected int port;
|
||||
properties = { "security.oauth2.client.client-id=client", "security.oauth2.client.client-secret=baeldung" })
|
||||
public class DefaultConfigAuthorizationServerIntegrationTest extends OAuth2IntegrationTestSupport {
|
||||
|
||||
@Test
|
||||
public void whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
|
||||
resourceDetails.setAccessTokenUri(format("http://localhost:%d/oauth/token", port));
|
||||
resourceDetails.setClientId("client");
|
||||
resourceDetails.setClientSecret("secret");
|
||||
resourceDetails.setGrantType("client_credentials");
|
||||
resourceDetails.setScope(asList("read", "write"));
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
public void givenOAuth2Context_whenAccessTokenIsRequested_ThenAccessTokenValueIsNotNull() {
|
||||
ClientCredentialsResourceDetails resourceDetails = getClientCredentialsResourceDetails("client", asList("read", "write"));
|
||||
OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);
|
||||
|
||||
OAuth2AccessToken accessToken = restTemplate.getAccessToken();
|
||||
|
||||
assertNotNull(accessToken);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
package com.baeldung.springbootsecurity.oauth2server;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
public class OAuth2IntegrationTestSupport {
|
||||
|
||||
@Value("${local.server.port}") protected int port;
|
||||
|
||||
protected ClientCredentialsResourceDetails getClientCredentialsResourceDetails(final String clientId, final List<String> scopes) {
|
||||
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
|
||||
resourceDetails.setAccessTokenUri(format("http://localhost:%d/oauth/token", port));
|
||||
resourceDetails.setClientId(clientId);
|
||||
resourceDetails.setClientSecret("baeldung");
|
||||
resourceDetails.setScope(scopes);
|
||||
resourceDetails.setGrantType("client_credentials");
|
||||
return resourceDetails;
|
||||
}
|
||||
|
||||
protected OAuth2RestTemplate getOAuth2RestTemplate(final ClientCredentialsResourceDetails resourceDetails) {
|
||||
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
|
||||
restTemplate.setMessageConverters(singletonList(new MappingJackson2HttpMessageConverter()));
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
@ -167,6 +167,12 @@
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.rometools</groupId>
|
||||
<artifactId>rome</artifactId>
|
||||
<version>${rome.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@ -276,6 +282,7 @@
|
||||
<tomee-servlet-api.version>8.5.11</tomee-servlet-api.version>
|
||||
<h2.version>1.4.194</h2.version>
|
||||
<togglz.version>2.4.1.Final</togglz.version>
|
||||
<rome.version>1.9.0</rome.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -6,14 +6,12 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@ComponentScan(basePackages = "com.baeldung.internationalization.config")
|
||||
public class MvcConfig extends WebMvcConfigurerAdapter {
|
||||
|
||||
@ -33,6 +31,6 @@ public class MvcConfig extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(localeChangeInterceptor());
|
||||
registry.addInterceptor(localeChangeInterceptor());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package com.baeldung.rss;
|
||||
|
||||
import com.rometools.rome.feed.rss.Channel;
|
||||
import com.rometools.rome.feed.rss.Description;
|
||||
import com.rometools.rome.feed.rss.Item;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service("articleFeedView")
|
||||
public class ArticleFeedView extends AbstractRssFeedView {
|
||||
|
||||
protected Channel newFeed() {
|
||||
Channel channel = new Channel("rss_2.0");
|
||||
channel.setLink("http://localhost:8080/rss");
|
||||
channel.setTitle("Article Feed");
|
||||
channel.setDescription("Article Feed Description");
|
||||
channel.setPubDate(new Date());
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Item> buildFeedItems(Map<String, Object> map, HttpServletRequest httpStRequest, HttpServletResponse httpStResponse) throws Exception {
|
||||
List list = new ArrayList<Item>();
|
||||
|
||||
Item item1 = new Item();
|
||||
item1.setLink("http://www.baeldung.com/netty-exception-handling");
|
||||
item1.setTitle("Exceptions in Netty");
|
||||
Description description1 = new Description();
|
||||
description1.setValue("In this quick article, we’ll be looking at exception handling in Netty.");
|
||||
item1.setDescription(description1);
|
||||
item1.setPubDate(new Date());
|
||||
item1.setAuthor("Carlos");
|
||||
|
||||
Item item2 = new Item();
|
||||
item2.setLink("http://www.baeldung.com/cockroachdb-java");
|
||||
item2.setTitle("Guide to CockroachDB in Java");
|
||||
Description description2 = new Description();
|
||||
description2.setValue("This tutorial is an introductory guide to using CockroachDB with Java.");
|
||||
item2.setDescription(description2);
|
||||
item2.setPubDate(new Date());
|
||||
item2.setAuthor("Baeldung");
|
||||
|
||||
list.add(item1);
|
||||
list.add(item2);
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.rss;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/rss", produces = "application/*")
|
||||
public class ArticleRssController {
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public String articleFeed() {
|
||||
return "articleFeedView";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.rss;
|
||||
|
||||
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
|
||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CustomContainer implements EmbeddedServletContainerCustomizer {
|
||||
|
||||
@Override
|
||||
public void customize(ConfigurableEmbeddedServletContainer container) {
|
||||
container.setPort(8080);
|
||||
container.setContextPath("");
|
||||
}
|
||||
|
||||
}
|
20
spring-boot/src/main/java/com/baeldung/rss/RssApp.java
Normal file
20
spring-boot/src/main/java/com/baeldung/rss/RssApp.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.baeldung.rss;
|
||||
|
||||
import com.baeldung.autoconfiguration.MySQLAutoconfiguration;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
|
||||
@SpringBootApplication(exclude = MySQLAutoconfiguration.class)
|
||||
@ComponentScan(basePackages = "com.baeldung.rss")
|
||||
public class RssApp {
|
||||
|
||||
@RolesAllowed("*")
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("security.basic.enabled", "false");
|
||||
SpringApplication.run(RssApp.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.ServletRequestBindingException;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
@ -2,7 +2,6 @@ package com.baeldung.webjar;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
import com.baeldung.autoconfiguration.MySQLAutoconfiguration;
|
||||
|
||||
|
@ -5,7 +5,6 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.Set;
|
||||
|
||||
public class GenericBigDecimalConverter implements GenericConverter {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.baeldung.boot.converter.controller;
|
||||
|
||||
import com.baeldung.toggle.Employee;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
@ -11,7 +11,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
$(document).ready(function() {
|
||||
$("#locales").change(function () {
|
||||
var selectedOption = $('#locales').val();
|
||||
if (selectedOption != ''){
|
||||
window.location.replace('international?lang=' + selectedOption);
|
||||
}
|
||||
});
|
||||
});
|
@ -4,16 +4,7 @@
|
||||
<meta charset="ISO-8859-1" />
|
||||
<title>Home</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$("#locales").change(function () {
|
||||
var selectedOption = $('#locales').val();
|
||||
if (selectedOption != ''){
|
||||
window.location.replace('international?lang=' + selectedOption);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script src="internationalization.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 th:text="#{greeting}"></h1>
|
||||
|
@ -10,8 +10,6 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.subethamail.wiser.Wiser;
|
||||
import org.subethamail.wiser.WiserMessage;
|
||||
|
||||
|
@ -12,13 +12,11 @@
|
||||
|
||||
Client-side service discovery allows services to find and communicate with each other without hardcoding hostname and port. The only ‘fixed point’ in such an architecture consists of a service registry with which each service has to register.
|
||||
|
||||
### Relevant Articles:
|
||||
- [Intro to Spring Cloud Netflix - Hystrix](http://www.baeldung.com/spring-cloud-netflix-hystrix)
|
||||
- [Dockerizing a Spring Boot Application](http://www.baeldung.com/dockerizing-spring-boot-application)
|
||||
- [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon)
|
||||
- [A Quick Guide to Spring Cloud Consul](http://www.baeldung.com/spring-cloud-consul)
|
||||
|
||||
### Relevant Articles:
|
||||
- [Introduction to Spring Cloud Rest Client with Netflix Ribbon](http://www.baeldung.com/spring-cloud-rest-client-with-netflix-ribbon)
|
||||
- [An Introduction to Spring Cloud Zookeeper](http://www.baeldung.com/spring-cloud-zookeeper)
|
||||
- [Using a Spring Cloud App Starter](http://www.baeldung.com/using-a-spring-cloud-app-starter)
|
||||
- [Spring Cloud Connectors and Heroku](http://www.baeldung.com/spring-cloud-heroku)
|
||||
|
||||
|
@ -19,3 +19,8 @@ to write the following in `application.properties`:
|
||||
cloud.aws.rds.spring-cloud-test-db
|
||||
cloud.aws.rds.spring-cloud-test-db.password=se3retpass
|
||||
```
|
||||
Multiple application classes are available under this project. To launch InstanceProfileAwsApplication application, replace `start-class` under `pom.xml`:
|
||||
|
||||
```
|
||||
<start-class>com.baeldung.spring.cloud.aws.InstanceProfileAwsApplication</start-class>
|
||||
```
|
@ -19,6 +19,7 @@
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<start-class>com.baeldung.spring.cloud.aws.SpringCloudAwsApplication</start-class>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
|
@ -0,0 +1,60 @@
|
||||
package com.baeldung.spring.cloud.aws;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.baeldung.spring.cloud.aws.s3.SpringCloudS3Service;
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan("com.baeldung.spring.cloud.aws.s3")
|
||||
public class InstanceProfileAwsApplication {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InstanceProfileAwsApplication.class);
|
||||
private static final String applicationConfig = "spring.config.name:application-instance-profile";
|
||||
|
||||
private static String bucketName;
|
||||
private static String fileName = "sample-file.txt";
|
||||
|
||||
private static void setupResources() {
|
||||
bucketName = "baeldung-test-" + UUID.randomUUID()
|
||||
.toString();
|
||||
try {
|
||||
Files.write(Paths.get(fileName), "Hello World!".getBytes());
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
setupResources();
|
||||
if (!new File(fileName).exists()) {
|
||||
logger.warn("Not able to create {} file. Check your folder permissions.", fileName);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
SpringApplication application = new SpringApplicationBuilder(InstanceProfileAwsApplication.class).properties(applicationConfig)
|
||||
.build();
|
||||
ConfigurableApplicationContext context = application.run(args);
|
||||
SpringCloudS3Service service = context.getBean(SpringCloudS3Service.class);
|
||||
|
||||
// S3 bucket operations
|
||||
service.createBucket(bucketName);
|
||||
service.uploadObject(bucketName, fileName);
|
||||
service.downloadObject(bucketName, fileName);
|
||||
service.deleteBucket(bucketName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.baeldung.spring.cloud.aws.s3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.model.ListObjectsV2Result;
|
||||
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
||||
|
||||
@Component
|
||||
public class SpringCloudS3Service {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SpringCloudS3Service.class);
|
||||
|
||||
@Autowired
|
||||
AmazonS3 amazonS3;
|
||||
|
||||
@Autowired
|
||||
SpringCloudS3 springCloudS3;
|
||||
|
||||
public void createBucket(String bucketName) {
|
||||
logger.debug("Creating S3 bucket: {}", bucketName);
|
||||
amazonS3.createBucket(bucketName);
|
||||
logger.info("{} bucket created successfully", bucketName);
|
||||
}
|
||||
|
||||
public void downloadObject(String bucketName, String objectName) {
|
||||
String s3Url = "s3://" + bucketName + "/" + objectName;
|
||||
try {
|
||||
springCloudS3.downloadS3Object(s3Url);
|
||||
logger.info("{} file download result: {}", objectName, new File(objectName).exists());
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void uploadObject(String bucketName, String objectName) {
|
||||
String s3Url = "s3://" + bucketName + "/" + objectName;
|
||||
File file = new File(objectName);
|
||||
try {
|
||||
springCloudS3.uploadFileToS3(file, s3Url);
|
||||
logger.info("{} file uploaded to S3", objectName);
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteBucket(String bucketName) {
|
||||
logger.trace("Deleting S3 objects under {} bucket...", bucketName);
|
||||
ListObjectsV2Result listObjectsV2Result = amazonS3.listObjectsV2(bucketName);
|
||||
for (S3ObjectSummary objectSummary : listObjectsV2Result.getObjectSummaries()) {
|
||||
logger.info("Deleting S3 object: {}", objectSummary.getKey());
|
||||
amazonS3.deleteObject(bucketName, objectSummary.getKey());
|
||||
}
|
||||
logger.info("Deleting S3 bucket: {}", bucketName);
|
||||
amazonS3.deleteBucket(bucketName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Metadata:
|
||||
'AWS::CloudFormation::Designer':
|
||||
157e7d5f-5cb3-4a23-a50c-97e7f6c57173:
|
||||
size:
|
||||
width: 60
|
||||
height: 60
|
||||
position:
|
||||
x: 450
|
||||
'y': 90
|
||||
z: 0
|
||||
embeds: []
|
||||
9bbaaa55-9cba-4555-a7c6-fb6ac248fd3a:
|
||||
size:
|
||||
width: 60
|
||||
height: 60
|
||||
position:
|
||||
x: 260
|
||||
'y': 90
|
||||
z: 0
|
||||
embeds: []
|
||||
isassociatedwith:
|
||||
- 157e7d5f-5cb3-4a23-a50c-97e7f6c57173
|
||||
a7348729-a594-4dca-9b0a-e1c8d777dc3b:
|
||||
size:
|
||||
width: 60
|
||||
height: 60
|
||||
position:
|
||||
x: 70
|
||||
'y': 90
|
||||
z: 0
|
||||
embeds: []
|
||||
Resources:
|
||||
IAMRoleBaeldung:
|
||||
Type: 'AWS::IAM::Role'
|
||||
Properties:
|
||||
AssumeRolePolicyDocument:
|
||||
Version: 2012-10-17
|
||||
Statement:
|
||||
- Effect: Allow
|
||||
Principal:
|
||||
Service:
|
||||
- ec2.amazonaws.com
|
||||
Action:
|
||||
- 'sts:AssumeRole'
|
||||
ManagedPolicyArns:
|
||||
- 'arn:aws:iam::aws:policy/AmazonS3FullAccess'
|
||||
Metadata:
|
||||
'AWS::CloudFormation::Designer':
|
||||
id: 157e7d5f-5cb3-4a23-a50c-97e7f6c57173
|
||||
InstanceProfileBaeldung:
|
||||
Type: 'AWS::IAM::InstanceProfile'
|
||||
Properties:
|
||||
Roles:
|
||||
- !Ref IAMRoleBaeldung
|
||||
Metadata:
|
||||
'AWS::CloudFormation::Designer':
|
||||
id: 9bbaaa55-9cba-4555-a7c6-fb6ac248fd3a
|
||||
EC2Instance:
|
||||
Type: 'AWS::EC2::Instance'
|
||||
Properties:
|
||||
ImageId: ami-2581aa40
|
||||
InstanceType: t2.micro
|
||||
IamInstanceProfile: !Ref InstanceProfileBaeldung
|
||||
KeyName: Satish-Ohio
|
||||
UserData: !Base64
|
||||
'Fn::Join':
|
||||
- ''
|
||||
- - |
|
||||
#!/bin/bash
|
||||
- |
|
||||
apt -y install openjdk-8-jre-headless
|
||||
Metadata:
|
||||
'AWS::CloudFormation::Designer':
|
||||
id: a7348729-a594-4dca-9b0a-e1c8d777dc3b
|
||||
DependsOn:
|
||||
- InstanceProfileBaeldung
|
||||
|
@ -0,0 +1,14 @@
|
||||
# Don't try to create DataSouce when running tests which don't need a DataSource
|
||||
spring.autoconfigure.exclude=\
|
||||
org.springframework.cloud.aws.autoconfigure.jdbc.AmazonRdsDatabaseAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
|
||||
cloud.aws.region.auto=true
|
||||
|
||||
# Load instance profile credentials
|
||||
cloud.aws.credentials.instanceProfile=true
|
||||
|
||||
# Disable auto cloud formation
|
||||
cloud.aws.stack.auto=false
|
||||
|
||||
# Disable web environment
|
||||
spring.main.web-environment=false
|
46
spring-cloud/spring-cloud-stream-starters/bash/hadoop.sh
Normal file
46
spring-cloud/spring-cloud-stream-starters/bash/hadoop.sh
Normal file
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# For Ubuntu 14.04
|
||||
# Inspired from: https://github.com/curran/setupHadoop/blob/master/setupHadoop.sh
|
||||
# Use from the user directory
|
||||
|
||||
# Install Java
|
||||
sudo apt-get update
|
||||
sudo add-apt-repository -y ppa:webupd8team/java
|
||||
sudo apt-get install -y oracle-java8-installer
|
||||
|
||||
# Install Hadoop
|
||||
curl -O http://mirror.cogentco.com/pub/apache/hadoop/common/hadoop-2.8.2/hadoop-2.8.2.tar.gz
|
||||
tar xfz hadoop-2.8.2.tar.gz
|
||||
sudo mv hadoop-2.8.2 /usr/local/hadoop
|
||||
rm hadoop-2.8.2.tar.gz
|
||||
|
||||
# Environmental Variables
|
||||
echo export JAVA_HOME=/usr/lib/jvm/java-8-oracle >> ~/.bashrc
|
||||
echo export HADOOP_PREFIX=/usr/local/hadoop >> ~/.bashrc
|
||||
echo export PATH=\$PATH:/usr/local/hadoop/bin >> ~/.bashrc
|
||||
echo export PATH=\$PATH:/usr/local/hadoop/sbin >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
# Copy configuration files
|
||||
cp master/* /usr/local/hadoop/etc/hadoop/
|
||||
|
||||
# Format HDFS
|
||||
hdfs namenode -format
|
||||
|
||||
# SSH keys for Hadoop to use.
|
||||
ssh-keygen -t rsa -P 'password' -f ~/.ssh/id_rsa.pub
|
||||
sudo mv ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys
|
||||
|
||||
# SSH
|
||||
ssh localhost
|
||||
# authenticate with osboxes.org
|
||||
|
||||
# Start NameNode daemon and DataNode daemon
|
||||
start-dfs.sh
|
||||
# stop-dfs.sh
|
||||
|
||||
# Install Maven
|
||||
sudo apt-get install maven
|
||||
|
||||
# Access Hadoop - http://localhost:50070
|
3
spring-cloud/spring-cloud-stream-starters/boot/.gitignore
vendored
Normal file
3
spring-cloud/spring-cloud-stream-starters/boot/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.idea
|
||||
*/target/*
|
||||
*.iml
|
55
spring-cloud/spring-cloud-stream-starters/boot/pom.xml
Normal file
55
spring-cloud/spring-cloud-stream-starters/boot/pom.xml
Normal file
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0"?>
|
||||
<project 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"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung.twitterhdfs</groupId>
|
||||
<artifactId>twitterhdfs</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<name>twitterhdfs</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>1.5.8.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Stream Starter Apps -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud.stream.app</groupId>
|
||||
<artifactId>spring-cloud-starter-stream-source-twitterstream</artifactId>
|
||||
<version>1.3.1.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud.stream.app</groupId>
|
||||
<artifactId>spring-cloud-starter-stream-sink-hdfs</artifactId>
|
||||
<version>1.3.1.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JSTL/JSP -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<finalName>twitterhdfs</finalName>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,18 @@
|
||||
package com.baeldung.twitterhdfs.aggregate;
|
||||
|
||||
import com.baeldung.twitterhdfs.processor.ProcessorApp;
|
||||
import com.baeldung.twitterhdfs.source.SourceApp;
|
||||
import com.baeldung.twitterhdfs.sink.SinkApp;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.stream.aggregate.AggregateApplicationBuilder;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AggregateApp {
|
||||
public static void main(String[] args) {
|
||||
new AggregateApplicationBuilder()
|
||||
.from(SourceApp.class).args("--fixedDelay=5000")
|
||||
.via(ProcessorApp.class)
|
||||
.to(SinkApp.class).args("--debug=true")
|
||||
.run(args);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.baeldung.twitterhdfs.processor;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.messaging.Processor;
|
||||
import org.springframework.integration.annotation.Transformer;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableBinding(Processor.class)
|
||||
public class ProcessorApp {
|
||||
Logger log = LoggerFactory.getLogger(ProcessorApp.class);
|
||||
|
||||
@Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
|
||||
public String processMessage(String payload) {
|
||||
log.info("Payload received!");
|
||||
return payload;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.baeldung.twitterhdfs.sink;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.app.hdfs.sink.HdfsSinkConfiguration;
|
||||
import org.springframework.cloud.stream.messaging.Sink;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableBinding(Sink.class)
|
||||
@Import(HdfsSinkConfiguration.class)
|
||||
public class SinkApp {
|
||||
Logger log = LoggerFactory.getLogger(SinkApp.class);
|
||||
|
||||
@ServiceActivator(inputChannel= Sink.INPUT)
|
||||
public void loggerSink(Object payload) {
|
||||
log.info("Received: " + payload);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.baeldung.twitterhdfs.source;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.app.twitterstream.source.TwitterstreamSourceConfiguration;
|
||||
import org.springframework.cloud.stream.messaging.Source;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.integration.annotation.InboundChannelAdapter;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableBinding(Source.class)
|
||||
@Import(TwitterstreamSourceConfiguration.class)
|
||||
public class SourceApp {
|
||||
Logger log = LoggerFactory.getLogger(SourceApp.class);
|
||||
|
||||
@InboundChannelAdapter(value = Source.OUTPUT)
|
||||
public String timerMessageSource() {
|
||||
return new SimpleDateFormat().format(new Date());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
hdfs.fs-uri=hdfs://127.0.0.1:50010/
|
||||
|
||||
twitter.credentials.access-token=
|
||||
twitter.credentials.access-token-secret=
|
||||
twitter.credentials.consumer-key=
|
||||
twitter.credentials.consumer-secret=
|
@ -0,0 +1 @@
|
||||
hdfs.fs-uri=hdfs://127.0.0.1:50010/
|
11
spring-cloud/spring-cloud-stream-starters/hdfs/hdfs.sh
Normal file
11
spring-cloud/spring-cloud-stream-starters/hdfs/hdfs.sh
Normal file
@ -0,0 +1,11 @@
|
||||
# Git spring-cloud-stream-app-starters
|
||||
# https://github.com/spring-cloud-stream-app-starters/hdfs/blob/master/spring-cloud-starter-stream-sink-hdfs/README.adoc
|
||||
git clone https://github.com/spring-cloud-stream-app-starters/hdfs.git
|
||||
|
||||
# Build it
|
||||
./mvnw clean install -PgenerateApps
|
||||
|
||||
# Run it
|
||||
cd target
|
||||
# Optionally inject application.properties prior to build
|
||||
java -jar hdfs-sink.jar --fsUri=hdfs://127.0.0.1:50010/
|
@ -0,0 +1,4 @@
|
||||
twitter.credentials.access-token=
|
||||
twitter.credentials.access-token-secret=
|
||||
twitter.credentials.consumer-key=
|
||||
twitter.credentials.consumer-secret=
|
12
spring-cloud/spring-cloud-stream-starters/twitter/twitter.sh
Normal file
12
spring-cloud/spring-cloud-stream-starters/twitter/twitter.sh
Normal file
@ -0,0 +1,12 @@
|
||||
# Git spring-cloud-stream-app-starters
|
||||
# https://github.com/spring-cloud-stream-app-starters/hdfs/blob/master/spring-cloud-starter-stream-sink-hdfs/README.adoc
|
||||
git clone https://github.com/spring-cloud-stream-app-starters/twitter.git
|
||||
|
||||
# Build it
|
||||
./mvnw clean install -PgenerateApps
|
||||
|
||||
# Run it
|
||||
cd target
|
||||
# Optionally inject application.properties prior to build
|
||||
java -jar twitter_stream_source.jar --consumerKey=<CONSUMER_KEY> --consumerSecret=<CONSUMER_SECRET> \
|
||||
--accessToken=<ACCESS_TOKEN> --accessTokenSecret=<ACCESS_TOKEN_SECRET>
|
@ -1,12 +1,13 @@
|
||||
package com.baeldung.spring.data.es.repository;
|
||||
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.annotations.Query;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
|
||||
@Repository
|
||||
public interface ArticleRepository extends ElasticsearchRepository<Article, String> {
|
||||
|
||||
@ -14,4 +15,10 @@ public interface ArticleRepository extends ElasticsearchRepository<Article, Stri
|
||||
|
||||
@Query("{\"bool\": {\"must\": [{\"match\": {\"authors.name\": \"?0\"}}]}}")
|
||||
Page<Article> findByAuthorsNameUsingCustomQuery(String name, Pageable pageable);
|
||||
|
||||
@Query("{\"bool\": {\"must\": {\"match_all\": {}}, \"filter\": {\"term\": {\"tags\": \"?0\" }}}}")
|
||||
Page<Article> findByFilteredTagQuery(String tag, Pageable pageable);
|
||||
|
||||
@Query("{\"bool\": {\"must\": {\"match\": {\"authors.name\": \"?0\"}}, \"filter\": {\"term\": {\"tags\": \"?1\" }}}}")
|
||||
Page<Article> findByAuthorsNameAndFilteredTagQuery(String name, String tag, Pageable pageable);
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package com.baeldung.spring.data.es.service;
|
||||
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
|
||||
public interface ArticleService {
|
||||
Article save(Article article);
|
||||
|
||||
@ -15,6 +16,10 @@ public interface ArticleService {
|
||||
|
||||
Page<Article> findByAuthorNameUsingCustomQuery(String name, Pageable pageable);
|
||||
|
||||
Page<Article> findByFilteredTagQuery(String tag, Pageable pageable);
|
||||
|
||||
Page<Article> findByAuthorsNameAndFilteredTagQuery(String name, String tag, Pageable pageable);
|
||||
|
||||
long count();
|
||||
|
||||
void delete(Article article);
|
||||
|
@ -1,12 +1,13 @@
|
||||
package com.baeldung.spring.data.es.service;
|
||||
|
||||
import com.baeldung.spring.data.es.repository.ArticleRepository;
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baeldung.spring.data.es.model.Article;
|
||||
import com.baeldung.spring.data.es.repository.ArticleRepository;
|
||||
|
||||
@Service
|
||||
public class ArticleServiceImpl implements ArticleService {
|
||||
|
||||
@ -42,6 +43,16 @@ public class ArticleServiceImpl implements ArticleService {
|
||||
return articleRepository.findByAuthorsNameUsingCustomQuery(name, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Article> findByFilteredTagQuery(String tag, Pageable pageable) {
|
||||
return articleRepository.findByFilteredTagQuery(tag, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Article> findByAuthorsNameAndFilteredTagQuery(String name, String tag, Pageable pageable) {
|
||||
return articleRepository.findByAuthorsNameAndFilteredTagQuery(name, tag, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return articleRepository.count();
|
||||
|
@ -46,14 +46,22 @@ public class ElasticSearchIntegrationTest {
|
||||
|
||||
Article article = new Article("Spring Data Elasticsearch");
|
||||
article.setAuthors(asList(johnSmith, johnDoe));
|
||||
article.setTags("elasticsearch", "spring data");
|
||||
articleService.save(article);
|
||||
|
||||
article = new Article("Search engines");
|
||||
article.setAuthors(asList(johnDoe));
|
||||
article.setTags("search engines", "tutorial");
|
||||
articleService.save(article);
|
||||
|
||||
article = new Article("Second Article About Elasticsearch");
|
||||
article.setAuthors(asList(johnSmith));
|
||||
article.setTags("elasticsearch", "spring data");
|
||||
articleService.save(article);
|
||||
|
||||
article = new Article("Elasticsearch Tutorial");
|
||||
article.setAuthors(asList(johnDoe));
|
||||
article.setTags("elasticsearch");
|
||||
articleService.save(article);
|
||||
}
|
||||
|
||||
@ -78,12 +86,22 @@ public class ElasticSearchIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void givenCustomQuery_whenSearchByAuthorsName_thenArticleIsFound() {
|
||||
final Page<Article> articleByAuthorName = articleService.findByAuthorNameUsingCustomQuery("Smith", new PageRequest(0, 10));
|
||||
assertEquals(2L, articleByAuthorName.getTotalElements());
|
||||
}
|
||||
|
||||
final Page<Article> articleByAuthorName = articleService
|
||||
.findByAuthorNameUsingCustomQuery("John Smith", new PageRequest(0, 10));
|
||||
@Test
|
||||
public void givenTagFilterQuery_whenSearchByTag_thenArticleIsFound() {
|
||||
final Page<Article> articleByAuthorName = articleService.findByFilteredTagQuery("elasticsearch", new PageRequest(0, 10));
|
||||
assertEquals(3L, articleByAuthorName.getTotalElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTagFilterQuery_whenSearchByAuthorsName_thenArticleIsFound() {
|
||||
final Page<Article> articleByAuthorName = articleService.findByAuthorsNameAndFilteredTagQuery("Doe", "elasticsearch", new PageRequest(0, 10));
|
||||
assertEquals(2L, articleByAuthorName.getTotalElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPersistedArticles_whenUseRegexQuery_thenRightArticlesFound() {
|
||||
|
||||
|
@ -191,4 +191,16 @@ public class ElasticSearchQueryIntegrationTest {
|
||||
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
|
||||
assertEquals(2, articles.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenBoolQuery_whenQueryByAuthorsName_thenFoundArticlesByThatAuthorAndFilteredTag() {
|
||||
final QueryBuilder builder = boolQuery().must(nestedQuery("authors", boolQuery().must(termQuery("authors.name", "doe"))))
|
||||
.filter(termQuery("tags", "elasticsearch"));
|
||||
|
||||
final SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder)
|
||||
.build();
|
||||
final List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
|
||||
|
||||
assertEquals(2, articles.size());
|
||||
}
|
||||
}
|
||||
|
1
spring-mvc-push/.gitignore
vendored
1
spring-mvc-push/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/.tern-project
|
@ -1,91 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>spring-mvc-push</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-mvc-push</name>
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven-surefire-plugin.version>2.20</maven-surefire-plugin.version>
|
||||
<maven.compiler.version>3.7.0</maven.compiler.version>
|
||||
<maven-war-plugin.version>3.2.0</maven-war-plugin.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<junit.jupiter.version>5.0.2</junit.jupiter.version>
|
||||
<spring.version>5.0.2.RELEASE</spring.version>
|
||||
<servlet.version>4.0.0</servlet.version>
|
||||
<jstl.version>1.2</jstl.version>
|
||||
<jsp-api.version>2.3.2-b02</jsp-api.version>
|
||||
<junit.jupiter.version>5.0.2</junit.jupiter.version>
|
||||
<junit.platform.version>1.0.2</junit.platform.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>${servlet.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
<version>${jstl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>javax.servlet.jsp-api</artifactId>
|
||||
<version>${jsp-api.version}</version>
|
||||
</dependency>
|
||||
<!--Testing -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>${maven-war-plugin.version}</version>
|
||||
<configuration>
|
||||
<warName>spring-mvc-push</warName>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
<outputDirectory>${deploy-path}</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-surefire-provider</artifactId>
|
||||
<version>${junit.platform.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<finalName>spring-mvc-push</finalName>
|
||||
</build>
|
||||
</project>
|
@ -1,48 +0,0 @@
|
||||
package com.baeldung.config;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.WebApplicationInitializer;
|
||||
import org.springframework.web.context.ContextLoaderListener;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@ComponentScan(basePackages = "com.baeldung.controller")
|
||||
public class PushConfiguration implements WebApplicationInitializer, WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext container) throws ServletException {
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(PushConfiguration.class);
|
||||
container.addListener(new ContextLoaderListener(context));
|
||||
ServletRegistration.Dynamic dispatcher = container.addServlet("DispatcherServlet", new DispatcherServlet(context));
|
||||
dispatcher.setLoadOnStartup(1);
|
||||
dispatcher.addMapping("/");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InternalResourceViewResolver jspViewResolver() {
|
||||
InternalResourceViewResolver bean = new InternalResourceViewResolver();
|
||||
bean.setPrefix("/WEB-INF/views/");
|
||||
bean.setSuffix(".jsp");
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/resources/**")
|
||||
.addResourceLocations("/resources/");
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8"
|
||||
pageEncoding="UTF-8"%>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>PushBuilder demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<h4>
|
||||
Go to <a href="demoWithPush">PushBuilder demo</a><br> Go to
|
||||
<a href="demoWithoutPush">Simple demo</a>
|
||||
</h4>
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
console.log('Script')
|
@ -1,9 +0,0 @@
|
||||
.single-title {
|
||||
font-size: 30px;
|
||||
color: #535353;
|
||||
font-weight: 200;
|
||||
letter-spacing: -1.5px;
|
||||
line-height: 64px;
|
||||
max-width: 750px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user