diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorter.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorter.java new file mode 100644 index 0000000000..4d885a6b3a --- /dev/null +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorter.java @@ -0,0 +1,70 @@ +package com.baeldung.bucketsort; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class IntegerBucketSorter implements Sorter { + + private final Comparator comparator; + + public IntegerBucketSorter(Comparator comparator) { + this.comparator = comparator; + } + + public IntegerBucketSorter() { + comparator = Comparator.naturalOrder(); + } + + public List sort(List arrayToSort) { + + List> buckets = splitIntoUnsortedBuckets(arrayToSort); + + for(List bucket : buckets){ + bucket.sort(comparator); + } + + return concatenateSortedBuckets(buckets); + } + + private List concatenateSortedBuckets(List> buckets){ + List sortedArray = new ArrayList<>(); + int index = 0; + for(List bucket : buckets){ + for(int number : bucket){ + sortedArray.add(index++, number); + } + } + return sortedArray; + } + + private List> splitIntoUnsortedBuckets(List initialList){ + + final int[] codes = createHashes(initialList); + + List> buckets = new ArrayList<>(codes[1]); + for(int i = 0; i < codes[1]; i++) buckets.add(new ArrayList<>()); + + //distribute the data + for (int i : initialList) { + buckets.get(hash(i, codes)).add(i); + } + return buckets; + + } + + private int[] createHashes(List input){ + int m = input.get(0); + for (int i = 1; i < input.size(); i++) { + if (m < input.get(i)) { + m = input.get(i); + } + } + return new int[]{m, (int) Math.sqrt(input.size())}; + } + + private static int hash(int i, int[] code) { + return (int) ((double) i / code[0] * (code[1] - 1)); + } + +} diff --git a/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/bucketsort/Sorter.java b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/bucketsort/Sorter.java new file mode 100644 index 0000000000..b86f60324f --- /dev/null +++ b/algorithms-miscellaneous-3/src/main/java/com/baeldung/algorithms/bucketsort/Sorter.java @@ -0,0 +1,8 @@ +package com.baeldung.bucketsort; + +import java.util.List; + +public interface Sorter { + + List sort(List arrayToSort); +} diff --git a/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorterUnitTest.java b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorterUnitTest.java new file mode 100644 index 0000000000..2773d8a68f --- /dev/null +++ b/algorithms-miscellaneous-3/src/test/java/com/baeldung/algorithms/bucketsort/IntegerBucketSorterUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.bucketsort; + +import com.baeldung.bucketsort.IntegerBucketSorter; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class IntegerBucketSorterUnitTest { + + private IntegerBucketSorter sorter; + + @Before + public void setUp() throws Exception { + sorter = new IntegerBucketSorter(); + } + + @Test + public void givenUnsortedList_whenSortedUsingBucketSorter_checkSortingCorrect() { + + List unsorted = Arrays.asList(80,50,60,30,20,10,70,0,40,500,600,602,200,15); + List expected = Arrays.asList(0,10,15,20,30,40,50,60,70,80,200,500,600,602); + + List actual = sorter.sort(unsorted); + + assertEquals(expected, actual); + + + } +} \ No newline at end of file diff --git a/core-groovy-2/pom.xml b/core-groovy-2/pom.xml index ba3fd0802b..91e31d4cba 100644 --- a/core-groovy-2/pom.xml +++ b/core-groovy-2/pom.xml @@ -48,6 +48,11 @@ ${spock-core.version} test + + com.github.groovy-wslite + groovy-wslite + ${groovy-wslite.version} + @@ -175,6 +180,7 @@ 1.0.0 2.4.0 1.1-groovy-2.4 + 1.1.3 3.8.1 1.2.3 2.5.7 diff --git a/core-groovy-2/src/test/groovy/com/baeldung/webservice/WebserviceUnitTest.groovy b/core-groovy-2/src/test/groovy/com/baeldung/webservice/WebserviceUnitTest.groovy new file mode 100644 index 0000000000..302959d0d9 --- /dev/null +++ b/core-groovy-2/src/test/groovy/com/baeldung/webservice/WebserviceUnitTest.groovy @@ -0,0 +1,152 @@ +package com.baeldung.webservice + +import groovy.json.JsonSlurper +import wslite.rest.ContentType +import wslite.rest.RESTClient +import wslite.rest.RESTClientException +import wslite.soap.SOAPClient +import wslite.soap.SOAPMessageBuilder +import wslite.http.auth.HTTPBasicAuthorization +import org.junit.Test + +class WebserviceUnitTest extends GroovyTestCase { + + JsonSlurper jsonSlurper = new JsonSlurper() + + static RESTClient client = new RESTClient("https://postman-echo.com") + + static { + client.defaultAcceptHeader = ContentType.JSON + client.httpClient.sslTrustAllCerts = true + } + + void test_whenSendingGet_thenRespose200() { + def postmanGet = new URL('https://postman-echo.com/get') + def getConnection = postmanGet.openConnection() + getConnection.requestMethod = 'GET' + assert getConnection.responseCode == 200 + if (getConnection.responseCode == 200) { + assert jsonSlurper.parseText(getConnection.content.text)?.headers?.host == "postman-echo.com" + } + } + + void test_whenSendingPost_thenRespose200() { + def postmanPost = new URL('https://postman-echo.com/post') + def query = "q=This is post request form parameter." + def postConnection = postmanPost.openConnection() + postConnection.requestMethod = 'POST' + assert postConnection.responseCode == 200 + } + + void test_whenSendingPostWithParams_thenRespose200() { + def postmanPost = new URL('https://postman-echo.com/post') + def form = "param1=This is request parameter." + def postConnection = postmanPost.openConnection() + postConnection.requestMethod = 'POST' + postConnection.doOutput = true + def text + postConnection.with { + outputStream.withWriter { outputStreamWriter -> + outputStreamWriter << form + } + text = content.text + } + assert postConnection.responseCode == 200 + assert jsonSlurper.parseText(text)?.json.param1 == "This is request parameter." + } + + void test_whenReadingRSS_thenReceiveFeed() { + def rssFeed = new XmlParser().parse("https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en") + def stories = [] + (0..4).each { + def item = rssFeed.channel.item.get(it) + stories << item.title.text() + } + assert stories.size() == 5 + } + + void test_whenReadingAtom_thenReceiveFeed() { + def atomFeed = new XmlParser().parse("https://news.google.com/atom?hl=en-US&gl=US&ceid=US:en") + def stories = [] + (0..4).each { + def entry = atomFeed.entry.get(it) + stories << entry.title.text() + } + assert stories.size() == 5 + } + + void test_whenConsumingSoap_thenReceiveResponse() { + def url = "http://www.dataaccess.com/webservicesserver/numberconversion.wso" + def soapClient = new SOAPClient(url) + def message = new SOAPMessageBuilder().build({ + body { + NumberToWords(xmlns: "http://www.dataaccess.com/webservicesserver/") { + ubiNum(1234) + } + } + }) + def response = soapClient.send(message.toString()); + def words = response.NumberToWordsResponse + assert words == "one thousand two hundred and thirty four " + } + + void test_whenConsumingRestGet_thenReceiveResponse() { + def path = "/get" + def response + try { + response = client.get(path: path) + assert response.statusCode == 200 + assert response.json?.headers?.host == "postman-echo.com" + } catch (RESTClientException e) { + assert e?.response?.statusCode != 200 + } + } + + void test_whenConsumingRestPost_thenReceiveResponse() { + def path = "/post" + def params = ["foo":1,"bar":2] + def response + try { + response = client.post(path: path) { + type ContentType.JSON + json params + } + assert response.json?.data == params + } catch (RESTClientException e) { + e.printStackTrace() + assert e?.response?.statusCode != 200 + } + } + + void test_whenBasicAuthentication_thenReceive200() { + def path = "/basic-auth" + def response + try { + client.authorization = new HTTPBasicAuthorization("postman", "password") + response = client.get(path: path) + assert response.statusCode == 200 + assert response.json?.authenticated == true + } catch (RESTClientException e) { + e.printStackTrace() + assert e?.response?.statusCode != 200 + } + } + + void test_whenOAuth_thenReceive200() { + RESTClient oAuthClient = new RESTClient("https://postman-echo.com") + oAuthClient.defaultAcceptHeader = ContentType.JSON + oAuthClient.httpClient.sslTrustAllCerts = true + + def path = "/oauth1" + def params = [oauth_consumer_key: "RKCGzna7bv9YD57c", oauth_signature_method: "HMAC-SHA1", oauth_timestamp:1567089944, oauth_nonce: "URT7v4", oauth_version: 1.0, oauth_signature: 'RGgR/ktDmclkM0ISWaFzebtlO0A='] + def response + try { + response = oAuthClient.get(path: path, query: params) + assert response.statusCode == 200 + assert response.statusMessage == "OK" + assert response.json.status == "pass" + } catch (RESTClientException e) { + assert e?.response?.statusCode != 200 + } + } +} \ No newline at end of file diff --git a/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/java/list/RemoveFromList.java b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/java/list/RemoveFromList.java new file mode 100644 index 0000000000..df9b3d987d --- /dev/null +++ b/core-java-modules/core-java-collections-array-list/src/main/java/com/baeldung/java/list/RemoveFromList.java @@ -0,0 +1,40 @@ +package com.baeldung.java.list; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class RemoveFromList { + + public static void main(String[] args) { + List sports = new ArrayList<>(); + sports.add("Football"); + sports.add("Basketball"); + sports.add("Baseball"); + sports.add("Boxing"); + sports.add("Cycling"); + + System.out.println("List before removing: " + sports); + + // Remove with index + sports.remove(1); + + // Remove with an element + sports.remove("Baseball"); + + // Iterator remove method + Iterator iterator = sports.iterator(); + while (iterator.hasNext()) { + if (iterator.next().equals("Boxing")) { + iterator.remove(); + break; + } + } + + // ArrayList removeIf method (Java 8) + sports.removeIf(p -> p.equals("Cycling")); + + System.out.println("List after removing: " + sports); + } + +} diff --git a/core-java-modules/core-java-io-2/src/test/java/com/baeldung/filereader/FileReaderExampleUnitTest.java b/core-java-modules/core-java-io-2/src/test/java/com/baeldung/filereader/FileReaderExampleUnitTest.java index 968c041115..4f893fb327 100644 --- a/core-java-modules/core-java-io-2/src/test/java/com/baeldung/filereader/FileReaderExampleUnitTest.java +++ b/core-java-modules/core-java-io-2/src/test/java/com/baeldung/filereader/FileReaderExampleUnitTest.java @@ -17,15 +17,9 @@ public class FileReaderExampleUnitTest { public void givenFileReader_whenReadAllCharacters_thenReturnsContent() throws IOException { String expectedText = "Hello, World!"; File file = new File(FILE_PATH); - FileReader fileReader = null; - try { - fileReader = new FileReader(file); + try (FileReader fileReader = new FileReader(file)) { String content = FileReaderExample.readAllCharactersOneByOne(fileReader); Assert.assertEquals(expectedText, content); - } finally { - if (fileReader != null) { - fileReader.close(); - } } } @@ -33,15 +27,9 @@ public class FileReaderExampleUnitTest { public void givenFileReader_whenReadMultipleCharacters_thenReturnsContent() throws IOException { String expectedText = "Hello"; File file = new File(FILE_PATH); - FileReader fileReader = null; - try { - fileReader = new FileReader(file); + try (FileReader fileReader = new FileReader(file)) { String content = FileReaderExample.readMultipleCharacters(fileReader, 5); Assert.assertEquals(expectedText, content); - } finally { - if (fileReader != null) { - fileReader.close(); - } } } diff --git a/core-java-modules/core-java-io/pom.xml b/core-java-modules/core-java-io/pom.xml index 1a133d2cbe..84bf3baeed 100644 --- a/core-java-modules/core-java-io/pom.xml +++ b/core-java-modules/core-java-io/pom.xml @@ -207,6 +207,21 @@ ${maven.compiler.target} + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + + true + com.baeldung.resource.MyResourceLoader + + + + @@ -274,6 +289,8 @@ 1.18 0.1.5 + 3.1.0 + \ No newline at end of file diff --git a/core-java-modules/core-java-io/src/main/java/com/baeldung/resource/MyResourceLoader.java b/core-java-modules/core-java-io/src/main/java/com/baeldung/resource/MyResourceLoader.java new file mode 100644 index 0000000000..7512b177df --- /dev/null +++ b/core-java-modules/core-java-io/src/main/java/com/baeldung/resource/MyResourceLoader.java @@ -0,0 +1,42 @@ +package com.baeldung.resource; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.stream.Collectors; + +public class MyResourceLoader { + + private void loadFileWithReader() throws IOException { + + try (FileReader fileReader = new FileReader("src/main/resources/input.txt"); + BufferedReader reader = new BufferedReader(fileReader)) { + String contents = reader.lines() + .collect(Collectors.joining(System.lineSeparator())); + System.out.println(contents); + } + + } + + private void loadFileAsResource() throws IOException { + + try (InputStream inputStream = getClass().getResourceAsStream("/input.txt"); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String contents = reader.lines() + .collect(Collectors.joining(System.lineSeparator())); + System.out.println(contents); + } + } + + public static void main(String[] args) throws IOException { + + MyResourceLoader resourceLoader = new MyResourceLoader(); + + resourceLoader.loadFileAsResource(); + resourceLoader.loadFileWithReader(); + + } + +} diff --git a/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/copyconstructor/Employee.java b/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/copyconstructor/Employee.java new file mode 100644 index 0000000000..7ad445e8ee --- /dev/null +++ b/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/copyconstructor/Employee.java @@ -0,0 +1,30 @@ +package com.baeldung.copyconstructor; + +import java.util.Date; + +public class Employee { + + protected int id; + protected String name; + protected Date startDate; + + public Employee(int id, String name, Date startDate) { + this.id = id; + this.name = name; + this.startDate = startDate; + } + + public Employee(Employee employee) { + this.id = employee.id; + this.name = employee.name; + this.startDate = new Date(employee.startDate.getTime()); + } + + Date getStartDate() { + return startDate; + } + + public Employee copy() { + return new Employee(this); + } +} diff --git a/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/copyconstructor/Manager.java b/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/copyconstructor/Manager.java new file mode 100644 index 0000000000..97b8580b8e --- /dev/null +++ b/core-java-modules/core-java-lang-oop-2/src/main/java/com/baeldung/copyconstructor/Manager.java @@ -0,0 +1,31 @@ +package com.baeldung.copyconstructor; + +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +public class Manager extends Employee { + + private List directReports; + + public Manager(int id, String name, Date startDate, List directReports) { + super(id, name, startDate); + this.directReports = directReports; + } + + public Manager(Manager manager) { + super(manager.id, manager.name, manager.startDate); + this.directReports = manager.directReports.stream() + .collect(Collectors.toList()); + } + + @Override + public Employee copy() { + return new Manager(this); + } + + List getDirectReport() { + return this.directReports; + } + +} diff --git a/core-java-modules/core-java-lang-oop-2/src/test/java/com/baeldung/copyconstructor/EmployeeUnitTest.java b/core-java-modules/core-java-lang-oop-2/src/test/java/com/baeldung/copyconstructor/EmployeeUnitTest.java new file mode 100644 index 0000000000..19a4001b62 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-2/src/test/java/com/baeldung/copyconstructor/EmployeeUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.copyconstructor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import java.util.Date; + +import org.junit.Test; + +public class EmployeeUnitTest { + @Test + public void givenCopyConstructor_whenDeepCopy_thenDistinct() { + Date d1 = new Date(123); + Employee e1 = new Employee(1, "Baeldung", d1); + Employee e2 = new Employee(e1); + assertEquals(d1, e1.getStartDate()); + assertEquals(d1, e2.getStartDate()); + + d1.setTime(456); + assertEquals(d1, e1.getStartDate()); + assertNotEquals(d1, e2.getStartDate()); + } + + @Test + public void givenCopyMethod_whenCopy_thenDistinct() { + Date d1 = new Date(123); + Employee e1 = new Employee(1, "Baeldung", d1); + Employee e2 = e1.copy(); + assertEquals(d1, e1.getStartDate()); + assertEquals(d1, e2.getStartDate()); + + d1.setTime(456); + assertEquals(d1, e1.getStartDate()); + assertNotEquals(d1, e2.getStartDate()); + } +} diff --git a/core-java-modules/core-java-lang-oop-2/src/test/java/com/baeldung/copyconstructor/ManagerUnitTest.java b/core-java-modules/core-java-lang-oop-2/src/test/java/com/baeldung/copyconstructor/ManagerUnitTest.java new file mode 100644 index 0000000000..ef9f261360 --- /dev/null +++ b/core-java-modules/core-java-lang-oop-2/src/test/java/com/baeldung/copyconstructor/ManagerUnitTest.java @@ -0,0 +1,67 @@ +package com.baeldung.copyconstructor; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.junit.Test; + +public class ManagerUnitTest { + @Test + public void givenCopyConstructor_whenDeepCopy_thenDistinct() { + Date startDate = new Date(123); + Employee e1 = new Employee(1, "Baeldung", startDate); + Employee e2 = new Employee(e1); + List directReports = new ArrayList(); + directReports.add(e1); + directReports.add(e2); + + Manager m1 = new Manager(1, "Baeldung Manager", startDate, directReports); + Manager m2 = new Manager(m1); + List directReports1 = m1.getDirectReport(); + List directReports2 = m2.getDirectReport(); + assertEquals(directReports1.size(), directReports2.size()); + assertArrayEquals(directReports1.toArray(), directReports2.toArray()); + + // clear m1's direct reports list. m2's list should not be affected + directReports.clear(); + directReports1 = m1.getDirectReport(); + directReports2 = m2.getDirectReport(); + assertEquals(0, directReports1.size()); + assertEquals(2, directReports2.size()); + + } + + @Test + public void givenCopyMethod_whenCopy_thenDistinct() { + Date startDate = new Date(123); + Employee e1 = new Employee(1, "Baeldung", startDate); + Employee e2 = new Employee(e1); + List directReports = new ArrayList(); + directReports.add(e1); + directReports.add(e2); + + // a Manager object whose declaration type is Employee. + Employee source = new Manager(1, "Baeldung Manager", startDate, directReports); + Employee clone = source.copy(); + + // after copy, clone should be still a Manager object. + assertTrue(clone instanceof Manager); + List directReports1 = ((Manager) source).getDirectReport(); + List directReports2 = ((Manager) clone).getDirectReport(); + assertEquals(directReports1.size(), directReports2.size()); + assertArrayEquals(directReports1.toArray(), directReports2.toArray()); + + // clear source's direct reports list. clone's list should not be affected + directReports.clear(); + directReports1 = ((Manager) source).getDirectReport(); + directReports2 = ((Manager) clone).getDirectReport(); + assertEquals(0, directReports1.size()); + assertEquals(2, directReports2.size()); + + } +} diff --git a/core-java-modules/core-java-lang-operators/src/main/java/com/baeldung/booleanoperators/Car.java b/core-java-modules/core-java-lang-operators/src/main/java/com/baeldung/booleanoperators/Car.java new file mode 100644 index 0000000000..37fb139917 --- /dev/null +++ b/core-java-modules/core-java-lang-operators/src/main/java/com/baeldung/booleanoperators/Car.java @@ -0,0 +1,36 @@ +package com.baeldung.booleanoperators; + +public class Car { + + private boolean diesel; + private boolean manual; + + public Car(boolean diesel, boolean manual) { + this.diesel = diesel; + this.manual = manual; + } + + public boolean isDiesel() { + return diesel; + } + + public boolean isManual() { + return manual; + } + + static Car dieselAndManualCar() { + return new Car(true, true); + } + + static Car dieselAndAutomaticCar() { + return new Car(true, false); + } + + static Car oilAndManualCar() { + return new Car(false, true); + } + + static Car oilAndAutomaticCar() { + return new Car(false, false); + } +} diff --git a/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/booleanoperators/XorUnitTest.java b/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/booleanoperators/XorUnitTest.java new file mode 100644 index 0000000000..efe38c6f45 --- /dev/null +++ b/core-java-modules/core-java-lang-operators/src/test/java/com/baeldung/booleanoperators/XorUnitTest.java @@ -0,0 +1,69 @@ +package com.baeldung.booleanoperators; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class XorUnitTest { + + @Test + void givenDieselManualCar_whenXorOldSchool_thenFalse() { + Car car = Car.dieselAndManualCar(); + boolean dieselXorManual = (car.isDiesel() && !car.isManual()) || (!car.isDiesel() && car.isManual()); + assertThat(dieselXorManual).isFalse(); + } + + @Test + void givenDieselAutomaticCar_whenXorOldSchool_thenTrue() { + Car car = Car.dieselAndAutomaticCar(); + boolean dieselXorManual = (car.isDiesel() && !car.isManual()) || (!car.isDiesel() && car.isManual()); + assertThat(dieselXorManual).isTrue(); + } + + @Test + void givenNonDieselManualCar_whenXorOldSchool_thenTrue() { + Car car = Car.oilAndManualCar(); + boolean dieselXorManual = (car.isDiesel() && !car.isManual()) || (!car.isDiesel() && car.isManual()); + assertThat(dieselXorManual).isTrue(); + } + + @Test + void givenNonDieselAutomaticCar_whenXorOldSchool_thenFalse() { + Car car = Car.oilAndAutomaticCar(); + boolean dieselXorManual = (car.isDiesel() && !car.isManual()) || (!car.isDiesel() && car.isManual()); + assertThat(dieselXorManual).isFalse(); + } + + @Test + void givenDieselManualCar_whenXor_thenFalse() { + Car car = Car.dieselAndManualCar(); + boolean dieselXorManual = car.isDiesel() ^ car.isManual(); + assertThat(dieselXorManual).isFalse(); + } + + @Test + void givenDieselAutomaticCar_whenXor_thenTrue() { + Car car = Car.dieselAndAutomaticCar(); + boolean dieselXorManual = car.isDiesel() ^ car.isManual(); + assertThat(dieselXorManual).isTrue(); + } + + @Test + void givenNonDieselManualCar_whenXor_thenTrue() { + Car car = Car.oilAndManualCar(); + boolean dieselXorManual = car.isDiesel() ^ car.isManual(); + assertThat(dieselXorManual).isTrue(); + } + + @Test + void givenNonDieselAutomaticCar_whenXor_thenFalse() { + Car car = Car.oilAndAutomaticCar(); + boolean dieselXorManual = car.isDiesel() ^ car.isManual(); + assertThat(dieselXorManual).isFalse(); + } + + @Test + void givenNumbersOneAndThree_whenXor_thenTwo() { + assertThat(1 ^ 3).isEqualTo(2); + } +} diff --git a/core-java-modules/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java b/core-java-modules/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java index dcf186de93..2659b29491 100644 --- a/core-java-modules/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java +++ b/core-java-modules/core-java/src/main/java/com/baeldung/uuid/UUIDGenerator.java @@ -3,6 +3,7 @@ package com.baeldung.uuid; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import java.util.UUID; public class UUIDGenerator { @@ -65,9 +66,9 @@ public class UUIDGenerator { try { md = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException nsae) { - throw new InternalError("MD5 not supported", nsae); + throw new InternalError("SHA-1 not supported", nsae); } - byte[] bytes = md.digest(name); + byte[] bytes = Arrays.copyOfRange(md.digest(name), 0, 16); bytes[6] &= 0x0f; /* clear version */ bytes[6] |= 0x50; /* set to version 5 */ bytes[8] &= 0x3f; /* clear variant */ diff --git a/javaxval/README.md b/javaxval/README.md index 3a975022ad..fadd174166 100644 --- a/javaxval/README.md +++ b/javaxval/README.md @@ -2,9 +2,6 @@ ## Java Bean Validation Examples -###The Course -The "REST With Spring" Classes: http://bit.ly/restwithspring - ### Relevant Articles: - [Java Bean Validation Basics](http://www.baeldung.com/javax-validation) - [Validating Container Elements with Bean Validation 2.0](http://www.baeldung.com/bean-validation-container-elements) diff --git a/mapstruct/src/main/java/com/baeldung/dto/CustomerDto.java b/mapstruct/src/main/java/com/baeldung/dto/CustomerDto.java new file mode 100644 index 0000000000..617f2c6e0c --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/dto/CustomerDto.java @@ -0,0 +1,25 @@ +package com.baeldung.dto; + +public class CustomerDto { + + private String forename; + private String surname; + + public String getForename() { + return forename; + } + + public CustomerDto setForename(String forename) { + this.forename = forename; + return this; + } + + public String getSurname() { + return surname; + } + + public CustomerDto setSurname(String surname) { + this.surname = surname; + return this; + } +} diff --git a/mapstruct/src/main/java/com/baeldung/entity/Address.java b/mapstruct/src/main/java/com/baeldung/entity/Address.java new file mode 100644 index 0000000000..4a6edbd75d --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/entity/Address.java @@ -0,0 +1,35 @@ +package com.baeldung.entity; + +public class Address { + + private String street; + private String postalcode; + private String county; + + public String getStreet() { + return street; + } + + public Address setStreet(String street) { + this.street = street; + return this; + } + + public String getPostalcode() { + return postalcode; + } + + public Address setPostalcode(String postalcode) { + this.postalcode = postalcode; + return this; + } + + public String getCounty() { + return county; + } + + public Address setCounty(String county) { + this.county = county; + return this; + } +} diff --git a/mapstruct/src/main/java/com/baeldung/entity/Customer.java b/mapstruct/src/main/java/com/baeldung/entity/Customer.java new file mode 100644 index 0000000000..cdde6b542a --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/entity/Customer.java @@ -0,0 +1,25 @@ +package com.baeldung.entity; + +public class Customer { + + private String firstName; + private String lastName; + + public String getFirstName() { + return firstName; + } + + public Customer setFirstName(String firstName) { + this.firstName = firstName; + return this; + } + + public String getLastName() { + return lastName; + } + + public Customer setLastName(String lastName) { + this.lastName = lastName; + return this; + } +} diff --git a/mapstruct/src/main/java/com/baeldung/entity/DeliveryAddress.java b/mapstruct/src/main/java/com/baeldung/entity/DeliveryAddress.java new file mode 100644 index 0000000000..084c5f86ef --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/entity/DeliveryAddress.java @@ -0,0 +1,55 @@ +package com.baeldung.entity; + +public class DeliveryAddress { + + private String forename; + private String surname; + private String street; + private String postalcode; + private String county; + + public String getForename() { + return forename; + } + + public DeliveryAddress setForename(String forename) { + this.forename = forename; + return this; + } + + public String getSurname() { + return surname; + } + + public DeliveryAddress setSurname(String surname) { + this.surname = surname; + return this; + } + + public String getStreet() { + return street; + } + + public DeliveryAddress setStreet(String street) { + this.street = street; + return this; + } + + public String getPostalcode() { + return postalcode; + } + + public DeliveryAddress setPostalcode(String postalcode) { + this.postalcode = postalcode; + return this; + } + + public String getCounty() { + return county; + } + + public DeliveryAddress setCounty(String county) { + this.county = county; + return this; + } +} diff --git a/mapstruct/src/main/java/com/baeldung/mapper/CustomerDtoMapper.java b/mapstruct/src/main/java/com/baeldung/mapper/CustomerDtoMapper.java new file mode 100644 index 0000000000..2c84f80167 --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/mapper/CustomerDtoMapper.java @@ -0,0 +1,15 @@ +package com.baeldung.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +import com.baeldung.dto.CustomerDto; +import com.baeldung.entity.Customer; + +@Mapper +public interface CustomerDtoMapper { + + @Mapping(source = "firstName", target = "forename") + @Mapping(source = "lastName", target = "surname") + CustomerDto from(Customer customer); +} diff --git a/mapstruct/src/main/java/com/baeldung/mapper/DeliveryAddressMapper.java b/mapstruct/src/main/java/com/baeldung/mapper/DeliveryAddressMapper.java new file mode 100644 index 0000000000..6a337fbb9e --- /dev/null +++ b/mapstruct/src/main/java/com/baeldung/mapper/DeliveryAddressMapper.java @@ -0,0 +1,24 @@ +package com.baeldung.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; + +import com.baeldung.entity.Address; +import com.baeldung.entity.Customer; +import com.baeldung.entity.DeliveryAddress; + +@Mapper +public interface DeliveryAddressMapper { + + @Mapping(source = "customer.firstName", target = "forename") + @Mapping(source = "customer.lastName", target = "surname") + @Mapping(source = "address.street", target = "street") + @Mapping(source = "address.postalcode", target = "postalcode") + @Mapping(source = "address.county", target = "county") + DeliveryAddress from(Customer customer, Address address); + + @Mapping(source = "address.postalcode", target = "postalcode") + @Mapping(source = "address.county", target = "county") + DeliveryAddress updateAddress(@MappingTarget DeliveryAddress deliveryAddress, Address address); +} diff --git a/mapstruct/src/test/java/com/baeldung/mapper/CustomerDtoMapperUnitTest.java b/mapstruct/src/test/java/com/baeldung/mapper/CustomerDtoMapperUnitTest.java new file mode 100644 index 0000000000..cded90138b --- /dev/null +++ b/mapstruct/src/test/java/com/baeldung/mapper/CustomerDtoMapperUnitTest.java @@ -0,0 +1,29 @@ +package com.baeldung.mapper; + +import static org.junit.Assert.assertEquals; + +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +import com.baeldung.dto.CustomerDto; +import com.baeldung.entity.Customer; + +public class CustomerDtoMapperUnitTest { + + private CustomerDtoMapper customerDtoMapper = Mappers.getMapper(CustomerDtoMapper.class); + + @Test + void testGivenCustomer_mapsToCustomerDto() { + + // given + Customer customer = new Customer().setFirstName("Max") + .setLastName("Powers"); + + // when + CustomerDto customerDto = customerDtoMapper.from(customer); + + // then + assertEquals(customerDto.getForename(), customer.getFirstName()); + assertEquals(customerDto.getSurname(), customer.getLastName()); + } +} diff --git a/mapstruct/src/test/java/com/baeldung/mapper/DeliveryAddressMapperUnitTest.java b/mapstruct/src/test/java/com/baeldung/mapper/DeliveryAddressMapperUnitTest.java new file mode 100644 index 0000000000..e2c12fcba3 --- /dev/null +++ b/mapstruct/src/test/java/com/baeldung/mapper/DeliveryAddressMapperUnitTest.java @@ -0,0 +1,64 @@ +package com.baeldung.mapper; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import org.junit.Test; +import org.mapstruct.factory.Mappers; + +import com.baeldung.entity.Address; +import com.baeldung.entity.Customer; +import com.baeldung.entity.DeliveryAddress; + +public class DeliveryAddressMapperUnitTest { + + private DeliveryAddressMapper deliveryAddressMapper = Mappers.getMapper(DeliveryAddressMapper.class); + + @Test + public void testGivenCustomerAndAddress_mapsToDeliveryAddress() { + + // given + Customer customer = new Customer().setFirstName("Max") + .setLastName("Powers"); + + Address homeAddress = new Address().setStreet("123 Some Street") + .setCounty("Nevada") + .setPostalcode("89123"); + + // when + DeliveryAddress deliveryAddress = deliveryAddressMapper.from(customer, homeAddress); + + // then + assertEquals(deliveryAddress.getForename(), customer.getFirstName()); + assertEquals(deliveryAddress.getSurname(), customer.getLastName()); + assertEquals(deliveryAddress.getStreet(), homeAddress.getStreet()); + assertEquals(deliveryAddress.getCounty(), homeAddress.getCounty()); + assertEquals(deliveryAddress.getPostalcode(), homeAddress.getPostalcode()); + } + + @Test + public void testGivenDeliveryAddressAndSomeOtherAddress_updatesDeliveryAddress() { + + // given + Customer customer = new Customer().setFirstName("Max") + .setLastName("Powers"); + + DeliveryAddress deliveryAddress = new DeliveryAddress().setStreet("123 Some Street") + .setCounty("Nevada") + .setPostalcode("89123"); + + Address otherAddress = new Address().setStreet("456 Some other street") + .setCounty("Arizona") + .setPostalcode("12345"); + + // when + DeliveryAddress updatedDeliveryAddress = deliveryAddressMapper.updateAddress(deliveryAddress, otherAddress); + + // then + assertSame(deliveryAddress, updatedDeliveryAddress); + + assertEquals(deliveryAddress.getStreet(), otherAddress.getStreet()); + assertEquals(deliveryAddress.getCounty(), otherAddress.getCounty()); + assertEquals(deliveryAddress.getPostalcode(), otherAddress.getPostalcode()); + } +} diff --git a/ml/README.md b/ml/README.md new file mode 100644 index 0000000000..f4712a94da --- /dev/null +++ b/ml/README.md @@ -0,0 +1,5 @@ +### Logistic Regression in Java +This is a soft introduction to ML using [deeplearning4j](https://deeplearning4j.org) library + +### Relevant Articles: +- [Logistic Regression in Java](http://www.baeldung.com/) diff --git a/ml/pom.xml b/ml/pom.xml new file mode 100644 index 0000000000..80afcc24f4 --- /dev/null +++ b/ml/pom.xml @@ -0,0 +1,52 @@ + + 4.0.0 + com.baeldung.deeplearning4j + ml + 1.0-SNAPSHOT + Machine Learning + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.nd4j + nd4j-native-platform + ${dl4j.version} + + + org.deeplearning4j + deeplearning4j-core + ${dl4j.version} + + + org.deeplearning4j + deeplearning4j-nn + ${dl4j.version} + + + + org.datavec + datavec-api + ${dl4j.version} + + + org.apache.httpcomponents + httpclient + 4.3.5 + + + + + + + 1.0.0-beta4 + + + \ No newline at end of file diff --git a/ml/src/main/java/com/baeldung/logreg/MnistClassifier.java b/ml/src/main/java/com/baeldung/logreg/MnistClassifier.java new file mode 100644 index 0000000000..1246de973f --- /dev/null +++ b/ml/src/main/java/com/baeldung/logreg/MnistClassifier.java @@ -0,0 +1,168 @@ +package com.baeldung.logreg; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import org.datavec.api.io.labels.ParentPathLabelGenerator; +import org.datavec.api.split.FileSplit; +import org.datavec.image.loader.NativeImageLoader; +import org.datavec.image.recordreader.ImageRecordReader; +import org.deeplearning4j.datasets.datavec.RecordReaderDataSetIterator; +import org.deeplearning4j.nn.conf.MultiLayerConfiguration; +import org.deeplearning4j.nn.conf.NeuralNetConfiguration; +import org.deeplearning4j.nn.conf.inputs.InputType; +import org.deeplearning4j.nn.conf.layers.ConvolutionLayer; +import org.deeplearning4j.nn.conf.layers.DenseLayer; +import org.deeplearning4j.nn.conf.layers.OutputLayer; +import org.deeplearning4j.nn.conf.layers.SubsamplingLayer; +import org.deeplearning4j.nn.multilayer.MultiLayerNetwork; +import org.deeplearning4j.nn.weights.WeightInit; +import org.deeplearning4j.optimize.listeners.ScoreIterationListener; +import org.deeplearning4j.util.ModelSerializer; +import org.nd4j.evaluation.classification.Evaluation; +import org.nd4j.linalg.activations.Activation; +import org.nd4j.linalg.dataset.api.iterator.DataSetIterator; +import org.nd4j.linalg.dataset.api.preprocessor.DataNormalization; +import org.nd4j.linalg.dataset.api.preprocessor.ImagePreProcessingScaler; +import org.nd4j.linalg.learning.config.Nesterovs; +import org.nd4j.linalg.lossfunctions.LossFunctions; +import org.nd4j.linalg.schedule.MapSchedule; +import org.nd4j.linalg.schedule.ScheduleType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handwritten digit image classification based on LeNet-5 architecture by Yann LeCun. + * + * This code accompanies the article "Logistic regression in Java" and is heavily based on + * MnistClassifier. + * Some minor changes have been made in order to make article's flow smoother. + * + */ + +public class MnistClassifier { + private static final Logger logger = LoggerFactory.getLogger(MnistClassifier.class); + private static final String basePath = System.getProperty("java.io.tmpdir") + "mnist" + File.separator; + private static final File modelPath = new File(basePath + "mnist-model.zip"); + private static final String dataUrl = "http://github.com/myleott/mnist_png/raw/master/mnist_png.tar.gz"; + + public static void main(String[] args) throws Exception { + // input image sizes in pixels + int height = 28; + int width = 28; + // input image colour depth (1 for gray scale images) + int channels = 1; + // the number of output classes + int outputClasses = 10; + // number of samples that will be propagated through the network in each iteration + int batchSize = 54; + // total number of training epochs + int epochs = 1; + + // initialize a pseudorandom number generator + int seed = 1234; + Random randNumGen = new Random(seed); + + final String path = basePath + "mnist_png" + File.separator; + if (!new File(path).exists()) { + logger.info("Downloading data {}", dataUrl); + String localFilePath = basePath + "mnist_png.tar.gz"; + File file = new File(localFilePath); + if (!file.exists()) { + file.getParentFile() + .mkdirs(); + Utils.downloadAndSave(dataUrl, file); + Utils.extractTarArchive(file, basePath); + } + } else { + logger.info("Using the local data from folder {}", path); + } + + logger.info("Vectorizing the data from folder {}", path); + // vectorization of train data + File trainData = new File(path + "training"); + FileSplit trainSplit = new FileSplit(trainData, NativeImageLoader.ALLOWED_FORMATS, randNumGen); + // use parent directory name as the image label + ParentPathLabelGenerator labelMaker = new ParentPathLabelGenerator(); + ImageRecordReader trainRR = new ImageRecordReader(height, width, channels, labelMaker); + trainRR.initialize(trainSplit); + DataSetIterator train = new RecordReaderDataSetIterator(trainRR, batchSize, 1, outputClasses); + + // pixel values from 0-255 to 0-1 (min-max scaling) + DataNormalization imageScaler = new ImagePreProcessingScaler(); + imageScaler.fit(train); + train.setPreProcessor(imageScaler); + + // vectorization of test data + File testData = new File(path + "testing"); + FileSplit testSplit = new FileSplit(testData, NativeImageLoader.ALLOWED_FORMATS, randNumGen); + ImageRecordReader testRR = new ImageRecordReader(height, width, channels, labelMaker); + testRR.initialize(testSplit); + DataSetIterator test = new RecordReaderDataSetIterator(testRR, batchSize, 1, outputClasses); + // same normalization for better results + test.setPreProcessor(imageScaler); + + logger.info("Network configuration and training..."); + // reduce the learning rate as the number of training epochs increases + // iteration #, learning rate + Map learningRateSchedule = new HashMap<>(); + learningRateSchedule.put(0, 0.06); + learningRateSchedule.put(200, 0.05); + learningRateSchedule.put(600, 0.028); + learningRateSchedule.put(800, 0.0060); + learningRateSchedule.put(1000, 0.001); + + final ConvolutionLayer layer1 = new ConvolutionLayer.Builder(5, 5).nIn(channels) + .stride(1, 1) + .nOut(20) + .activation(Activation.IDENTITY) + .build(); + final SubsamplingLayer layer2 = new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX).kernelSize(2, 2) + .stride(2, 2) + .build(); + // nIn need not specified in later layers + final ConvolutionLayer layer3 = new ConvolutionLayer.Builder(5, 5).stride(1, 1) + .nOut(50) + .activation(Activation.IDENTITY) + .build(); + final DenseLayer layer4 = new DenseLayer.Builder().activation(Activation.RELU) + .nOut(500) + .build(); + final OutputLayer layer5 = new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD).nOut(outputClasses) + .activation(Activation.SOFTMAX) + .build(); + final MultiLayerConfiguration config = new NeuralNetConfiguration.Builder().seed(seed) + .l2(0.0005) // ridge regression value + .updater(new Nesterovs(new MapSchedule(ScheduleType.ITERATION, learningRateSchedule))) + .weightInit(WeightInit.XAVIER) + .list() + .layer(layer1) + .layer(layer2) + .layer(layer3) + .layer(layer2) + .layer(layer4) + .layer(layer5) + .setInputType(InputType.convolutionalFlat(height, width, channels)) + .build(); + + final MultiLayerNetwork model = new MultiLayerNetwork(config); + model.init(); + model.setListeners(new ScoreIterationListener(100)); + logger.info("Total num of params: {}", model.numParams()); + + // evaluation while training (the score should go down) + for (int i = 0; i < epochs; i++) { + model.fit(train); + logger.info("Completed epoch {}", i); + train.reset(); + test.reset(); + } + Evaluation eval = model.evaluate(test); + logger.info(eval.stats()); + + ModelSerializer.writeModel(model, modelPath, true); + logger.info("The MINIST model has been saved in {}", modelPath.getPath()); + } +} \ No newline at end of file diff --git a/ml/src/main/java/com/baeldung/logreg/MnistPrediction.java b/ml/src/main/java/com/baeldung/logreg/MnistPrediction.java new file mode 100644 index 0000000000..56097d9a45 --- /dev/null +++ b/ml/src/main/java/com/baeldung/logreg/MnistPrediction.java @@ -0,0 +1,57 @@ +package com.baeldung.logreg; + +import java.io.File; +import java.io.IOException; + +import javax.swing.JFileChooser; + +import org.datavec.image.loader.NativeImageLoader; +import org.deeplearning4j.nn.multilayer.MultiLayerNetwork; +import org.deeplearning4j.util.ModelSerializer; +import org.nd4j.linalg.api.ndarray.INDArray; +import org.nd4j.linalg.dataset.api.preprocessor.ImagePreProcessingScaler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MnistPrediction { + private static final Logger logger = LoggerFactory.getLogger(MnistPrediction.class); + private static final File modelPath = new File(System.getProperty("java.io.tmpdir") + "mnist" + File.separator + "mnist-model.zip"); + private static final int height = 28; + private static final int width = 28; + private static final int channels = 1; + + /** + * Opens a popup that allows to select a file from the filesystem. + * @return + */ + public static String fileChose() { + JFileChooser fc = new JFileChooser(); + int ret = fc.showOpenDialog(null); + if (ret == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + return file.getAbsolutePath(); + } else { + return null; + } + } + + public static void main(String[] args) throws IOException { + if (!modelPath.exists()) { + logger.info("The model not found. Have you trained it?"); + return; + } + MultiLayerNetwork model = ModelSerializer.restoreMultiLayerNetwork(modelPath); + String path = fileChose(); + File file = new File(path); + + INDArray image = new NativeImageLoader(height, width, channels).asMatrix(file); + new ImagePreProcessingScaler(0, 1).transform(image); + + // Pass through to neural Net + INDArray output = model.output(image); + + logger.info("File: {}", path); + logger.info("Probabilities: {}", output); + } + +} diff --git a/ml/src/main/java/com/baeldung/logreg/Utils.java b/ml/src/main/java/com/baeldung/logreg/Utils.java new file mode 100644 index 0000000000..fa4be127cd --- /dev/null +++ b/ml/src/main/java/com/baeldung/logreg/Utils.java @@ -0,0 +1,103 @@ +package com.baeldung.logreg; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class for digit classifier. + * + */ +public class Utils { + + private static final Logger logger = LoggerFactory.getLogger(Utils.class); + + private Utils() { + } + + /** + * Download the content of the given url and save it into a file. + * @param url + * @param file + */ + public static void downloadAndSave(String url, File file) throws IOException { + CloseableHttpClient client = HttpClientBuilder.create() + .build(); + logger.info("Connecting to {}", url); + try (CloseableHttpResponse response = client.execute(new HttpGet(url))) { + HttpEntity entity = response.getEntity(); + if (entity != null) { + logger.info("Downloaded {} bytes", entity.getContentLength()); + try (FileOutputStream outstream = new FileOutputStream(file)) { + logger.info("Saving to the local file"); + entity.writeTo(outstream); + outstream.flush(); + logger.info("Local file saved"); + } + } + } + } + + /** + * Extract a "tar.gz" file into a given folder. + * @param file + * @param folder + */ + public static void extractTarArchive(File file, String folder) throws IOException { + logger.info("Extracting archive {} into folder {}", file.getName(), folder); + // @formatter:off + try (FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + GzipCompressorInputStream gzip = new GzipCompressorInputStream(bis); + TarArchiveInputStream tar = new TarArchiveInputStream(gzip)) { + // @formatter:on + TarArchiveEntry entry; + while ((entry = (TarArchiveEntry) tar.getNextEntry()) != null) { + extractEntry(entry, tar, folder); + } + } + logger.info("Archive extracted"); + } + + /** + * Extract an entry of the input stream into a given folder + * @param entry + * @param tar + * @param folder + * @throws IOException + */ + public static void extractEntry(ArchiveEntry entry, InputStream tar, String folder) throws IOException { + final int bufferSize = 4096; + final String path = folder + entry.getName(); + if (entry.isDirectory()) { + new File(path).mkdirs(); + } else { + int count; + byte[] data = new byte[bufferSize]; + // @formatter:off + try (FileOutputStream os = new FileOutputStream(path); + BufferedOutputStream dest = new BufferedOutputStream(os, bufferSize)) { + // @formatter:off + while ((count = tar.read(data, 0, bufferSize)) != -1) { + dest.write(data, 0, count); + } + } + } + } +} diff --git a/ml/src/main/resources/logback.xml b/ml/src/main/resources/logback.xml new file mode 100644 index 0000000000..7d900d8ea8 --- /dev/null +++ b/ml/src/main/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/java-cassandra/pom.xml b/persistence-modules/java-cassandra/pom.xml index e7c93bc4e5..3f8367d130 100644 --- a/persistence-modules/java-cassandra/pom.xml +++ b/persistence-modules/java-cassandra/pom.xml @@ -35,6 +35,11 @@ java-driver-core ${datastax-cassandra.version} + + com.datastax.oss + java-driver-query-builder + ${datastax-cassandra.version} + io.netty diff --git a/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/Application.java b/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/Application.java index 23140e0455..f067ee8b73 100644 --- a/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/Application.java +++ b/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/Application.java @@ -26,7 +26,7 @@ public class Application { KeyspaceRepository keyspaceRepository = new KeyspaceRepository(session); - keyspaceRepository.createKeyspace("testKeyspace", "SimpleStrategy", 1); + keyspaceRepository.createKeyspace("testKeyspace", 1); keyspaceRepository.useKeyspace("testKeyspace"); VideoRepository videoRepository = new VideoRepository(session); diff --git a/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/repository/KeyspaceRepository.java b/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/repository/KeyspaceRepository.java index fd4581d055..899481738a 100644 --- a/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/repository/KeyspaceRepository.java +++ b/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/repository/KeyspaceRepository.java @@ -1,7 +1,11 @@ package com.baeldung.datastax.cassandra.repository; +import com.datastax.oss.driver.api.core.CqlIdentifier; import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.querybuilder.SchemaBuilder; +import com.datastax.oss.driver.api.querybuilder.schema.CreateKeyspace; + public class KeyspaceRepository { private final CqlSession session; @@ -9,19 +13,15 @@ public class KeyspaceRepository { this.session = session; } - public void createKeyspace(String keyspaceName, String replicationStrategy, int numberOfReplicas) { - StringBuilder sb = new StringBuilder("CREATE KEYSPACE IF NOT EXISTS ").append(keyspaceName) - .append(" WITH replication = {") - .append("'class':'").append(replicationStrategy) - .append("','replication_factor':").append(numberOfReplicas) - .append("};"); + public void createKeyspace(String keyspaceName, int numberOfReplicas) { + CreateKeyspace createKeyspace = SchemaBuilder.createKeyspace(keyspaceName) + .ifNotExists() + .withSimpleStrategy(numberOfReplicas); - final String query = sb.toString(); - - session.execute(query); + session.execute(createKeyspace.build()); } public void useKeyspace(String keyspace) { - session.execute("USE " + keyspace); + session.execute("USE " + CqlIdentifier.fromCql(keyspace)); } } diff --git a/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/repository/VideoRepository.java b/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/repository/VideoRepository.java index 9a09d77072..48eb000eba 100644 --- a/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/repository/VideoRepository.java +++ b/persistence-modules/java-cassandra/src/main/java/com/baeldung/datastax/cassandra/repository/VideoRepository.java @@ -7,6 +7,12 @@ import com.datastax.oss.driver.api.core.cql.BoundStatement; import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.ResultSet; import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.core.type.DataTypes; +import com.datastax.oss.driver.api.querybuilder.QueryBuilder; +import com.datastax.oss.driver.api.querybuilder.SchemaBuilder; +import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert; +import com.datastax.oss.driver.api.querybuilder.schema.CreateTable; +import com.datastax.oss.driver.api.querybuilder.select.Select; import java.util.ArrayList; import java.util.List; @@ -27,15 +33,12 @@ public class VideoRepository { } public void createTable(String keyspace) { - StringBuilder sb = new StringBuilder("CREATE TABLE IF NOT EXISTS ").append(TABLE_NAME).append(" (") - .append("video_id UUID,") - .append("title TEXT,") - .append("creation_date TIMESTAMP,") - .append("PRIMARY KEY(video_id));"); + CreateTable createTable = SchemaBuilder.createTable(TABLE_NAME).ifNotExists() + .withPartitionKey("video_id", DataTypes.UUID) + .withColumn("title", DataTypes.TEXT) + .withColumn("creation_date", DataTypes.TIMESTAMP); - String query = sb.toString(); - - executeStatement(SimpleStatement.newInstance(query), keyspace); + executeStatement(createTable.build(), keyspace); } public UUID insertVideo(Video video) { @@ -47,17 +50,23 @@ public class VideoRepository { video.setId(videoId); - String absoluteTableName = keyspace != null ? keyspace + "." + TABLE_NAME: TABLE_NAME; + RegularInsert insertInto = QueryBuilder.insertInto(TABLE_NAME) + .value("video_id", QueryBuilder.bindMarker()) + .value("title", QueryBuilder.bindMarker()) + .value("creation_date", QueryBuilder.bindMarker()); - StringBuilder sb = new StringBuilder("INSERT INTO ").append(absoluteTableName) - .append("(video_id, title, creation_date) values (:video_id, :title, :creation_date)"); + SimpleStatement insertStatement = insertInto.build(); - PreparedStatement preparedStatement = session.prepare(sb.toString()); + if (keyspace != null) { + insertStatement = insertStatement.setKeyspace(keyspace); + } + + PreparedStatement preparedStatement = session.prepare(insertStatement); BoundStatement statement = preparedStatement.bind() - .setUuid("video_id", video.getId()) - .setString("title", video.getTitle()) - .setInstant("creation_date", video.getCreationDate()); + .setUuid(0, video.getId()) + .setString(1, video.getTitle()) + .setInstant(2, video.getCreationDate()); session.execute(statement); @@ -69,11 +78,9 @@ public class VideoRepository { } public List + + javax.el + javax.el-api + ${javax.el.version} + + + org.glassfish + javax.el + ${javax.el.version} + - 4.3.4.RELEASE + 4.3.4.RELEASE 2.1.5.RELEASE 5.3.3.Final 2.9.6 + 3.0.0 diff --git a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextLiveTest.java b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextLiveTest.java index af228735b8..5e20a98a1d 100644 --- a/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextLiveTest.java +++ b/persistence-modules/spring-data-couchbase-2/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -9,6 +9,45 @@ import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; +/** + * This LiveTest requires: + * + * 1- Couchbase instance running (e.g. with `docker run -d --name db -p 8091-8096:8091-8096 -p 11210-11211:11210-11211 couchbase`) + * + * + * 2- Couchbase configured with (we can use the console in localhost:8091): + * + * 2.1- Buckets: named 'baeldung' and 'baeldung2' + * + * 2.2- Security: users 'baeldung' and 'baeldung2'. Note: in newer versions an empty password is not allowed, then we have to change the passwords in the project) + * + * 2.3- Spacial View: Add new spacial view (in Index tab) in document 'campus_spatial', view 'byLocation' with the following function: + * {@code + * function (doc) { + * if (doc.location && + * doc._class == "org.baeldung.spring.data.couchbase.model.Campus") { + * emit([doc.location.x, doc.location.y], null); + * } + * }} + * + * 2.4- MapReduce Views: Add new views in document 'campus': + * 2.4.1- view 'all' with function: + * {@code + * function (doc, meta) { + * if(doc._class == "org.baeldung.spring.data.couchbase.model.Campus") { + * emit(meta.id, null); + * } + * }} + * + * 2.4.2- view 'byName' with function: + * {@code + * function (doc, meta) { + * if(doc._class == "org.baeldung.spring.data.couchbase.model.Campus" && + * doc.name) { + * emit(doc.name, null); + * } + * }} + */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { MultiBucketCouchbaseConfig.class, MultiBucketIntegrationTestConfig.class }) @TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class }) diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/mongoconfig/SpringContextLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/mongoconfig/SpringContextLiveTest.java new file mode 100644 index 0000000000..a2a3d1761f --- /dev/null +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/mongoconfig/SpringContextLiveTest.java @@ -0,0 +1,26 @@ +package com.baeldung.contexttests.mongoconfig; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.config.MongoConfig; + +/** + * This Live test requires: + * * mongodb instance running on the environment + * + * (e.g. `docker run -d -p 27017:27017 --name bael-mongo mongo`) + * + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = MongoConfig.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } + +} diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/mongoreactiveconfig/SpringContextLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/mongoreactiveconfig/SpringContextLiveTest.java new file mode 100644 index 0000000000..d2a946fb90 --- /dev/null +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/mongoreactiveconfig/SpringContextLiveTest.java @@ -0,0 +1,26 @@ +package com.baeldung.contexttests.mongoreactiveconfig; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.config.MongoReactiveConfig; + +/** + * This Live test requires: + * * mongodb instance running on the environment + * + * (e.g. `docker run -d -p 27017:27017 --name bael-mongo mongo`) + * + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = MongoReactiveConfig.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } + +} diff --git a/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/simplemongoconfig/SpringContextLiveTest.java b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/simplemongoconfig/SpringContextLiveTest.java new file mode 100644 index 0000000000..6e8905c139 --- /dev/null +++ b/persistence-modules/spring-data-mongodb/src/test/java/com/baeldung/contexttests/simplemongoconfig/SpringContextLiveTest.java @@ -0,0 +1,26 @@ +package com.baeldung.contexttests.simplemongoconfig; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.config.SimpleMongoConfig; + +/** + * This Live test requires: + * * mongodb instance running on the environment + * + * (e.g. `docker run -d -p 27017:27017 --name bael-mongo mongo`) + * + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = SimpleMongoConfig.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } + +} diff --git a/play-framework/introduction/.gitignore b/play-framework/introduction/.gitignore index eb372fc719..e497f3fc67 100644 --- a/play-framework/introduction/.gitignore +++ b/play-framework/introduction/.gitignore @@ -1,6 +1,7 @@ logs target /.idea +/.g8 /.idea_modules /.classpath /.project diff --git a/play-framework/introduction/LICENSE b/play-framework/introduction/LICENSE deleted file mode 100644 index 4baedcb95f..0000000000 --- a/play-framework/introduction/LICENSE +++ /dev/null @@ -1,8 +0,0 @@ -This software is licensed under the Apache 2 license, quoted below. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with -the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific -language governing permissions and limitations under the License. \ No newline at end of file diff --git a/play-framework/introduction/README b/play-framework/introduction/README deleted file mode 100644 index f21d092edf..0000000000 --- a/play-framework/introduction/README +++ /dev/null @@ -1,49 +0,0 @@ -This is your new Play application -================================= - -This file will be packaged with your application when using `activator dist`. - -There are several demonstration files available in this template. - -Controllers -=========== - -- HomeController.java: - - Shows how to handle simple HTTP requests. - -- AsyncController.java: - - Shows how to do asynchronous programming when handling a request. - -- CountController.java: - - Shows how to inject a component into a controller and use the component when - handling requests. - -Components -========== - -- Module.java: - - Shows how to use Guice to bind all the components needed by your application. - -- Counter.java: - - An example of a component that contains state, in this case a simple counter. - -- ApplicationTimer.java: - - An example of a component that starts when the application starts and stops - when the application stops. - -Filters -======= - -- Filters.java: - - Creates the list of HTTP filters used by your application. - -- ExampleFilter.java - - A simple filter that adds a header to every response. \ No newline at end of file diff --git a/play-framework/introduction/app/Filters.java b/play-framework/introduction/app/Filters.java deleted file mode 100644 index 255de8ca93..0000000000 --- a/play-framework/introduction/app/Filters.java +++ /dev/null @@ -1,46 +0,0 @@ -import javax.inject.*; -import play.*; -import play.mvc.EssentialFilter; -import play.http.HttpFilters; -import play.mvc.*; - -import filters.ExampleFilter; - -/** - * This class configures filters that run on every request. This - * class is queried by Play to get a list of filters. - * - * Play will automatically use filters from any class called - * Filters that is placed the root package. You can load filters - * from a different class by adding a `play.http.filters` setting to - * the application.conf configuration file. - */ -@Singleton -public class Filters implements HttpFilters { - - private final Environment env; - private final EssentialFilter exampleFilter; - - /** - * @param env Basic environment settings for the current application. - * @param exampleFilter A demonstration filter that adds a header to - */ - @Inject - public Filters(Environment env, ExampleFilter exampleFilter) { - this.env = env; - this.exampleFilter = exampleFilter; - } - - @Override - public EssentialFilter[] filters() { - // Use the example filter if we're running development mode. If - // we're running in production or test mode then don't use any - // filters at all. - if (env.mode().equals(Mode.DEV)) { - return new EssentialFilter[] { exampleFilter }; - } else { - return new EssentialFilter[] {}; - } - } - -} diff --git a/play-framework/introduction/app/Module.java b/play-framework/introduction/app/Module.java deleted file mode 100644 index 6e7d1766ef..0000000000 --- a/play-framework/introduction/app/Module.java +++ /dev/null @@ -1,31 +0,0 @@ -import com.google.inject.AbstractModule; -import java.time.Clock; - -import services.ApplicationTimer; -import services.AtomicCounter; -import services.Counter; - -/** - * This class is a Guice module that tells Guice how to bind several - * different types. This Guice module is created when the Play - * application starts. - * - * Play will automatically use any class called `Module` that is in - * the root package. You can create modules in other locations by - * adding `play.modules.enabled` settings to the `application.conf` - * configuration file. - */ -public class Module extends AbstractModule { - - @Override - public void configure() { - // Use the system clock as the default implementation of Clock - bind(Clock.class).toInstance(Clock.systemDefaultZone()); - // Ask Guice to create an instance of ApplicationTimer when the - // application starts. - bind(ApplicationTimer.class).asEagerSingleton(); - // Set AtomicCounter as the implementation for Counter. - bind(Counter.class).to(AtomicCounter.class); - } - -} diff --git a/play-framework/introduction/app/controllers/AsyncController.java b/play-framework/introduction/app/controllers/AsyncController.java deleted file mode 100644 index 92c84bb755..0000000000 --- a/play-framework/introduction/app/controllers/AsyncController.java +++ /dev/null @@ -1,64 +0,0 @@ -package controllers; - -import akka.actor.ActorSystem; - -import javax.inject.*; - -import play.*; -import play.mvc.*; - -import java.util.concurrent.Executor; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.TimeUnit; - -import scala.concurrent.duration.Duration; -import scala.concurrent.ExecutionContextExecutor; - -/** - * This controller contains an action that demonstrates how to write - * simple asynchronous code in a controller. It uses a timer to - * asynchronously delay sending a response for 1 second. - * - * @param actorSystem We need the {@link ActorSystem}'s - * {@link Scheduler} to run code after a delay. - * @param exec We need a Java {@link Executor} to apply the result - * of the {@link CompletableFuture} and a Scala - * {@link ExecutionContext} so we can use the Akka {@link Scheduler}. - * An {@link ExecutionContextExecutor} implements both interfaces. - */ -@Singleton -public class AsyncController extends Controller { - - private final ActorSystem actorSystem; - private final ExecutionContextExecutor exec; - - @Inject - public AsyncController(ActorSystem actorSystem, ExecutionContextExecutor exec) { - this.actorSystem = actorSystem; - this.exec = exec; - } - - /** - * An action that returns a plain text message after a delay - * of 1 second. - *

- * The configuration in the routes file means that this method - * will be called when the application receives a GET request with - * a path of /message. - */ - public CompletionStage message() { - return getFutureMessage(1, TimeUnit.SECONDS).thenApplyAsync(Results::ok, exec); - } - - private CompletionStage getFutureMessage(long time, TimeUnit timeUnit) { - CompletableFuture future = new CompletableFuture<>(); - actorSystem.scheduler().scheduleOnce( - Duration.create(time, timeUnit), - () -> future.complete("Hi!"), - exec - ); - return future; - } - -} diff --git a/play-framework/introduction/app/controllers/CountController.java b/play-framework/introduction/app/controllers/CountController.java deleted file mode 100644 index 02fcb15f8e..0000000000 --- a/play-framework/introduction/app/controllers/CountController.java +++ /dev/null @@ -1,35 +0,0 @@ -package controllers; - -import javax.inject.*; -import play.*; -import play.mvc.*; - -import services.Counter; - -/** - * This controller demonstrates how to use dependency injection to - * bind a component into a controller class. The class contains an - * action that shows an incrementing count to users. The {@link Counter} - * object is injected by the Guice dependency injection system. - */ -@Singleton -public class CountController extends Controller { - - private final Counter counter; - - @Inject - public CountController(Counter counter) { - this.counter = counter; - } - - /** - * An action that responds with the {@link Counter}'s current - * count. The result is plain text. This action is mapped to - * GET requests with a path of /count - * requests by an entry in the routes config file. - */ - public Result count() { - return ok(Integer.toString(counter.nextCount())); - } - -} diff --git a/play-framework/introduction/app/controllers/HomeController.java b/play-framework/introduction/app/controllers/HomeController.java index 6a79856eb4..9b1146886e 100644 --- a/play-framework/introduction/app/controllers/HomeController.java +++ b/play-framework/introduction/app/controllers/HomeController.java @@ -1,14 +1,25 @@ package controllers; +import play.libs.concurrent.HttpExecutionContext; import play.mvc.*; +import play.twirl.api.Html; -import views.html.*; +import javax.inject.Inject; +import java.util.concurrent.CompletionStage; + +import static java.util.concurrent.CompletableFuture.supplyAsync; /** * This controller contains an action to handle HTTP requests * to the application's home page. */ public class HomeController extends Controller { + private HttpExecutionContext ec; + + @Inject + public HomeController(HttpExecutionContext ec) { + this.ec = ec; + } /** * An action that renders an HTML page with a welcome message. @@ -17,7 +28,41 @@ public class HomeController extends Controller { * GET request with a path of /. */ public Result index() { - return ok(index.render("Your new application is ready.")); + return ok(views.html.index.render()); } + public Result applyHtml() { + return ok(Html.apply("

This text will appear as a heading 1

")); + } + + public Result badRequestPage() { + return badRequest("Your request data has issues."); + } + + public Result notFoundPage() { + return notFound("Could not find the page you requested."); + } + + public Result customContentType() { + return ok("This is some text content").as("text/html"); + } + + public CompletionStage asyncOperation() { + return supplyAsync(() -> { + return longRunningTask(); + }, ec.current()) + .thenApplyAsync(s -> { + return ok("Got result -> " + s); + }, ec.current()); + } + + private String longRunningTask() { + return "Long running task has completed"; + } + + public Result setHeaders() { + return ok("This is some text content") + .as("text/html") + .withHeader("Header-Key", "Some value"); + } } diff --git a/play-framework/introduction/app/controllers/StudentController.java b/play-framework/introduction/app/controllers/StudentController.java deleted file mode 100644 index 8b759b9598..0000000000 --- a/play-framework/introduction/app/controllers/StudentController.java +++ /dev/null @@ -1,63 +0,0 @@ -package controllers; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import models.Student; -import models.StudentStore; -import play.libs.Json; -import play.mvc.Controller; -import play.mvc.Result; -import util.Util; - -import java.util.Set; - -public class StudentController extends Controller { - public Result create() { - JsonNode json = request().body().asJson(); - if (json == null) { - return badRequest(Util.createResponse("Expecting Json data", false)); - } - Student student = StudentStore.getInstance().addStudent(Json.fromJson(json, Student.class)); - JsonNode jsonObject = Json.toJson(student); - return created(Util.createResponse(jsonObject, true)); - } - - public Result update() { - JsonNode json = request().body().asJson(); - if (json == null) { - return badRequest(Util.createResponse("Expecting Json data", false)); - } - Student student = StudentStore.getInstance().updateStudent(Json.fromJson(json, Student.class)); - if (student == null) { - return notFound(Util.createResponse("Student not found", false)); - } - - JsonNode jsonObject = Json.toJson(student); - return ok(Util.createResponse(jsonObject, true)); - } - - public Result retrieve(int id) { - if (StudentStore.getInstance().getStudent(id) == null) { - return notFound(Util.createResponse("Student with id:" + id + " not found", false)); - } - JsonNode jsonObjects = Json.toJson(StudentStore.getInstance().getStudent(id)); - return ok(Util.createResponse(jsonObjects, true)); - } - - public Result listStudents() { - Set result = StudentStore.getInstance().getAllStudents(); - ObjectMapper mapper = new ObjectMapper(); - - JsonNode jsonData = mapper.convertValue(result, JsonNode.class); - return ok(Util.createResponse(jsonData, true)); - - } - - public Result delete(int id) { - if (!StudentStore.getInstance().deleteStudent(id)) { - return notFound(Util.createResponse("Student with id:" + id + " not found", false)); - } - return ok(Util.createResponse("Student with id:" + id + " deleted", true)); - } - -} diff --git a/play-framework/introduction/app/filters/ExampleFilter.java b/play-framework/introduction/app/filters/ExampleFilter.java deleted file mode 100644 index 67a6a36cc3..0000000000 --- a/play-framework/introduction/app/filters/ExampleFilter.java +++ /dev/null @@ -1,45 +0,0 @@ -package filters; - -import akka.stream.Materializer; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.Executor; -import java.util.function.Function; -import javax.inject.*; -import play.mvc.*; -import play.mvc.Http.RequestHeader; - - -/** - * This is a simple filter that adds a header to all requests. It's - * added to the application's list of filters by the - * {@link Filters} class. - */ -@Singleton -public class ExampleFilter extends Filter { - - private final Executor exec; - - /** - * @param mat This object is needed to handle streaming of requests - * and responses. - * @param exec This class is needed to execute code asynchronously. - * It is used below by the thenAsyncApply method. - */ - @Inject - public ExampleFilter(Materializer mat, Executor exec) { - super(mat); - this.exec = exec; - } - - @Override - public CompletionStage apply( - Function> next, - RequestHeader requestHeader) { - - return next.apply(requestHeader).thenApplyAsync( - result -> result.withHeader("X-ExampleFilter", "foo"), - exec - ); - } - -} diff --git a/play-framework/introduction/app/models/StudentStore.java b/play-framework/introduction/app/models/StudentStore.java deleted file mode 100644 index add6a5dbd6..0000000000 --- a/play-framework/introduction/app/models/StudentStore.java +++ /dev/null @@ -1,46 +0,0 @@ -package models; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class StudentStore { - private static StudentStore instance; - private Map students = new HashMap<>(); - - public static StudentStore getInstance() { - if (instance == null) { - instance = new StudentStore(); - } - return instance; - } - - public Student addStudent(Student student) { - int id = students.size(); - student.setId(id); - students.put(id, student); - return student; - } - - public Student getStudent(int id) { - return students.get(id); - } - - public Set getAllStudents() { - return new HashSet<>(students.values()); - } - - public Student updateStudent(Student student) { - int id = student.getId(); - if (students.containsKey(id)) { - students.put(id, student); - return student; - } - return null; - } - - public boolean deleteStudent(int id) { - return students.remove(id) != null; - } -} \ No newline at end of file diff --git a/play-framework/introduction/app/services/ApplicationTimer.java b/play-framework/introduction/app/services/ApplicationTimer.java deleted file mode 100644 index a951562b1d..0000000000 --- a/play-framework/introduction/app/services/ApplicationTimer.java +++ /dev/null @@ -1,50 +0,0 @@ -package services; - -import java.time.Clock; -import java.time.Instant; -import java.util.concurrent.CompletableFuture; -import javax.inject.*; -import play.Logger; -import play.inject.ApplicationLifecycle; - -/** - * This class demonstrates how to run code when the - * application starts and stops. It starts a timer when the - * application starts. When the application stops it prints out how - * long the application was running for. - * - * This class is registered for Guice dependency injection in the - * {@link Module} class. We want the class to start when the application - * starts, so it is registered as an "eager singleton". See the code - * in the {@link Module} class to see how this happens. - * - * This class needs to run code when the server stops. It uses the - * application's {@link ApplicationLifecycle} to register a stop hook. - */ -@Singleton -public class ApplicationTimer { - - private final Clock clock; - private final ApplicationLifecycle appLifecycle; - private final Instant start; - - @Inject - public ApplicationTimer(Clock clock, ApplicationLifecycle appLifecycle) { - this.clock = clock; - this.appLifecycle = appLifecycle; - // This code is called when the application starts. - start = clock.instant(); - Logger.info("ApplicationTimer demo: Starting application at " + start); - - // When the application starts, register a stop hook with the - // ApplicationLifecycle object. The code inside the stop hook will - // be run when the application stops. - appLifecycle.addStopHook(() -> { - Instant stop = clock.instant(); - Long runningTime = stop.getEpochSecond() - start.getEpochSecond(); - Logger.info("ApplicationTimer demo: Stopping application at " + clock.instant() + " after " + runningTime + "s."); - return CompletableFuture.completedFuture(null); - }); - } - -} diff --git a/play-framework/introduction/app/services/AtomicCounter.java b/play-framework/introduction/app/services/AtomicCounter.java deleted file mode 100644 index 41f741cbf7..0000000000 --- a/play-framework/introduction/app/services/AtomicCounter.java +++ /dev/null @@ -1,26 +0,0 @@ -package services; - -import java.util.concurrent.atomic.AtomicInteger; -import javax.inject.*; - -/** - * This class is a concrete implementation of the {@link Counter} trait. - * It is configured for Guice dependency injection in the {@link Module} - * class. - * - * This class has a {@link Singleton} annotation because we need to make - * sure we only use one counter per application. Without this - * annotation we would get a new instance every time a {@link Counter} is - * injected. - */ -@Singleton -public class AtomicCounter implements Counter { - - private final AtomicInteger atomicCounter = new AtomicInteger(); - - @Override - public int nextCount() { - return atomicCounter.getAndIncrement(); - } - -} diff --git a/play-framework/introduction/app/services/Counter.java b/play-framework/introduction/app/services/Counter.java deleted file mode 100644 index dadad8b09d..0000000000 --- a/play-framework/introduction/app/services/Counter.java +++ /dev/null @@ -1,13 +0,0 @@ -package services; - -/** - * This interface demonstrates how to create a component that is injected - * into a controller. The interface represents a counter that returns a - * incremented number each time it is called. - * - * The {@link Modules} class binds this interface to the - * {@link AtomicCounter} implementation. - */ -public interface Counter { - int nextCount(); -} diff --git a/play-framework/introduction/app/views/index.scala.html b/play-framework/introduction/app/views/index.scala.html index 4539f5a10b..68d37fb1d4 100644 --- a/play-framework/introduction/app/views/index.scala.html +++ b/play-framework/introduction/app/views/index.scala.html @@ -1,20 +1,5 @@ -@* - * This template takes a single argument, a String containing a - * message to display. - *@ -@(message: String) +@() -@* - * Call the `main` template with two arguments. The first - * argument is a `String` with the title of the page, the second - * argument is an `Html` object containing the body of the page. - *@ @main("Welcome to Play") { - - @* - * Get an `Html` object by calling the built-in Play welcome - * template and passing a `String` message. - *@ - @play20.welcome(message, style = "Java") - +

Welcome to Play!

} diff --git a/play-framework/introduction/app/views/main.scala.html b/play-framework/introduction/app/views/main.scala.html index 9414f4be6e..c5f755f236 100644 --- a/play-framework/introduction/app/views/main.scala.html +++ b/play-framework/introduction/app/views/main.scala.html @@ -13,11 +13,12 @@ @title - @* And here's where we render the `Html` object containing * the page content. *@ @content + + diff --git a/play-framework/introduction/bin/activator b/play-framework/introduction/bin/activator deleted file mode 100644 index a8b11d482f..0000000000 --- a/play-framework/introduction/bin/activator +++ /dev/null @@ -1,397 +0,0 @@ -#!/usr/bin/env bash - -### ------------------------------- ### -### Helper methods for BASH scripts ### -### ------------------------------- ### - -realpath () { -( - TARGET_FILE="$1" - FIX_CYGPATH="$2" - - cd "$(dirname "$TARGET_FILE")" - TARGET_FILE=$(basename "$TARGET_FILE") - - COUNT=0 - while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ] - do - TARGET_FILE=$(readlink "$TARGET_FILE") - cd "$(dirname "$TARGET_FILE")" - TARGET_FILE=$(basename "$TARGET_FILE") - COUNT=$(($COUNT + 1)) - done - - # make sure we grab the actual windows path, instead of cygwin's path. - if [[ "x$FIX_CYGPATH" != "x" ]]; then - echo "$(cygwinpath "$(pwd -P)/$TARGET_FILE")" - else - echo "$(pwd -P)/$TARGET_FILE" - fi -) -} - - -# Uses uname to detect if we're in the odd cygwin environment. -is_cygwin() { - local os=$(uname -s) - case "$os" in - CYGWIN*) return 0 ;; - *) return 1 ;; - esac -} - -# TODO - Use nicer bash-isms here. -CYGWIN_FLAG=$(if is_cygwin; then echo true; else echo false; fi) - - -# This can fix cygwin style /cygdrive paths so we get the -# windows style paths. -cygwinpath() { - local file="$1" - if [[ "$CYGWIN_FLAG" == "true" ]]; then - echo $(cygpath -w $file) - else - echo $file - fi -} - -# Make something URI friendly -make_url() { - url="$1" - local nospaces=${url// /%20} - if is_cygwin; then - echo "/${nospaces//\\//}" - else - echo "$nospaces" - fi -} - -declare -a residual_args -declare -a java_args -declare -a scalac_args -declare -a sbt_commands -declare java_cmd=java -declare java_version -declare -r real_script_path="$(realpath "$0")" -declare -r sbt_home="$(realpath "$(dirname "$(dirname "$real_script_path")")")" -declare -r sbt_bin_dir="$(dirname "$real_script_path")" -declare -r app_version="1.3.10" - -declare -r script_name=activator -declare -r java_opts=( "${ACTIVATOR_OPTS[@]}" "${SBT_OPTS[@]}" "${JAVA_OPTS[@]}" "${java_opts[@]}" ) -userhome="$HOME" -if is_cygwin; then - # cygwin sets home to something f-d up, set to real windows homedir - userhome="$USERPROFILE" -fi -declare -r activator_user_home_dir="${userhome}/.activator" -declare -r java_opts_config_home="${activator_user_home_dir}/activatorconfig.txt" -declare -r java_opts_config_version="${activator_user_home_dir}/${app_version}/activatorconfig.txt" - -echoerr () { - echo 1>&2 "$@" -} -vlog () { - [[ $verbose || $debug ]] && echoerr "$@" -} -dlog () { - [[ $debug ]] && echoerr "$@" -} - -jar_file () { - echo "$(cygwinpath "${sbt_home}/libexec/activator-launch-${app_version}.jar")" -} - -acquire_sbt_jar () { - sbt_jar="$(jar_file)" - - if [[ ! -f "$sbt_jar" ]]; then - echoerr "Could not find launcher jar: $sbt_jar" - exit 2 - fi -} - -execRunner () { - # print the arguments one to a line, quoting any containing spaces - [[ $verbose || $debug ]] && echo "# Executing command line:" && { - for arg; do - if printf "%s\n" "$arg" | grep -q ' '; then - printf "\"%s\"\n" "$arg" - else - printf "%s\n" "$arg" - fi - done - echo "" - } - - # THis used to be exec, but we loose the ability to re-hook stty then - # for cygwin... Maybe we should flag the feature here... - "$@" -} - -addJava () { - dlog "[addJava] arg = '$1'" - java_args=( "${java_args[@]}" "$1" ) -} -addSbt () { - dlog "[addSbt] arg = '$1'" - sbt_commands=( "${sbt_commands[@]}" "$1" ) -} -addResidual () { - dlog "[residual] arg = '$1'" - residual_args=( "${residual_args[@]}" "$1" ) -} -addDebugger () { - addJava "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$1" -} - -get_mem_opts () { - # if we detect any of these settings in ${JAVA_OPTS} we need to NOT output our settings. - # The reason is the Xms/Xmx, if they don't line up, cause errors. - if [[ "${JAVA_OPTS}" == *-Xmx* ]] || [[ "${JAVA_OPTS}" == *-Xms* ]] || [[ "${JAVA_OPTS}" == *-XX:MaxPermSize* ]] || [[ "${JAVA_OPTS}" == *-XX:MaxMetaspaceSize* ]] || [[ "${JAVA_OPTS}" == *-XX:ReservedCodeCacheSize* ]]; then - echo "" - else - # a ham-fisted attempt to move some memory settings in concert - # so they need not be messed around with individually. - local mem=${1:-1024} - local codecache=$(( $mem / 8 )) - (( $codecache > 128 )) || codecache=128 - (( $codecache < 512 )) || codecache=512 - local class_metadata_size=$(( $codecache * 2 )) - local class_metadata_opt=$([[ "$java_version" < "1.8" ]] && echo "MaxPermSize" || echo "MaxMetaspaceSize") - - echo "-Xms${mem}m -Xmx${mem}m -XX:ReservedCodeCacheSize=${codecache}m -XX:${class_metadata_opt}=${class_metadata_size}m" - fi -} - -require_arg () { - local type="$1" - local opt="$2" - local arg="$3" - if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then - echo "$opt requires <$type> argument" - exit 1 - fi -} - -is_function_defined() { - declare -f "$1" > /dev/null -} - -# If we're *not* running in a terminal, and we don't have any arguments, then we need to add the 'ui' parameter -detect_terminal_for_ui() { - [[ ! -t 0 ]] && [[ "${#residual_args}" == "0" ]] && { - addResidual "ui" - } - # SPECIAL TEST FOR MAC - [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]] && [[ "${#residual_args}" == "0" ]] && { - echo "Detected MAC OSX launched script...." - echo "Swapping to UI" - addResidual "ui" - } -} - -process_args () { - while [[ $# -gt 0 ]]; do - case "$1" in - -h|-help) usage; exit 1 ;; - -v|-verbose) verbose=1 && shift ;; - -d|-debug) debug=1 && shift ;; - - -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; - -mem) require_arg integer "$1" "$2" && sbt_mem="$2" && shift 2 ;; - -jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;; - -batch) exec &1 | awk -F '"' '/version/ {print $2}') - vlog "[process_args] java_version = '$java_version'" -} - -# Detect that we have java installed. -checkJava() { - local required_version="$1" - # Now check to see if it's a good enough version - if [[ "$java_version" == "" ]]; then - echo - echo No java installations was detected. - echo Please go to http://www.java.com/getjava/ and download - echo - exit 1 - elif [[ ! "$java_version" > "$required_version" ]]; then - echo - echo The java installation you have is not up to date - echo $script_name requires at least version $required_version+, you have - echo version $java_version - echo - echo Please go to http://www.java.com/getjava/ and download - echo a valid Java Runtime and install before running $script_name. - echo - exit 1 - fi -} - - -run() { - # no jar? download it. - [[ -f "$sbt_jar" ]] || acquire_sbt_jar "$sbt_version" || { - # still no jar? uh-oh. - echo "Download failed. Obtain the sbt-launch.jar manually and place it at $sbt_jar" - exit 1 - } - - # process the combined args, then reset "$@" to the residuals - process_args "$@" - detect_terminal_for_ui - set -- "${residual_args[@]}" - argumentCount=$# - - # TODO - java check should be configurable... - checkJava "1.6" - - #If we're in cygwin, we should use the windows config, and terminal hacks - if [[ "$CYGWIN_FLAG" == "true" ]]; then - stty -icanon min 1 -echo > /dev/null 2>&1 - addJava "-Djline.terminal=jline.UnixTerminal" - addJava "-Dsbt.cygwin=true" - fi - - # run sbt - execRunner "$java_cmd" \ - "-Dactivator.home=$(make_url "$sbt_home")" \ - ${SBT_OPTS:-$default_sbt_opts} \ - $(get_mem_opts $sbt_mem) \ - ${JAVA_OPTS} \ - ${java_args[@]} \ - -jar "$sbt_jar" \ - "${sbt_commands[@]}" \ - "${residual_args[@]}" - - exit_code=$? - - # Clean up the terminal from cygwin hacks. - if [[ "$CYGWIN_FLAG" == "true" ]]; then - stty icanon echo > /dev/null 2>&1 - fi - exit $exit_code -} - - -declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy" -declare -r sbt_opts_file=".sbtopts" -declare -r etc_sbt_opts_file="${sbt_home}/conf/sbtopts" -declare -r win_sbt_opts_file="${sbt_home}/conf/sbtconfig.txt" - -usage() { - cat < path to global settings/plugins directory (default: ~/.sbt) - -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11 series) - -ivy path to local Ivy repository (default: ~/.ivy2) - -mem set memory options (default: $sbt_mem, which is $(get_mem_opts $sbt_mem)) - -no-share use all local caches; no sharing - -no-global uses global caches, but does not use global ~/.sbt directory. - -jvm-debug Turn on JVM debugging, open at the given port. - -batch Disable interactive mode - - # sbt version (default: from project/build.properties if present, else latest release) - -sbt-version use the specified version of sbt - -sbt-jar use the specified jar as the sbt launcher - -sbt-rc use an RC version of sbt - -sbt-snapshot use a snapshot version of sbt - - # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) - -java-home alternate JAVA_HOME - - # jvm options and output control - JAVA_OPTS environment variable, if unset uses "$java_opts" - SBT_OPTS environment variable, if unset uses "$default_sbt_opts" - ACTIVATOR_OPTS Environment variable, if unset uses "" - .sbtopts if this file exists in the current directory, it is - prepended to the runner args - /etc/sbt/sbtopts if this file exists, it is prepended to the runner args - -Dkey=val pass -Dkey=val directly to the java runtime - -J-X pass option -X directly to the java runtime - (-J is stripped) - -S-X add -X to sbt's scalacOptions (-S is stripped) - -In the case of duplicated or conflicting options, the order above -shows precedence: JAVA_OPTS lowest, command line options highest. -EOM -} - - - -process_my_args () { - while [[ $# -gt 0 ]]; do - case "$1" in - -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;; - -no-share) addJava "$noshare_opts" && shift ;; - -no-global) addJava "-Dsbt.global.base=$(pwd)/project/.sbtboot" && shift ;; - -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; - -sbt-dir) require_arg path "$1" "$2" && addJava "-Dsbt.global.base=$2" && shift 2 ;; - -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; - -batch) exec ^&1') do ( - if %%~j==java set JAVAINSTALLED=1 - if %%~j==openjdk set JAVAINSTALLED=1 -) - -rem Detect the same thing about javac -if "%_JAVACCMD%"=="" ( - if not "%JAVA_HOME%"=="" ( - if exist "%JAVA_HOME%\bin\javac.exe" set "_JAVACCMD=%JAVA_HOME%\bin\javac.exe" - ) -) -if "%_JAVACCMD%"=="" set _JAVACCMD=javac -for /F %%j in ('"%_JAVACCMD%" -version 2^>^&1') do ( - if %%~j==javac set JAVACINSTALLED=1 -) - -rem BAT has no logical or, so we do it OLD SCHOOL! Oppan Redmond Style -set JAVAOK=true -if not defined JAVAINSTALLED set JAVAOK=false -if not defined JAVACINSTALLED set JAVAOK=false - -if "%JAVAOK%"=="false" ( - echo. - echo A Java JDK is not installed or can't be found. - if not "%JAVA_HOME%"=="" ( - echo JAVA_HOME = "%JAVA_HOME%" - ) - echo. - echo Please go to - echo http://www.oracle.com/technetwork/java/javase/downloads/index.html - echo and download a valid Java JDK and install before running Activator. - echo. - echo If you think this message is in error, please check - echo your environment variables to see if "java.exe" and "javac.exe" are - echo available via JAVA_HOME or PATH. - echo. - if defined DOUBLECLICKED pause - exit /B 1 -) - -rem Check what Java version is being used to determine what memory options to use -for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do ( - set JAVA_VERSION=%%g -) - -rem Strips away the " characters -set JAVA_VERSION=%JAVA_VERSION:"=% - -rem TODO Check if there are existing mem settings in JAVA_OPTS/CFG_OPTS and use those instead of the below -for /f "delims=. tokens=1-3" %%v in ("%JAVA_VERSION%") do ( - set MAJOR=%%v - set MINOR=%%w - set BUILD=%%x - - set META_SIZE=-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=256M - if "!MINOR!" LSS "8" ( - set META_SIZE=-XX:PermSize=64M -XX:MaxPermSize=256M - ) - - set MEM_OPTS=!META_SIZE! - ) - -rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config. -set _JAVA_OPTS=%JAVA_OPTS% -if "%_JAVA_OPTS%"=="" set _JAVA_OPTS=%CFG_OPTS% - -set DEBUG_OPTS= - -rem Loop through the arguments, building remaining args in args variable -set args= -:argsloop -if not "%~1"=="" ( - rem Checks if the argument contains "-D" and if true, adds argument 1 with 2 and puts an equal sign between them. - rem This is done since batch considers "=" to be a delimiter so we need to circumvent this behavior with a small hack. - set arg1=%~1 - if "!arg1:~0,2!"=="-D" ( - set "args=%args% "%~1"="%~2"" - shift - shift - goto argsloop - ) - - if "%~1"=="-jvm-debug" ( - if not "%~2"=="" ( - rem This piece of magic somehow checks that an argument is a number - for /F "delims=0123456789" %%i in ("%~2") do ( - set var="%%i" - ) - if defined var ( - rem Not a number, assume no argument given and default to 9999 - set JPDA_PORT=9999 - ) else ( - rem Port was given, shift arguments - set JPDA_PORT=%~2 - shift - ) - ) else ( - set JPDA_PORT=9999 - ) - shift - - set DEBUG_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=!JPDA_PORT! - goto argsloop - ) - rem else - set "args=%args% "%~1"" - shift - goto argsloop -) - -:run - -if "!args!"=="" ( - if defined DOUBLECLICKED ( - set CMDS="ui" - ) else set CMDS=!args! -) else set CMDS=!args! - -rem We add a / in front, so we get file:///C: instead of file://C: -rem Java considers the later a UNC path. -rem We also attempt a solid effort at making it URI friendly. -rem We don't even bother with UNC paths. -set JAVA_FRIENDLY_HOME_1=/!ACTIVATOR_HOME:\=/! -set JAVA_FRIENDLY_HOME=/!JAVA_FRIENDLY_HOME_1: =%%20! - -rem Checks if the command contains spaces to know if it should be wrapped in quotes or not -set NON_SPACED_CMD=%_JAVACMD: =% -if "%_JAVACMD%"=="%NON_SPACED_CMD%" %_JAVACMD% %DEBUG_OPTS% %MEM_OPTS% %ACTIVATOR_OPTS% %SBT_OPTS% %_JAVA_OPTS% "-Dactivator.home=%JAVA_FRIENDLY_HOME%" -jar "%ACTIVATOR_HOME%\libexec\%ACTIVATOR_LAUNCH_JAR%" %CMDS% -if NOT "%_JAVACMD%"=="%NON_SPACED_CMD%" "%_JAVACMD%" %DEBUG_OPTS% %MEM_OPTS% %ACTIVATOR_OPTS% %SBT_OPTS% %_JAVA_OPTS% "-Dactivator.home=%JAVA_FRIENDLY_HOME%" -jar "%ACTIVATOR_HOME%\libexec\%ACTIVATOR_LAUNCH_JAR%" %CMDS% - -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end - -@endlocal - -exit /B %ERROR_CODE% diff --git a/play-framework/introduction/build.sbt b/play-framework/introduction/build.sbt index 0f5ea736f6..5b05db6719 100644 --- a/play-framework/introduction/build.sbt +++ b/play-framework/introduction/build.sbt @@ -1,13 +1,10 @@ -name := """student-api""" +name := """introduction""" +organization := "com.baeldung" version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayJava) -scalaVersion := "2.11.7" +scalaVersion := "2.13.0" -libraryDependencies ++= Seq( - javaJdbc, - cache, - javaWs -) +libraryDependencies += guice diff --git a/play-framework/introduction/conf/application.conf b/play-framework/introduction/conf/application.conf index 489d3f9b3e..85c184dcb1 100644 --- a/play-framework/introduction/conf/application.conf +++ b/play-framework/introduction/conf/application.conf @@ -1,353 +1,2 @@ # This is the main configuration file for the application. # https://www.playframework.com/documentation/latest/ConfigFile -# ~~~~~ -# Play uses HOCON as its configuration file format. HOCON has a number -# of advantages over other config formats, but there are two things that -# can be used when modifying settings. -# -# You can include other configuration files in this main application.conf file: -#include "extra-config.conf" -# -# You can declare variables and substitute for them: -#mykey = ${some.value} -# -# And if an environment variable exists when there is no other subsitution, then -# HOCON will fall back to substituting environment variable: -#mykey = ${JAVA_HOME} - -## Akka -# https://www.playframework.com/documentation/latest/ScalaAkka#Configuration -# https://www.playframework.com/documentation/latest/JavaAkka#Configuration -# ~~~~~ -# Play uses Akka internally and exposes Akka Streams and actors in Websockets and -# other streaming HTTP responses. -akka { - # "akka.log-config-on-start" is extraordinarly useful because it log the complete - # configuration at INFO level, including defaults and overrides, so it s worth - # putting at the very top. - # - # Put the following in your conf/logback.xml file: - # - # - # - # And then uncomment this line to debug the configuration. - # - #log-config-on-start = true -} - -## Secret key -# http://www.playframework.com/documentation/latest/ApplicationSecret -# ~~~~~ -# The secret key is used to sign Play's session cookie. -# This must be changed for production, but we don't recommend you change it in this file. -play.crypto.secret = "changeme" - -## Modules -# https://www.playframework.com/documentation/latest/Modules -# ~~~~~ -# Control which modules are loaded when Play starts. Note that modules are -# the replacement for "GlobalSettings", which are deprecated in 2.5.x. -# Please see https://www.playframework.com/documentation/latest/GlobalSettings -# for more information. -# -# You can also extend Play functionality by using one of the publically available -# Play modules: https://playframework.com/documentation/latest/ModuleDirectory -play.modules { - # By default, Play will load any class called Module that is defined - # in the root package (the "app" directory), or you can define them - # explicitly below. - # If there are any built-in modules that you want to disable, you can list them here. - #enabled += my.application.Module - - # If there are any built-in modules that you want to disable, you can list them here. - #disabled += "" -} - -## IDE -# https://www.playframework.com/documentation/latest/IDE -# ~~~~~ -# Depending on your IDE, you can add a hyperlink for errors that will jump you -# directly to the code location in the IDE in dev mode. The following line makes -# use of the IntelliJ IDEA REST interface: -#play.editor="http://localhost:63342/api/file/?file=%s&line=%s" - -## Internationalisation -# https://www.playframework.com/documentation/latest/JavaI18N -# https://www.playframework.com/documentation/latest/ScalaI18N -# ~~~~~ -# Play comes with its own i18n settings, which allow the user's preferred language -# to map through to internal messages, or allow the language to be stored in a cookie. -play.i18n { - # The application languages - langs = [ "en" ] - - # Whether the language cookie should be secure or not - #langCookieSecure = true - - # Whether the HTTP only attribute of the cookie should be set to true - #langCookieHttpOnly = true -} - -## Play HTTP settings -# ~~~~~ -play.http { - ## Router - # https://www.playframework.com/documentation/latest/JavaRouting - # https://www.playframework.com/documentation/latest/ScalaRouting - # ~~~~~ - # Define the Router object to use for this application. - # This router will be looked up first when the application is starting up, - # so make sure this is the entry point. - # Furthermore, it's assumed your route file is named properly. - # So for an application router like `my.application.Router`, - # you may need to define a router file `conf/my.application.routes`. - # Default to Routes in the root package (aka "apps" folder) (and conf/routes) - #router = my.application.Router - - ## Action Creator - # https://www.playframework.com/documentation/latest/JavaActionCreator - # ~~~~~ - #actionCreator = null - - ## ErrorHandler - # https://www.playframework.com/documentation/latest/JavaRouting - # https://www.playframework.com/documentation/latest/ScalaRouting - # ~~~~~ - # If null, will attempt to load a class called ErrorHandler in the root package, - #errorHandler = null - - ## Filters - # https://www.playframework.com/documentation/latest/ScalaHttpFilters - # https://www.playframework.com/documentation/latest/JavaHttpFilters - # ~~~~~ - # Filters run code on every request. They can be used to perform - # common logic for all your actions, e.g. adding common headers. - # Defaults to "Filters" in the root package (aka "apps" folder) - # Alternatively you can explicitly register a class here. - #filters = my.application.Filters - - ## Session & Flash - # https://www.playframework.com/documentation/latest/JavaSessionFlash - # https://www.playframework.com/documentation/latest/ScalaSessionFlash - # ~~~~~ - session { - # Sets the cookie to be sent only over HTTPS. - #secure = true - - # Sets the cookie to be accessed only by the server. - #httpOnly = true - - # Sets the max-age field of the cookie to 5 minutes. - # NOTE: this only sets when the browser will discard the cookie. Play will consider any - # cookie value with a valid signature to be a valid session forever. To implement a server side session timeout, - # you need to put a timestamp in the session and check it at regular intervals to possibly expire it. - #maxAge = 300 - - # Sets the domain on the session cookie. - #domain = "example.com" - } - - flash { - # Sets the cookie to be sent only over HTTPS. - #secure = true - - # Sets the cookie to be accessed only by the server. - #httpOnly = true - } -} - -## Netty Provider -# https://www.playframework.com/documentation/latest/SettingsNetty -# ~~~~~ -play.server.netty { - # Whether the Netty wire should be logged - #log.wire = true - - # If you run Play on Linux, you can use Netty's native socket transport - # for higher performance with less garbage. - #transport = "native" -} - -## WS (HTTP Client) -# https://www.playframework.com/documentation/latest/ScalaWS#Configuring-WS -# ~~~~~ -# The HTTP client primarily used for REST APIs. The default client can be -# configured directly, but you can also create different client instances -# with customized settings. You must enable this by adding to build.sbt: -# -# libraryDependencies += ws // or javaWs if using java -# -play.ws { - # Sets HTTP requests not to follow 302 requests - #followRedirects = false - - # Sets the maximum number of open HTTP connections for the client. - #ahc.maxConnectionsTotal = 50 - - ## WS SSL - # https://www.playframework.com/documentation/latest/WsSSL - # ~~~~~ - ssl { - # Configuring HTTPS with Play WS does not require programming. You can - # set up both trustManager and keyManager for mutual authentication, and - # turn on JSSE debugging in development with a reload. - #debug.handshake = true - #trustManager = { - # stores = [ - # { type = "JKS", path = "exampletrust.jks" } - # ] - #} - } -} - -## Cache -# https://www.playframework.com/documentation/latest/JavaCache -# https://www.playframework.com/documentation/latest/ScalaCache -# ~~~~~ -# Play comes with an integrated cache API that can reduce the operational -# overhead of repeated requests. You must enable this by adding to build.sbt: -# -# libraryDependencies += cache -# -play.cache { - # If you want to bind several caches, you can bind the individually - #bindCaches = ["db-cache", "user-cache", "session-cache"] -} - -## Filters -# https://www.playframework.com/documentation/latest/Filters -# ~~~~~ -# There are a number of built-in filters that can be enabled and configured -# to give Play greater security. You must enable this by adding to build.sbt: -# -# libraryDependencies += filters -# -play.filters { - ## CORS filter configuration - # https://www.playframework.com/documentation/latest/CorsFilter - # ~~~~~ - # CORS is a protocol that allows web applications to make requests from the browser - # across different domains. - # NOTE: You MUST apply the CORS configuration before the CSRF filter, as CSRF has - # dependencies on CORS settings. - cors { - # Filter paths by a whitelist of path prefixes - #pathPrefixes = ["/some/path", ...] - - # The allowed origins. If null, all origins are allowed. - #allowedOrigins = ["http://www.example.com"] - - # The allowed HTTP methods. If null, all methods are allowed - #allowedHttpMethods = ["GET", "POST"] - } - - ## CSRF Filter - # https://www.playframework.com/documentation/latest/ScalaCsrf#Applying-a-global-CSRF-filter - # https://www.playframework.com/documentation/latest/JavaCsrf#Applying-a-global-CSRF-filter - # ~~~~~ - # Play supports multiple methods for verifying that a request is not a CSRF request. - # The primary mechanism is a CSRF token. This token gets placed either in the query string - # or body of every form submitted, and also gets placed in the users session. - # Play then verifies that both tokens are present and match. - csrf { - # Sets the cookie to be sent only over HTTPS - #cookie.secure = true - - # Defaults to CSRFErrorHandler in the root package. - #errorHandler = MyCSRFErrorHandler - } - - ## Security headers filter configuration - # https://www.playframework.com/documentation/latest/SecurityHeaders - # ~~~~~ - # Defines security headers that prevent XSS attacks. - # If enabled, then all options are set to the below configuration by default: - headers { - # The X-Frame-Options header. If null, the header is not set. - #frameOptions = "DENY" - - # The X-XSS-Protection header. If null, the header is not set. - #xssProtection = "1; mode=block" - - # The X-Content-Type-Options header. If null, the header is not set. - #contentTypeOptions = "nosniff" - - # The X-Permitted-Cross-Domain-Policies header. If null, the header is not set. - #permittedCrossDomainPolicies = "master-only" - - # The Content-Security-Policy header. If null, the header is not set. - #contentSecurityPolicy = "default-src 'self'" - } - - ## Allowed hosts filter configuration - # https://www.playframework.com/documentation/latest/AllowedHostsFilter - # ~~~~~ - # Play provides a filter that lets you configure which hosts can access your application. - # This is useful to prevent cache poisoning attacks. - hosts { - # Allow requests to example.com, its subdomains, and localhost:9000. - #allowed = [".example.com", "localhost:9000"] - } -} - -## Evolutions -# https://www.playframework.com/documentation/latest/Evolutions -# ~~~~~ -# Evolutions allows database scripts to be automatically run on startup in dev mode -# for database migrations. You must enable this by adding to build.sbt: -# -# libraryDependencies += evolutions -# -play.evolutions { - # You can disable evolutions for a specific datasource if necessary - #db.default.enabled = false -} - -## Database Connection Pool -# https://www.playframework.com/documentation/latest/SettingsJDBC -# ~~~~~ -# Play doesn't require a JDBC database to run, but you can easily enable one. -# -# libraryDependencies += jdbc -# -play.db { - # The combination of these two settings results in "db.default" as the - # default JDBC pool: - #config = "db" - #default = "default" - - # Play uses HikariCP as the default connection pool. You can override - # settings by changing the prototype: - prototype { - # Sets a fixed JDBC connection pool size of 50 - #hikaricp.minimumIdle = 50 - #hikaricp.maximumPoolSize = 50 - } -} - -## JDBC Datasource -# https://www.playframework.com/documentation/latest/JavaDatabase -# https://www.playframework.com/documentation/latest/ScalaDatabase -# ~~~~~ -# Once JDBC datasource is set up, you can work with several different -# database options: -# -# Slick (Scala preferred option): https://www.playframework.com/documentation/latest/PlaySlick -# JPA (Java preferred option): https://playframework.com/documentation/latest/JavaJPA -# EBean: https://playframework.com/documentation/latest/JavaEbean -# Anorm: https://www.playframework.com/documentation/latest/ScalaAnorm -# -db { - # You can declare as many datasources as you want. - # By convention, the default datasource is named `default` - - # https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database - #default.driver = org.h2.Driver - #default.url = "jdbc:h2:mem:play" - #default.username = sa - #default.password = "" - - # You can turn on SQL logging for any datasource - # https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements - #default.logSql=true -} diff --git a/play-framework/introduction/conf/logback.xml b/play-framework/introduction/conf/logback.xml index 86ec12c0af..e8c982543f 100644 --- a/play-framework/introduction/conf/logback.xml +++ b/play-framework/introduction/conf/logback.xml @@ -27,12 +27,6 @@ - - - - - - diff --git a/play-framework/introduction/conf/routes b/play-framework/introduction/conf/routes index ab55792683..e26dc10383 100644 --- a/play-framework/introduction/conf/routes +++ b/play-framework/introduction/conf/routes @@ -2,11 +2,14 @@ # This file defines all application routes (Higher priority routes first) # ~~~~ -GET / controllers.StudentController.listStudents() -POST /:id controllers.StudentController.retrieve(id:Int) -POST / controllers.StudentController.create() -PUT / controllers.StudentController.update() -DELETE /:id controllers.StudentController.delete(id:Int) +# An example controller showing a sample home page +GET / controllers.HomeController.index +GET /baeldung/html controllers.HomeController.applyHtml +GET /baeldung/bad-req controllers.HomeController.badRequestPage +GET /baeldung/not-found controllers.HomeController.notFoundPage +GET /baeldung/custom-content-type controllers.HomeController.customContentType +GET /baeldung/async controllers.HomeController.asyncOperation +GET /baeldung/headers controllers.HomeController.setHeaders # Map static resources from the /public folder to the /assets URL path -GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) +GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) diff --git a/play-framework/introduction/libexec/activator-launch-1.3.10.jar b/play-framework/introduction/libexec/activator-launch-1.3.10.jar deleted file mode 100644 index 69050e7dec..0000000000 Binary files a/play-framework/introduction/libexec/activator-launch-1.3.10.jar and /dev/null differ diff --git a/play-framework/introduction/project/build.properties b/play-framework/introduction/project/build.properties index 6d9fa6badb..c0bab04941 100644 --- a/play-framework/introduction/project/build.properties +++ b/play-framework/introduction/project/build.properties @@ -1,4 +1 @@ -#Activator-generated Properties -#Wed Sep 07 12:29:40 EAT 2016 -template.uuid=c373963b-f5ad-433b-8e74-178e7ae25b1c -sbt.version=0.13.11 +sbt.version=1.2.8 diff --git a/play-framework/introduction/project/plugins.sbt b/play-framework/introduction/project/plugins.sbt index 51c5b2a35a..1c8c62a0d5 100644 --- a/play-framework/introduction/project/plugins.sbt +++ b/play-framework/introduction/project/plugins.sbt @@ -1,21 +1,7 @@ // The Play plugin -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.6") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3") -// Web plugins -addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.3") -addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.7") -addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.1.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-mocha" % "1.1.0") -addSbtPlugin("org.irundaia.sbt" % "sbt-sassify" % "1.4.2") - -// Play enhancer - this automatically generates getters/setters for public fields -// and rewrites accessors of these fields to use the getters/setters. Remove this -// plugin if you prefer not to have this feature, or disable on a per project -// basis using disablePlugins(PlayEnhancer) in your build.sbt -addSbtPlugin("com.typesafe.sbt" % "sbt-play-enhancer" % "1.1.0") - -// Play Ebean support, to enable, uncomment this line, and enable in your build.sbt using -// enablePlugins(PlayEbean). -// addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "1.0.0") +// Defines scaffolding (found under .g8 folder) +// http://www.foundweekends.org/giter8/scaffolding.html +// sbt "g8Scaffold form" +addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0") diff --git a/play-framework/introduction/public/javascripts/hello.js b/play-framework/introduction/public/javascripts/hello.js deleted file mode 100644 index 02ee13c7ca..0000000000 --- a/play-framework/introduction/public/javascripts/hello.js +++ /dev/null @@ -1,3 +0,0 @@ -if (window.console) { - console.log("Welcome to your Play application's JavaScript!"); -} diff --git a/play-framework/introduction/public/javascripts/main.js b/play-framework/introduction/public/javascripts/main.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/play-framework/introduction/test/ApplicationLiveTest.java b/play-framework/introduction/test/ApplicationLiveTest.java deleted file mode 100644 index beeef1a602..0000000000 --- a/play-framework/introduction/test/ApplicationLiveTest.java +++ /dev/null @@ -1,172 +0,0 @@ - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Arrays; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; -import model.Student; -import play.test.*; -import static play.test.Helpers.*; - -public class ApplicationLiveTest{ - private static final String BASE_URL = "http://localhost:9000"; - - @Test -public void testInServer() throws Exception { - TestServer server = testServer(3333); - running(server, () -> { - try { - WSClient ws = play.libs.ws.WS.newClient(3333); - CompletionStage completionStage = ws.url("/").get(); - WSResponse response = completionStage.toCompletableFuture().get(); - ws.close(); - assertEquals(OK, response.getStatus()); - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - }); -} - @Test - public void whenCreatesRecord_thenCorrect() { - Student student = new Student("jody", "west", 50); - JSONObject obj = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))); - assertTrue(obj.getBoolean("isSuccessfull")); - JSONObject body = obj.getJSONObject("body"); - assertEquals(student.getAge(), body.getInt("age")); - assertEquals(student.getFirstName(), body.getString("firstName")); - assertEquals(student.getLastName(), body.getString("lastName")); - } - - @Test - public void whenDeletesCreatedRecord_thenCorrect() { - Student student = new Student("Usain", "Bolt", 25); - JSONObject ob1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body"); - int id = ob1.getInt("id"); - JSONObject obj1 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject())); - assertTrue(obj1.getBoolean("isSuccessfull")); - makeRequest(BASE_URL + "/" + id, "DELETE", null); - JSONObject obj2 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject())); - assertFalse(obj2.getBoolean("isSuccessfull")); - } - - @Test - public void whenUpdatesCreatedRecord_thenCorrect() { - Student student = new Student("john", "doe", 50); - JSONObject body1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body"); - assertEquals(student.getAge(), body1.getInt("age")); - int newAge = 60; - body1.put("age", newAge); - JSONObject body2 = new JSONObject(makeRequest(BASE_URL, "PUT", body1)).getJSONObject("body"); - assertFalse(student.getAge() == body2.getInt("age")); - assertTrue(newAge == body2.getInt("age")); - } - - @Test - public void whenGetsAllRecords_thenCorrect() { - Student student1 = new Student("jane", "daisy", 50); - Student student2 = new Student("john", "daniel", 60); - Student student3 = new Student("don", "mason", 55); - Student student4 = new Student("scarlet", "ohara", 90); - - makeRequest(BASE_URL, "POST", new JSONObject(student1)); - makeRequest(BASE_URL, "POST", new JSONObject(student2)); - makeRequest(BASE_URL, "POST", new JSONObject(student3)); - makeRequest(BASE_URL, "POST", new JSONObject(student4)); - - JSONObject objects = new JSONObject(makeRequest(BASE_URL, "GET", null)); - assertTrue(objects.getBoolean("isSuccessfull")); - JSONArray array = objects.getJSONArray("body"); - assertTrue(array.length() >= 4); - } - - public static String makeRequest(String myUrl, String httpMethod, JSONObject parameters) { - - URL url = null; - try { - url = new URL(myUrl); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - HttpURLConnection conn = null; - try { - - conn = (HttpURLConnection) url.openConnection(); - } catch (IOException e) { - e.printStackTrace(); - } - conn.setDoInput(true); - - conn.setReadTimeout(10000); - - conn.setRequestProperty("Content-Type", "application/json"); - DataOutputStream dos = null; - int respCode = 0; - String inputString = null; - try { - conn.setRequestMethod(httpMethod); - - if (Arrays.asList("POST", "PUT").contains(httpMethod)) { - String params = parameters.toString(); - - conn.setDoOutput(true); - - dos = new DataOutputStream(conn.getOutputStream()); - dos.writeBytes(params); - dos.flush(); - dos.close(); - } - respCode = conn.getResponseCode(); - if (respCode != 200 && respCode != 201) { - String error = inputStreamToString(conn.getErrorStream()); - return error; - } - inputString = inputStreamToString(conn.getInputStream()); - - } catch (IOException e) { - - e.printStackTrace(); - } - return inputString; - } - - public static String inputStreamToString(InputStream is) { - BufferedReader br = null; - StringBuilder sb = new StringBuilder(); - - String line; - try { - - br = new BufferedReader(new InputStreamReader(is)); - while ((line = br.readLine()) != null) { - sb.append(line); - } - - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (br != null) { - try { - br.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - return sb.toString(); - - } -} diff --git a/play-framework/introduction/test/controllers/HomeControllerUnitTest.java b/play-framework/introduction/test/controllers/HomeControllerUnitTest.java new file mode 100644 index 0000000000..42a2e871f0 --- /dev/null +++ b/play-framework/introduction/test/controllers/HomeControllerUnitTest.java @@ -0,0 +1,97 @@ +package controllers; + +import org.junit.Test; +import play.Application; +import play.inject.guice.GuiceApplicationBuilder; +import play.mvc.Http; +import play.mvc.Result; +import play.test.WithApplication; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static play.mvc.Http.Status.*; +import static play.test.Helpers.GET; +import static play.test.Helpers.route; + +public class HomeControllerUnitTest extends WithApplication { + + @Override + protected Application provideApplication() { + return new GuiceApplicationBuilder().build(); + } + + @Test + public void givenRequest_whenRootPath_ThenStatusOkay() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/"); + + Result result = route(app, request); + assertEquals(OK, result.status()); + } + + @Test + public void givenRequest_whenHtmlPath_ThenStatusOkay() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/baeldung/html"); + + Result result = route(app, request); + assertEquals(OK, result.status()); + } + + @Test + public void givenRequest_whenBadRequest_ThenStatusBadRequest() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/baeldung/bad-req"); + + Result result = route(app, request); + assertEquals(BAD_REQUEST, result.status()); + } + + @Test + public void givenRequest_whenNotFound_ThenStatusNotFound() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/baeldung/not-found"); + + Result result = route(app, request); + assertEquals(NOT_FOUND, result.status()); + } + + @Test + public void givenRequest_whenCustomContentTypePath_ThenContextTypeTextHtml() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/baeldung/custom-content-type"); + + Result result = route(app, request); + assertTrue(result.contentType().isPresent()); + assertEquals("text/html", result.contentType().get()); + } + + @Test + public void givenRequest_whenAsyncPath_ThenStatusOkay() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/baeldung/async"); + + Result result = route(app, request); + assertEquals(OK, result.status()); + } + + @Test + public void givenRequest_whenHeadersPath_ThenCustomHeaderFieldSet() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/baeldung/headers"); + + Result result = route(app, request); + final Optional headerOptional = result.header("Header-Key"); + assertTrue(headerOptional.isPresent()); + assertEquals("Some value", headerOptional.get()); + } +} diff --git a/play-framework/routing-in-play/LICENSE b/play-framework/routing-in-play/LICENSE deleted file mode 100644 index 4baedcb95f..0000000000 --- a/play-framework/routing-in-play/LICENSE +++ /dev/null @@ -1,8 +0,0 @@ -This software is licensed under the Apache 2 license, quoted below. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with -the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific -language governing permissions and limitations under the License. \ No newline at end of file diff --git a/play-framework/routing-in-play/README b/play-framework/routing-in-play/README deleted file mode 100644 index f21d092edf..0000000000 --- a/play-framework/routing-in-play/README +++ /dev/null @@ -1,49 +0,0 @@ -This is your new Play application -================================= - -This file will be packaged with your application when using `activator dist`. - -There are several demonstration files available in this template. - -Controllers -=========== - -- HomeController.java: - - Shows how to handle simple HTTP requests. - -- AsyncController.java: - - Shows how to do asynchronous programming when handling a request. - -- CountController.java: - - Shows how to inject a component into a controller and use the component when - handling requests. - -Components -========== - -- Module.java: - - Shows how to use Guice to bind all the components needed by your application. - -- Counter.java: - - An example of a component that contains state, in this case a simple counter. - -- ApplicationTimer.java: - - An example of a component that starts when the application starts and stops - when the application stops. - -Filters -======= - -- Filters.java: - - Creates the list of HTTP filters used by your application. - -- ExampleFilter.java - - A simple filter that adds a header to every response. \ No newline at end of file diff --git a/play-framework/routing-in-play/app/Filters.java b/play-framework/routing-in-play/app/Filters.java deleted file mode 100644 index 255de8ca93..0000000000 --- a/play-framework/routing-in-play/app/Filters.java +++ /dev/null @@ -1,46 +0,0 @@ -import javax.inject.*; -import play.*; -import play.mvc.EssentialFilter; -import play.http.HttpFilters; -import play.mvc.*; - -import filters.ExampleFilter; - -/** - * This class configures filters that run on every request. This - * class is queried by Play to get a list of filters. - * - * Play will automatically use filters from any class called - * Filters that is placed the root package. You can load filters - * from a different class by adding a `play.http.filters` setting to - * the application.conf configuration file. - */ -@Singleton -public class Filters implements HttpFilters { - - private final Environment env; - private final EssentialFilter exampleFilter; - - /** - * @param env Basic environment settings for the current application. - * @param exampleFilter A demonstration filter that adds a header to - */ - @Inject - public Filters(Environment env, ExampleFilter exampleFilter) { - this.env = env; - this.exampleFilter = exampleFilter; - } - - @Override - public EssentialFilter[] filters() { - // Use the example filter if we're running development mode. If - // we're running in production or test mode then don't use any - // filters at all. - if (env.mode().equals(Mode.DEV)) { - return new EssentialFilter[] { exampleFilter }; - } else { - return new EssentialFilter[] {}; - } - } - -} diff --git a/play-framework/routing-in-play/app/Module.java b/play-framework/routing-in-play/app/Module.java deleted file mode 100644 index 6e7d1766ef..0000000000 --- a/play-framework/routing-in-play/app/Module.java +++ /dev/null @@ -1,31 +0,0 @@ -import com.google.inject.AbstractModule; -import java.time.Clock; - -import services.ApplicationTimer; -import services.AtomicCounter; -import services.Counter; - -/** - * This class is a Guice module that tells Guice how to bind several - * different types. This Guice module is created when the Play - * application starts. - * - * Play will automatically use any class called `Module` that is in - * the root package. You can create modules in other locations by - * adding `play.modules.enabled` settings to the `application.conf` - * configuration file. - */ -public class Module extends AbstractModule { - - @Override - public void configure() { - // Use the system clock as the default implementation of Clock - bind(Clock.class).toInstance(Clock.systemDefaultZone()); - // Ask Guice to create an instance of ApplicationTimer when the - // application starts. - bind(ApplicationTimer.class).asEagerSingleton(); - // Set AtomicCounter as the implementation for Counter. - bind(Counter.class).to(AtomicCounter.class); - } - -} diff --git a/play-framework/routing-in-play/app/controllers/HomeController.java b/play-framework/routing-in-play/app/controllers/HomeController.java index 6e340d594f..c7f6daa898 100644 --- a/play-framework/routing-in-play/app/controllers/HomeController.java +++ b/play-framework/routing-in-play/app/controllers/HomeController.java @@ -1,8 +1,13 @@ package controllers; +import play.libs.concurrent.HttpExecutionContext; import play.mvc.*; +import play.twirl.api.Html; -import views.html.*; +import javax.inject.Inject; +import java.util.concurrent.CompletionStage; + +import static java.util.concurrent.CompletableFuture.supplyAsync; /** * This controller contains an action to handle HTTP requests @@ -16,18 +21,33 @@ public class HomeController extends Controller { * this method will be called when the application receives a * GET request with a path of /. */ - public Result index(String author,int id) { - return ok("Routing in Play by:"+author+" ID:"+id); - } - public Result greet(String name,int age) { - return ok("Hello "+name+", you are "+age+" years old"); - } - public Result introduceMe(String data) { - String[] clientData=data.split(","); - return ok("Your name is "+clientData[0]+", you are "+clientData[1]+" years old"); - } - public Result squareMe(Long num) { - return ok(num+" Squared is "+(num*num)); + public Result index() { + return ok(views.html.index.render()); } + public Result writer(String author) { + return ok("Routing in Play by " + author); + } + + public Result viewUser(String userId) { + final String response = String.format("Got user id {} in request.", userId); + return ok(response); + } + + public Result greet(String name, int age) { + return ok("Hello " + name + ", you are " + age + " years old"); + } + + public Result squareMe(Long num) { + return ok(num + " Squared is " + (num * num)); + } + + public Result writer(String author, int id) { + return ok("Routing in Play by: " + author + " ID: " + id); + } + + public Result introduceMe(String data) { + String[] clientData = data.split(","); + return ok("Your name is " + clientData[0] + ", you are " + clientData[1] + " years old"); + } } diff --git a/play-framework/routing-in-play/app/filters/ExampleFilter.java b/play-framework/routing-in-play/app/filters/ExampleFilter.java deleted file mode 100644 index 67a6a36cc3..0000000000 --- a/play-framework/routing-in-play/app/filters/ExampleFilter.java +++ /dev/null @@ -1,45 +0,0 @@ -package filters; - -import akka.stream.Materializer; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.Executor; -import java.util.function.Function; -import javax.inject.*; -import play.mvc.*; -import play.mvc.Http.RequestHeader; - - -/** - * This is a simple filter that adds a header to all requests. It's - * added to the application's list of filters by the - * {@link Filters} class. - */ -@Singleton -public class ExampleFilter extends Filter { - - private final Executor exec; - - /** - * @param mat This object is needed to handle streaming of requests - * and responses. - * @param exec This class is needed to execute code asynchronously. - * It is used below by the thenAsyncApply method. - */ - @Inject - public ExampleFilter(Materializer mat, Executor exec) { - super(mat); - this.exec = exec; - } - - @Override - public CompletionStage apply( - Function> next, - RequestHeader requestHeader) { - - return next.apply(requestHeader).thenApplyAsync( - result -> result.withHeader("X-ExampleFilter", "foo"), - exec - ); - } - -} diff --git a/play-framework/routing-in-play/app/services/ApplicationTimer.java b/play-framework/routing-in-play/app/services/ApplicationTimer.java deleted file mode 100644 index a951562b1d..0000000000 --- a/play-framework/routing-in-play/app/services/ApplicationTimer.java +++ /dev/null @@ -1,50 +0,0 @@ -package services; - -import java.time.Clock; -import java.time.Instant; -import java.util.concurrent.CompletableFuture; -import javax.inject.*; -import play.Logger; -import play.inject.ApplicationLifecycle; - -/** - * This class demonstrates how to run code when the - * application starts and stops. It starts a timer when the - * application starts. When the application stops it prints out how - * long the application was running for. - * - * This class is registered for Guice dependency injection in the - * {@link Module} class. We want the class to start when the application - * starts, so it is registered as an "eager singleton". See the code - * in the {@link Module} class to see how this happens. - * - * This class needs to run code when the server stops. It uses the - * application's {@link ApplicationLifecycle} to register a stop hook. - */ -@Singleton -public class ApplicationTimer { - - private final Clock clock; - private final ApplicationLifecycle appLifecycle; - private final Instant start; - - @Inject - public ApplicationTimer(Clock clock, ApplicationLifecycle appLifecycle) { - this.clock = clock; - this.appLifecycle = appLifecycle; - // This code is called when the application starts. - start = clock.instant(); - Logger.info("ApplicationTimer demo: Starting application at " + start); - - // When the application starts, register a stop hook with the - // ApplicationLifecycle object. The code inside the stop hook will - // be run when the application stops. - appLifecycle.addStopHook(() -> { - Instant stop = clock.instant(); - Long runningTime = stop.getEpochSecond() - start.getEpochSecond(); - Logger.info("ApplicationTimer demo: Stopping application at " + clock.instant() + " after " + runningTime + "s."); - return CompletableFuture.completedFuture(null); - }); - } - -} diff --git a/play-framework/routing-in-play/app/services/AtomicCounter.java b/play-framework/routing-in-play/app/services/AtomicCounter.java deleted file mode 100644 index 41f741cbf7..0000000000 --- a/play-framework/routing-in-play/app/services/AtomicCounter.java +++ /dev/null @@ -1,26 +0,0 @@ -package services; - -import java.util.concurrent.atomic.AtomicInteger; -import javax.inject.*; - -/** - * This class is a concrete implementation of the {@link Counter} trait. - * It is configured for Guice dependency injection in the {@link Module} - * class. - * - * This class has a {@link Singleton} annotation because we need to make - * sure we only use one counter per application. Without this - * annotation we would get a new instance every time a {@link Counter} is - * injected. - */ -@Singleton -public class AtomicCounter implements Counter { - - private final AtomicInteger atomicCounter = new AtomicInteger(); - - @Override - public int nextCount() { - return atomicCounter.getAndIncrement(); - } - -} diff --git a/play-framework/routing-in-play/app/services/Counter.java b/play-framework/routing-in-play/app/services/Counter.java deleted file mode 100644 index dadad8b09d..0000000000 --- a/play-framework/routing-in-play/app/services/Counter.java +++ /dev/null @@ -1,13 +0,0 @@ -package services; - -/** - * This interface demonstrates how to create a component that is injected - * into a controller. The interface represents a counter that returns a - * incremented number each time it is called. - * - * The {@link Modules} class binds this interface to the - * {@link AtomicCounter} implementation. - */ -public interface Counter { - int nextCount(); -} diff --git a/play-framework/routing-in-play/app/views/index.scala.html b/play-framework/routing-in-play/app/views/index.scala.html index 4539f5a10b..68d37fb1d4 100644 --- a/play-framework/routing-in-play/app/views/index.scala.html +++ b/play-framework/routing-in-play/app/views/index.scala.html @@ -1,20 +1,5 @@ -@* - * This template takes a single argument, a String containing a - * message to display. - *@ -@(message: String) +@() -@* - * Call the `main` template with two arguments. The first - * argument is a `String` with the title of the page, the second - * argument is an `Html` object containing the body of the page. - *@ @main("Welcome to Play") { - - @* - * Get an `Html` object by calling the built-in Play welcome - * template and passing a `String` message. - *@ - @play20.welcome(message, style = "Java") - +

Welcome to Play!

} diff --git a/play-framework/routing-in-play/app/views/main.scala.html b/play-framework/routing-in-play/app/views/main.scala.html index 9414f4be6e..c5f755f236 100644 --- a/play-framework/routing-in-play/app/views/main.scala.html +++ b/play-framework/routing-in-play/app/views/main.scala.html @@ -13,11 +13,12 @@ @title - @* And here's where we render the `Html` object containing * the page content. *@ @content + + diff --git a/play-framework/routing-in-play/bin/activator b/play-framework/routing-in-play/bin/activator deleted file mode 100644 index a8b11d482f..0000000000 --- a/play-framework/routing-in-play/bin/activator +++ /dev/null @@ -1,397 +0,0 @@ -#!/usr/bin/env bash - -### ------------------------------- ### -### Helper methods for BASH scripts ### -### ------------------------------- ### - -realpath () { -( - TARGET_FILE="$1" - FIX_CYGPATH="$2" - - cd "$(dirname "$TARGET_FILE")" - TARGET_FILE=$(basename "$TARGET_FILE") - - COUNT=0 - while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ] - do - TARGET_FILE=$(readlink "$TARGET_FILE") - cd "$(dirname "$TARGET_FILE")" - TARGET_FILE=$(basename "$TARGET_FILE") - COUNT=$(($COUNT + 1)) - done - - # make sure we grab the actual windows path, instead of cygwin's path. - if [[ "x$FIX_CYGPATH" != "x" ]]; then - echo "$(cygwinpath "$(pwd -P)/$TARGET_FILE")" - else - echo "$(pwd -P)/$TARGET_FILE" - fi -) -} - - -# Uses uname to detect if we're in the odd cygwin environment. -is_cygwin() { - local os=$(uname -s) - case "$os" in - CYGWIN*) return 0 ;; - *) return 1 ;; - esac -} - -# TODO - Use nicer bash-isms here. -CYGWIN_FLAG=$(if is_cygwin; then echo true; else echo false; fi) - - -# This can fix cygwin style /cygdrive paths so we get the -# windows style paths. -cygwinpath() { - local file="$1" - if [[ "$CYGWIN_FLAG" == "true" ]]; then - echo $(cygpath -w $file) - else - echo $file - fi -} - -# Make something URI friendly -make_url() { - url="$1" - local nospaces=${url// /%20} - if is_cygwin; then - echo "/${nospaces//\\//}" - else - echo "$nospaces" - fi -} - -declare -a residual_args -declare -a java_args -declare -a scalac_args -declare -a sbt_commands -declare java_cmd=java -declare java_version -declare -r real_script_path="$(realpath "$0")" -declare -r sbt_home="$(realpath "$(dirname "$(dirname "$real_script_path")")")" -declare -r sbt_bin_dir="$(dirname "$real_script_path")" -declare -r app_version="1.3.10" - -declare -r script_name=activator -declare -r java_opts=( "${ACTIVATOR_OPTS[@]}" "${SBT_OPTS[@]}" "${JAVA_OPTS[@]}" "${java_opts[@]}" ) -userhome="$HOME" -if is_cygwin; then - # cygwin sets home to something f-d up, set to real windows homedir - userhome="$USERPROFILE" -fi -declare -r activator_user_home_dir="${userhome}/.activator" -declare -r java_opts_config_home="${activator_user_home_dir}/activatorconfig.txt" -declare -r java_opts_config_version="${activator_user_home_dir}/${app_version}/activatorconfig.txt" - -echoerr () { - echo 1>&2 "$@" -} -vlog () { - [[ $verbose || $debug ]] && echoerr "$@" -} -dlog () { - [[ $debug ]] && echoerr "$@" -} - -jar_file () { - echo "$(cygwinpath "${sbt_home}/libexec/activator-launch-${app_version}.jar")" -} - -acquire_sbt_jar () { - sbt_jar="$(jar_file)" - - if [[ ! -f "$sbt_jar" ]]; then - echoerr "Could not find launcher jar: $sbt_jar" - exit 2 - fi -} - -execRunner () { - # print the arguments one to a line, quoting any containing spaces - [[ $verbose || $debug ]] && echo "# Executing command line:" && { - for arg; do - if printf "%s\n" "$arg" | grep -q ' '; then - printf "\"%s\"\n" "$arg" - else - printf "%s\n" "$arg" - fi - done - echo "" - } - - # THis used to be exec, but we loose the ability to re-hook stty then - # for cygwin... Maybe we should flag the feature here... - "$@" -} - -addJava () { - dlog "[addJava] arg = '$1'" - java_args=( "${java_args[@]}" "$1" ) -} -addSbt () { - dlog "[addSbt] arg = '$1'" - sbt_commands=( "${sbt_commands[@]}" "$1" ) -} -addResidual () { - dlog "[residual] arg = '$1'" - residual_args=( "${residual_args[@]}" "$1" ) -} -addDebugger () { - addJava "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$1" -} - -get_mem_opts () { - # if we detect any of these settings in ${JAVA_OPTS} we need to NOT output our settings. - # The reason is the Xms/Xmx, if they don't line up, cause errors. - if [[ "${JAVA_OPTS}" == *-Xmx* ]] || [[ "${JAVA_OPTS}" == *-Xms* ]] || [[ "${JAVA_OPTS}" == *-XX:MaxPermSize* ]] || [[ "${JAVA_OPTS}" == *-XX:MaxMetaspaceSize* ]] || [[ "${JAVA_OPTS}" == *-XX:ReservedCodeCacheSize* ]]; then - echo "" - else - # a ham-fisted attempt to move some memory settings in concert - # so they need not be messed around with individually. - local mem=${1:-1024} - local codecache=$(( $mem / 8 )) - (( $codecache > 128 )) || codecache=128 - (( $codecache < 512 )) || codecache=512 - local class_metadata_size=$(( $codecache * 2 )) - local class_metadata_opt=$([[ "$java_version" < "1.8" ]] && echo "MaxPermSize" || echo "MaxMetaspaceSize") - - echo "-Xms${mem}m -Xmx${mem}m -XX:ReservedCodeCacheSize=${codecache}m -XX:${class_metadata_opt}=${class_metadata_size}m" - fi -} - -require_arg () { - local type="$1" - local opt="$2" - local arg="$3" - if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then - echo "$opt requires <$type> argument" - exit 1 - fi -} - -is_function_defined() { - declare -f "$1" > /dev/null -} - -# If we're *not* running in a terminal, and we don't have any arguments, then we need to add the 'ui' parameter -detect_terminal_for_ui() { - [[ ! -t 0 ]] && [[ "${#residual_args}" == "0" ]] && { - addResidual "ui" - } - # SPECIAL TEST FOR MAC - [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]] && [[ "${#residual_args}" == "0" ]] && { - echo "Detected MAC OSX launched script...." - echo "Swapping to UI" - addResidual "ui" - } -} - -process_args () { - while [[ $# -gt 0 ]]; do - case "$1" in - -h|-help) usage; exit 1 ;; - -v|-verbose) verbose=1 && shift ;; - -d|-debug) debug=1 && shift ;; - - -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; - -mem) require_arg integer "$1" "$2" && sbt_mem="$2" && shift 2 ;; - -jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;; - -batch) exec &1 | awk -F '"' '/version/ {print $2}') - vlog "[process_args] java_version = '$java_version'" -} - -# Detect that we have java installed. -checkJava() { - local required_version="$1" - # Now check to see if it's a good enough version - if [[ "$java_version" == "" ]]; then - echo - echo No java installations was detected. - echo Please go to http://www.java.com/getjava/ and download - echo - exit 1 - elif [[ ! "$java_version" > "$required_version" ]]; then - echo - echo The java installation you have is not up to date - echo $script_name requires at least version $required_version+, you have - echo version $java_version - echo - echo Please go to http://www.java.com/getjava/ and download - echo a valid Java Runtime and install before running $script_name. - echo - exit 1 - fi -} - - -run() { - # no jar? download it. - [[ -f "$sbt_jar" ]] || acquire_sbt_jar "$sbt_version" || { - # still no jar? uh-oh. - echo "Download failed. Obtain the sbt-launch.jar manually and place it at $sbt_jar" - exit 1 - } - - # process the combined args, then reset "$@" to the residuals - process_args "$@" - detect_terminal_for_ui - set -- "${residual_args[@]}" - argumentCount=$# - - # TODO - java check should be configurable... - checkJava "1.6" - - #If we're in cygwin, we should use the windows config, and terminal hacks - if [[ "$CYGWIN_FLAG" == "true" ]]; then - stty -icanon min 1 -echo > /dev/null 2>&1 - addJava "-Djline.terminal=jline.UnixTerminal" - addJava "-Dsbt.cygwin=true" - fi - - # run sbt - execRunner "$java_cmd" \ - "-Dactivator.home=$(make_url "$sbt_home")" \ - ${SBT_OPTS:-$default_sbt_opts} \ - $(get_mem_opts $sbt_mem) \ - ${JAVA_OPTS} \ - ${java_args[@]} \ - -jar "$sbt_jar" \ - "${sbt_commands[@]}" \ - "${residual_args[@]}" - - exit_code=$? - - # Clean up the terminal from cygwin hacks. - if [[ "$CYGWIN_FLAG" == "true" ]]; then - stty icanon echo > /dev/null 2>&1 - fi - exit $exit_code -} - - -declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy" -declare -r sbt_opts_file=".sbtopts" -declare -r etc_sbt_opts_file="${sbt_home}/conf/sbtopts" -declare -r win_sbt_opts_file="${sbt_home}/conf/sbtconfig.txt" - -usage() { - cat < path to global settings/plugins directory (default: ~/.sbt) - -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11 series) - -ivy path to local Ivy repository (default: ~/.ivy2) - -mem set memory options (default: $sbt_mem, which is $(get_mem_opts $sbt_mem)) - -no-share use all local caches; no sharing - -no-global uses global caches, but does not use global ~/.sbt directory. - -jvm-debug Turn on JVM debugging, open at the given port. - -batch Disable interactive mode - - # sbt version (default: from project/build.properties if present, else latest release) - -sbt-version use the specified version of sbt - -sbt-jar use the specified jar as the sbt launcher - -sbt-rc use an RC version of sbt - -sbt-snapshot use a snapshot version of sbt - - # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) - -java-home alternate JAVA_HOME - - # jvm options and output control - JAVA_OPTS environment variable, if unset uses "$java_opts" - SBT_OPTS environment variable, if unset uses "$default_sbt_opts" - ACTIVATOR_OPTS Environment variable, if unset uses "" - .sbtopts if this file exists in the current directory, it is - prepended to the runner args - /etc/sbt/sbtopts if this file exists, it is prepended to the runner args - -Dkey=val pass -Dkey=val directly to the java runtime - -J-X pass option -X directly to the java runtime - (-J is stripped) - -S-X add -X to sbt's scalacOptions (-S is stripped) - -In the case of duplicated or conflicting options, the order above -shows precedence: JAVA_OPTS lowest, command line options highest. -EOM -} - - - -process_my_args () { - while [[ $# -gt 0 ]]; do - case "$1" in - -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;; - -no-share) addJava "$noshare_opts" && shift ;; - -no-global) addJava "-Dsbt.global.base=$(pwd)/project/.sbtboot" && shift ;; - -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; - -sbt-dir) require_arg path "$1" "$2" && addJava "-Dsbt.global.base=$2" && shift 2 ;; - -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; - -batch) exec ^&1') do ( - if %%~j==java set JAVAINSTALLED=1 - if %%~j==openjdk set JAVAINSTALLED=1 -) - -rem Detect the same thing about javac -if "%_JAVACCMD%"=="" ( - if not "%JAVA_HOME%"=="" ( - if exist "%JAVA_HOME%\bin\javac.exe" set "_JAVACCMD=%JAVA_HOME%\bin\javac.exe" - ) -) -if "%_JAVACCMD%"=="" set _JAVACCMD=javac -for /F %%j in ('"%_JAVACCMD%" -version 2^>^&1') do ( - if %%~j==javac set JAVACINSTALLED=1 -) - -rem BAT has no logical or, so we do it OLD SCHOOL! Oppan Redmond Style -set JAVAOK=true -if not defined JAVAINSTALLED set JAVAOK=false -if not defined JAVACINSTALLED set JAVAOK=false - -if "%JAVAOK%"=="false" ( - echo. - echo A Java JDK is not installed or can't be found. - if not "%JAVA_HOME%"=="" ( - echo JAVA_HOME = "%JAVA_HOME%" - ) - echo. - echo Please go to - echo http://www.oracle.com/technetwork/java/javase/downloads/index.html - echo and download a valid Java JDK and install before running Activator. - echo. - echo If you think this message is in error, please check - echo your environment variables to see if "java.exe" and "javac.exe" are - echo available via JAVA_HOME or PATH. - echo. - if defined DOUBLECLICKED pause - exit /B 1 -) - -rem Check what Java version is being used to determine what memory options to use -for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do ( - set JAVA_VERSION=%%g -) - -rem Strips away the " characters -set JAVA_VERSION=%JAVA_VERSION:"=% - -rem TODO Check if there are existing mem settings in JAVA_OPTS/CFG_OPTS and use those instead of the below -for /f "delims=. tokens=1-3" %%v in ("%JAVA_VERSION%") do ( - set MAJOR=%%v - set MINOR=%%w - set BUILD=%%x - - set META_SIZE=-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=256M - if "!MINOR!" LSS "8" ( - set META_SIZE=-XX:PermSize=64M -XX:MaxPermSize=256M - ) - - set MEM_OPTS=!META_SIZE! - ) - -rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config. -set _JAVA_OPTS=%JAVA_OPTS% -if "%_JAVA_OPTS%"=="" set _JAVA_OPTS=%CFG_OPTS% - -set DEBUG_OPTS= - -rem Loop through the arguments, building remaining args in args variable -set args= -:argsloop -if not "%~1"=="" ( - rem Checks if the argument contains "-D" and if true, adds argument 1 with 2 and puts an equal sign between them. - rem This is done since batch considers "=" to be a delimiter so we need to circumvent this behavior with a small hack. - set arg1=%~1 - if "!arg1:~0,2!"=="-D" ( - set "args=%args% "%~1"="%~2"" - shift - shift - goto argsloop - ) - - if "%~1"=="-jvm-debug" ( - if not "%~2"=="" ( - rem This piece of magic somehow checks that an argument is a number - for /F "delims=0123456789" %%i in ("%~2") do ( - set var="%%i" - ) - if defined var ( - rem Not a number, assume no argument given and default to 9999 - set JPDA_PORT=9999 - ) else ( - rem Port was given, shift arguments - set JPDA_PORT=%~2 - shift - ) - ) else ( - set JPDA_PORT=9999 - ) - shift - - set DEBUG_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=!JPDA_PORT! - goto argsloop - ) - rem else - set "args=%args% "%~1"" - shift - goto argsloop -) - -:run - -if "!args!"=="" ( - if defined DOUBLECLICKED ( - set CMDS="ui" - ) else set CMDS=!args! -) else set CMDS=!args! - -rem We add a / in front, so we get file:///C: instead of file://C: -rem Java considers the later a UNC path. -rem We also attempt a solid effort at making it URI friendly. -rem We don't even bother with UNC paths. -set JAVA_FRIENDLY_HOME_1=/!ACTIVATOR_HOME:\=/! -set JAVA_FRIENDLY_HOME=/!JAVA_FRIENDLY_HOME_1: =%%20! - -rem Checks if the command contains spaces to know if it should be wrapped in quotes or not -set NON_SPACED_CMD=%_JAVACMD: =% -if "%_JAVACMD%"=="%NON_SPACED_CMD%" %_JAVACMD% %DEBUG_OPTS% %MEM_OPTS% %ACTIVATOR_OPTS% %SBT_OPTS% %_JAVA_OPTS% "-Dactivator.home=%JAVA_FRIENDLY_HOME%" -jar "%ACTIVATOR_HOME%\libexec\%ACTIVATOR_LAUNCH_JAR%" %CMDS% -if NOT "%_JAVACMD%"=="%NON_SPACED_CMD%" "%_JAVACMD%" %DEBUG_OPTS% %MEM_OPTS% %ACTIVATOR_OPTS% %SBT_OPTS% %_JAVA_OPTS% "-Dactivator.home=%JAVA_FRIENDLY_HOME%" -jar "%ACTIVATOR_HOME%\libexec\%ACTIVATOR_LAUNCH_JAR%" %CMDS% - -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end - -@endlocal - -exit /B %ERROR_CODE% diff --git a/play-framework/routing-in-play/build.sbt b/play-framework/routing-in-play/build.sbt index 083d071676..4fb0126eaa 100644 --- a/play-framework/routing-in-play/build.sbt +++ b/play-framework/routing-in-play/build.sbt @@ -1,13 +1,10 @@ -name := """webapp""" +name := """play-routing""" +organization := "com.baeldung" version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayJava) -scalaVersion := "2.11.7" +scalaVersion := "2.13.0" -libraryDependencies ++= Seq( - javaJdbc, - cache, - javaWs -) +libraryDependencies += guice diff --git a/play-framework/routing-in-play/conf/application.conf b/play-framework/routing-in-play/conf/application.conf index 489d3f9b3e..85c184dcb1 100644 --- a/play-framework/routing-in-play/conf/application.conf +++ b/play-framework/routing-in-play/conf/application.conf @@ -1,353 +1,2 @@ # This is the main configuration file for the application. # https://www.playframework.com/documentation/latest/ConfigFile -# ~~~~~ -# Play uses HOCON as its configuration file format. HOCON has a number -# of advantages over other config formats, but there are two things that -# can be used when modifying settings. -# -# You can include other configuration files in this main application.conf file: -#include "extra-config.conf" -# -# You can declare variables and substitute for them: -#mykey = ${some.value} -# -# And if an environment variable exists when there is no other subsitution, then -# HOCON will fall back to substituting environment variable: -#mykey = ${JAVA_HOME} - -## Akka -# https://www.playframework.com/documentation/latest/ScalaAkka#Configuration -# https://www.playframework.com/documentation/latest/JavaAkka#Configuration -# ~~~~~ -# Play uses Akka internally and exposes Akka Streams and actors in Websockets and -# other streaming HTTP responses. -akka { - # "akka.log-config-on-start" is extraordinarly useful because it log the complete - # configuration at INFO level, including defaults and overrides, so it s worth - # putting at the very top. - # - # Put the following in your conf/logback.xml file: - # - # - # - # And then uncomment this line to debug the configuration. - # - #log-config-on-start = true -} - -## Secret key -# http://www.playframework.com/documentation/latest/ApplicationSecret -# ~~~~~ -# The secret key is used to sign Play's session cookie. -# This must be changed for production, but we don't recommend you change it in this file. -play.crypto.secret = "changeme" - -## Modules -# https://www.playframework.com/documentation/latest/Modules -# ~~~~~ -# Control which modules are loaded when Play starts. Note that modules are -# the replacement for "GlobalSettings", which are deprecated in 2.5.x. -# Please see https://www.playframework.com/documentation/latest/GlobalSettings -# for more information. -# -# You can also extend Play functionality by using one of the publically available -# Play modules: https://playframework.com/documentation/latest/ModuleDirectory -play.modules { - # By default, Play will load any class called Module that is defined - # in the root package (the "app" directory), or you can define them - # explicitly below. - # If there are any built-in modules that you want to disable, you can list them here. - #enabled += my.application.Module - - # If there are any built-in modules that you want to disable, you can list them here. - #disabled += "" -} - -## IDE -# https://www.playframework.com/documentation/latest/IDE -# ~~~~~ -# Depending on your IDE, you can add a hyperlink for errors that will jump you -# directly to the code location in the IDE in dev mode. The following line makes -# use of the IntelliJ IDEA REST interface: -#play.editor="http://localhost:63342/api/file/?file=%s&line=%s" - -## Internationalisation -# https://www.playframework.com/documentation/latest/JavaI18N -# https://www.playframework.com/documentation/latest/ScalaI18N -# ~~~~~ -# Play comes with its own i18n settings, which allow the user's preferred language -# to map through to internal messages, or allow the language to be stored in a cookie. -play.i18n { - # The application languages - langs = [ "en" ] - - # Whether the language cookie should be secure or not - #langCookieSecure = true - - # Whether the HTTP only attribute of the cookie should be set to true - #langCookieHttpOnly = true -} - -## Play HTTP settings -# ~~~~~ -play.http { - ## Router - # https://www.playframework.com/documentation/latest/JavaRouting - # https://www.playframework.com/documentation/latest/ScalaRouting - # ~~~~~ - # Define the Router object to use for this application. - # This router will be looked up first when the application is starting up, - # so make sure this is the entry point. - # Furthermore, it's assumed your route file is named properly. - # So for an application router like `my.application.Router`, - # you may need to define a router file `conf/my.application.routes`. - # Default to Routes in the root package (aka "apps" folder) (and conf/routes) - #router = my.application.Router - - ## Action Creator - # https://www.playframework.com/documentation/latest/JavaActionCreator - # ~~~~~ - #actionCreator = null - - ## ErrorHandler - # https://www.playframework.com/documentation/latest/JavaRouting - # https://www.playframework.com/documentation/latest/ScalaRouting - # ~~~~~ - # If null, will attempt to load a class called ErrorHandler in the root package, - #errorHandler = null - - ## Filters - # https://www.playframework.com/documentation/latest/ScalaHttpFilters - # https://www.playframework.com/documentation/latest/JavaHttpFilters - # ~~~~~ - # Filters run code on every request. They can be used to perform - # common logic for all your actions, e.g. adding common headers. - # Defaults to "Filters" in the root package (aka "apps" folder) - # Alternatively you can explicitly register a class here. - #filters = my.application.Filters - - ## Session & Flash - # https://www.playframework.com/documentation/latest/JavaSessionFlash - # https://www.playframework.com/documentation/latest/ScalaSessionFlash - # ~~~~~ - session { - # Sets the cookie to be sent only over HTTPS. - #secure = true - - # Sets the cookie to be accessed only by the server. - #httpOnly = true - - # Sets the max-age field of the cookie to 5 minutes. - # NOTE: this only sets when the browser will discard the cookie. Play will consider any - # cookie value with a valid signature to be a valid session forever. To implement a server side session timeout, - # you need to put a timestamp in the session and check it at regular intervals to possibly expire it. - #maxAge = 300 - - # Sets the domain on the session cookie. - #domain = "example.com" - } - - flash { - # Sets the cookie to be sent only over HTTPS. - #secure = true - - # Sets the cookie to be accessed only by the server. - #httpOnly = true - } -} - -## Netty Provider -# https://www.playframework.com/documentation/latest/SettingsNetty -# ~~~~~ -play.server.netty { - # Whether the Netty wire should be logged - #log.wire = true - - # If you run Play on Linux, you can use Netty's native socket transport - # for higher performance with less garbage. - #transport = "native" -} - -## WS (HTTP Client) -# https://www.playframework.com/documentation/latest/ScalaWS#Configuring-WS -# ~~~~~ -# The HTTP client primarily used for REST APIs. The default client can be -# configured directly, but you can also create different client instances -# with customized settings. You must enable this by adding to build.sbt: -# -# libraryDependencies += ws // or javaWs if using java -# -play.ws { - # Sets HTTP requests not to follow 302 requests - #followRedirects = false - - # Sets the maximum number of open HTTP connections for the client. - #ahc.maxConnectionsTotal = 50 - - ## WS SSL - # https://www.playframework.com/documentation/latest/WsSSL - # ~~~~~ - ssl { - # Configuring HTTPS with Play WS does not require programming. You can - # set up both trustManager and keyManager for mutual authentication, and - # turn on JSSE debugging in development with a reload. - #debug.handshake = true - #trustManager = { - # stores = [ - # { type = "JKS", path = "exampletrust.jks" } - # ] - #} - } -} - -## Cache -# https://www.playframework.com/documentation/latest/JavaCache -# https://www.playframework.com/documentation/latest/ScalaCache -# ~~~~~ -# Play comes with an integrated cache API that can reduce the operational -# overhead of repeated requests. You must enable this by adding to build.sbt: -# -# libraryDependencies += cache -# -play.cache { - # If you want to bind several caches, you can bind the individually - #bindCaches = ["db-cache", "user-cache", "session-cache"] -} - -## Filters -# https://www.playframework.com/documentation/latest/Filters -# ~~~~~ -# There are a number of built-in filters that can be enabled and configured -# to give Play greater security. You must enable this by adding to build.sbt: -# -# libraryDependencies += filters -# -play.filters { - ## CORS filter configuration - # https://www.playframework.com/documentation/latest/CorsFilter - # ~~~~~ - # CORS is a protocol that allows web applications to make requests from the browser - # across different domains. - # NOTE: You MUST apply the CORS configuration before the CSRF filter, as CSRF has - # dependencies on CORS settings. - cors { - # Filter paths by a whitelist of path prefixes - #pathPrefixes = ["/some/path", ...] - - # The allowed origins. If null, all origins are allowed. - #allowedOrigins = ["http://www.example.com"] - - # The allowed HTTP methods. If null, all methods are allowed - #allowedHttpMethods = ["GET", "POST"] - } - - ## CSRF Filter - # https://www.playframework.com/documentation/latest/ScalaCsrf#Applying-a-global-CSRF-filter - # https://www.playframework.com/documentation/latest/JavaCsrf#Applying-a-global-CSRF-filter - # ~~~~~ - # Play supports multiple methods for verifying that a request is not a CSRF request. - # The primary mechanism is a CSRF token. This token gets placed either in the query string - # or body of every form submitted, and also gets placed in the users session. - # Play then verifies that both tokens are present and match. - csrf { - # Sets the cookie to be sent only over HTTPS - #cookie.secure = true - - # Defaults to CSRFErrorHandler in the root package. - #errorHandler = MyCSRFErrorHandler - } - - ## Security headers filter configuration - # https://www.playframework.com/documentation/latest/SecurityHeaders - # ~~~~~ - # Defines security headers that prevent XSS attacks. - # If enabled, then all options are set to the below configuration by default: - headers { - # The X-Frame-Options header. If null, the header is not set. - #frameOptions = "DENY" - - # The X-XSS-Protection header. If null, the header is not set. - #xssProtection = "1; mode=block" - - # The X-Content-Type-Options header. If null, the header is not set. - #contentTypeOptions = "nosniff" - - # The X-Permitted-Cross-Domain-Policies header. If null, the header is not set. - #permittedCrossDomainPolicies = "master-only" - - # The Content-Security-Policy header. If null, the header is not set. - #contentSecurityPolicy = "default-src 'self'" - } - - ## Allowed hosts filter configuration - # https://www.playframework.com/documentation/latest/AllowedHostsFilter - # ~~~~~ - # Play provides a filter that lets you configure which hosts can access your application. - # This is useful to prevent cache poisoning attacks. - hosts { - # Allow requests to example.com, its subdomains, and localhost:9000. - #allowed = [".example.com", "localhost:9000"] - } -} - -## Evolutions -# https://www.playframework.com/documentation/latest/Evolutions -# ~~~~~ -# Evolutions allows database scripts to be automatically run on startup in dev mode -# for database migrations. You must enable this by adding to build.sbt: -# -# libraryDependencies += evolutions -# -play.evolutions { - # You can disable evolutions for a specific datasource if necessary - #db.default.enabled = false -} - -## Database Connection Pool -# https://www.playframework.com/documentation/latest/SettingsJDBC -# ~~~~~ -# Play doesn't require a JDBC database to run, but you can easily enable one. -# -# libraryDependencies += jdbc -# -play.db { - # The combination of these two settings results in "db.default" as the - # default JDBC pool: - #config = "db" - #default = "default" - - # Play uses HikariCP as the default connection pool. You can override - # settings by changing the prototype: - prototype { - # Sets a fixed JDBC connection pool size of 50 - #hikaricp.minimumIdle = 50 - #hikaricp.maximumPoolSize = 50 - } -} - -## JDBC Datasource -# https://www.playframework.com/documentation/latest/JavaDatabase -# https://www.playframework.com/documentation/latest/ScalaDatabase -# ~~~~~ -# Once JDBC datasource is set up, you can work with several different -# database options: -# -# Slick (Scala preferred option): https://www.playframework.com/documentation/latest/PlaySlick -# JPA (Java preferred option): https://playframework.com/documentation/latest/JavaJPA -# EBean: https://playframework.com/documentation/latest/JavaEbean -# Anorm: https://www.playframework.com/documentation/latest/ScalaAnorm -# -db { - # You can declare as many datasources as you want. - # By convention, the default datasource is named `default` - - # https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database - #default.driver = org.h2.Driver - #default.url = "jdbc:h2:mem:play" - #default.username = sa - #default.password = "" - - # You can turn on SQL logging for any datasource - # https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements - #default.logSql=true -} diff --git a/play-framework/routing-in-play/conf/logback.xml b/play-framework/routing-in-play/conf/logback.xml index 86ec12c0af..e8c982543f 100644 --- a/play-framework/routing-in-play/conf/logback.xml +++ b/play-framework/routing-in-play/conf/logback.xml @@ -27,12 +27,6 @@ - - - - - - diff --git a/play-framework/routing-in-play/conf/routes b/play-framework/routing-in-play/conf/routes index f72d8a1a14..43dc4c8733 100644 --- a/play-framework/routing-in-play/conf/routes +++ b/play-framework/routing-in-play/conf/routes @@ -1,7 +1,15 @@ -GET / controllers.HomeController.index(author="Baeldung",id:Int?=1) -GET /:author controllers.HomeController.index(author,id:Int?=1) -GET /greet/:name/:age controllers.HomeController.greet(name,age:Integer) -GET /square/$num<[0-9]+> controllers.HomeController.squareMe(num:Long) +# Routes +# This file defines all application routes (Higher priority routes first) +# ~~~~ + +# An example controller showing a sample home page +GET / controllers.HomeController.index +GET /writer controllers.HomeController.writer(author = "Baeldung", id: Int ?= 1) +GET /writer/:author controllers.HomeController.writer(author: String, id: Int ?= 1) +GET /baeldung/:id controllers.HomeController.viewUser(id: String) +GET /greet/:name/:age controllers.HomeController.greet(name: String, age: Integer) +GET /square/$num<[0-9]+> controllers.HomeController.squareMe(num: Long) +GET /*data controllers.HomeController.introduceMe(data) + # Map static resources from the /public folder to the /assets URL path -GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) -GET /*data controllers.HomeController.introduceMe(data) +GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) diff --git a/play-framework/routing-in-play/libexec/activator-launch-1.3.10.jar b/play-framework/routing-in-play/libexec/activator-launch-1.3.10.jar deleted file mode 100644 index 69050e7dec..0000000000 Binary files a/play-framework/routing-in-play/libexec/activator-launch-1.3.10.jar and /dev/null differ diff --git a/play-framework/routing-in-play/project/build.properties b/play-framework/routing-in-play/project/build.properties index 6d22e3f2d1..c0bab04941 100644 --- a/play-framework/routing-in-play/project/build.properties +++ b/play-framework/routing-in-play/project/build.properties @@ -1,4 +1 @@ -#Activator-generated Properties -#Fri Sep 30 14:25:10 EAT 2016 -template.uuid=26c759a5-daf0-4e02-bcfa-ac69725267c0 -sbt.version=0.13.11 +sbt.version=1.2.8 diff --git a/play-framework/routing-in-play/project/plugins.sbt b/play-framework/routing-in-play/project/plugins.sbt index e8e7f602f7..1c8c62a0d5 100644 --- a/play-framework/routing-in-play/project/plugins.sbt +++ b/play-framework/routing-in-play/project/plugins.sbt @@ -1,21 +1,7 @@ // The Play plugin -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.8") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3") -// Web plugins -addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.4") -addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.8") -addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.1.1") -addSbtPlugin("com.typesafe.sbt" % "sbt-mocha" % "1.1.0") -addSbtPlugin("org.irundaia.sbt" % "sbt-sassify" % "1.4.6") - -// Play enhancer - this automatically generates getters/setters for public fields -// and rewrites accessors of these fields to use the getters/setters. Remove this -// plugin if you prefer not to have this feature, or disable on a per project -// basis using disablePlugins(PlayEnhancer) in your build.sbt -addSbtPlugin("com.typesafe.sbt" % "sbt-play-enhancer" % "1.1.0") - -// Play Ebean support, to enable, uncomment this line, and enable in your build.sbt using -// enablePlugins(PlayEbean). -// addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.2") +// Defines scaffolding (found under .g8 folder) +// http://www.foundweekends.org/giter8/scaffolding.html +// sbt "g8Scaffold form" +addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0") diff --git a/play-framework/routing-in-play/public/javascripts/hello.js b/play-framework/routing-in-play/public/javascripts/hello.js deleted file mode 100644 index 02ee13c7ca..0000000000 --- a/play-framework/routing-in-play/public/javascripts/hello.js +++ /dev/null @@ -1,3 +0,0 @@ -if (window.console) { - console.log("Welcome to your Play application's JavaScript!"); -} diff --git a/play-framework/routing-in-play/public/javascripts/main.js b/play-framework/routing-in-play/public/javascripts/main.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/play-framework/routing-in-play/test/ApplicationUnitTest.java b/play-framework/routing-in-play/test/ApplicationUnitTest.java deleted file mode 100644 index 572ce282bc..0000000000 --- a/play-framework/routing-in-play/test/ApplicationUnitTest.java +++ /dev/null @@ -1,45 +0,0 @@ -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.databind.JsonNode; -import org.junit.*; - -import play.mvc.*; -import play.test.*; -import play.data.DynamicForm; -import play.data.validation.ValidationError; -import play.data.validation.Constraints.RequiredValidator; -import play.i18n.Lang; -import play.libs.F; -import play.libs.F.*; -import play.twirl.api.Content; - -import static play.test.Helpers.*; -import static org.junit.Assert.*; - - -/** - * - * Simple (JUnit) tests that can call all parts of a play app. - * If you are interested in mocking a whole application, see the wiki for more details. - * - */ -public class ApplicationUnitTest { - - @Test - public void simpleCheck() { - int a = 1 + 1; - assertEquals(2, a); - } - - @Test - public void renderTemplate() { - Content html = views.html.index.render("Your new application is ready."); - assertEquals("text/html", html.contentType()); - assertTrue(html.body().contains("Your new application is ready.")); - } - - -} diff --git a/play-framework/routing-in-play/test/IntegrationTest.java b/play-framework/routing-in-play/test/IntegrationTest.java deleted file mode 100644 index c53c71e124..0000000000 --- a/play-framework/routing-in-play/test/IntegrationTest.java +++ /dev/null @@ -1,25 +0,0 @@ -import org.junit.*; - -import play.mvc.*; -import play.test.*; - -import static play.test.Helpers.*; -import static org.junit.Assert.*; - -import static org.fluentlenium.core.filter.FilterConstructor.*; - -public class IntegrationTest { - - /** - * add your integration test here - * in this example we just check if the welcome page is being shown - */ - @Test - public void test() { - running(testServer(3333, fakeApplication(inMemoryDatabase())), HTMLUNIT, browser -> { - browser.goTo("http://localhost:3333"); - assertTrue(browser.pageSource().contains("Your new application is ready.")); - }); - } - -} diff --git a/play-framework/routing-in-play/test/controllers/HomeControllerUnitTest.java b/play-framework/routing-in-play/test/controllers/HomeControllerUnitTest.java new file mode 100644 index 0000000000..b911242ac7 --- /dev/null +++ b/play-framework/routing-in-play/test/controllers/HomeControllerUnitTest.java @@ -0,0 +1,36 @@ +package controllers; + +import org.junit.Test; +import play.Application; +import play.inject.guice.GuiceApplicationBuilder; +import play.mvc.Http; +import play.mvc.Result; +import play.test.WithApplication; +import play.twirl.api.Html; + +import java.util.Optional; +import java.util.concurrent.CompletionStage; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static play.mvc.Http.Status.*; +import static play.test.Helpers.GET; +import static play.test.Helpers.route; + +public class HomeControllerUnitTest extends WithApplication { + + @Override + protected Application provideApplication() { + return new GuiceApplicationBuilder().build(); + } + + @Test + public void givenRequest_whenRootPath_ThenStatusOkay() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/"); + + Result result = route(app, request); + assertEquals(OK, result.status()); + } +} diff --git a/play-framework/routing-in-play/.gitignore b/play-framework/student-api/.gitignore similarity index 94% rename from play-framework/routing-in-play/.gitignore rename to play-framework/student-api/.gitignore index eb372fc719..e497f3fc67 100644 --- a/play-framework/routing-in-play/.gitignore +++ b/play-framework/student-api/.gitignore @@ -1,6 +1,7 @@ logs target /.idea +/.g8 /.idea_modules /.classpath /.project diff --git a/play-framework/student-api/app/controllers/StudentController.java b/play-framework/student-api/app/controllers/StudentController.java new file mode 100644 index 0000000000..5373511560 --- /dev/null +++ b/play-framework/student-api/app/controllers/StudentController.java @@ -0,0 +1,91 @@ +package controllers; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import model.Student; +import play.libs.Json; +import play.libs.concurrent.HttpExecutionContext; +import play.mvc.Controller; +import play.mvc.Http; +import play.mvc.Result; +import store.StudentStore; +import utils.Util; + +import javax.inject.Inject; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletionStage; + +import static java.util.concurrent.CompletableFuture.supplyAsync; + +public class StudentController extends Controller { + private HttpExecutionContext ec; + private StudentStore studentStore; + + @Inject + public StudentController(HttpExecutionContext ec, StudentStore studentStore) { + this.studentStore = studentStore; + this.ec = ec; + } + + public CompletionStage create(Http.Request request) { + JsonNode json = request.body().asJson(); + return supplyAsync(() -> { + if (json == null) { + return badRequest(Util.createResponse("Expecting Json data", false)); + } + + Optional studentOptional = studentStore.addStudent(Json.fromJson(json, Student.class)); + return studentOptional.map(student -> { + JsonNode jsonObject = Json.toJson(student); + return created(Util.createResponse(jsonObject, true)); + }).orElse(internalServerError(Util.createResponse("Could not create data.", false))); + }, ec.current()); + } + + public CompletionStage listStudents() { + return supplyAsync(() -> { + Set result = studentStore.getAllStudents(); + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonData = mapper.convertValue(result, JsonNode.class); + return ok(Util.createResponse(jsonData, true)); + }, ec.current()); + } + + public CompletionStage retrieve(int id) { + return supplyAsync(() -> { + final Optional studentOptional = studentStore.getStudent(id); + return studentOptional.map(student -> { + JsonNode jsonObjects = Json.toJson(student); + return ok(Util.createResponse(jsonObjects, true)); + }).orElse(notFound(Util.createResponse("Student with id:" + id + " not found", false))); + }, ec.current()); + } + + public CompletionStage update(Http.Request request) { + JsonNode json = request.body().asJson(); + return supplyAsync(() -> { + if (json == null) { + return badRequest(Util.createResponse("Expecting Json data", false)); + } + Optional studentOptional = studentStore.updateStudent(Json.fromJson(json, Student.class)); + return studentOptional.map(student -> { + if (student == null) { + return notFound(Util.createResponse("Student not found", false)); + } + JsonNode jsonObject = Json.toJson(student); + return ok(Util.createResponse(jsonObject, true)); + }).orElse(internalServerError(Util.createResponse("Could not create data.", false))); + }, ec.current()); + } + + public CompletionStage delete(int id) { + return supplyAsync(() -> { + boolean status = studentStore.deleteStudent(id); + if (!status) { + return notFound(Util.createResponse("Student with id:" + id + " not found", false)); + } + return ok(Util.createResponse("Student with id:" + id + " deleted", true)); + }, ec.current()); + } +} diff --git a/play-framework/introduction/app/models/Student.java b/play-framework/student-api/app/model/Student.java similarity index 84% rename from play-framework/introduction/app/models/Student.java rename to play-framework/student-api/app/model/Student.java index dc539767bd..39cbfe0040 100644 --- a/play-framework/introduction/app/models/Student.java +++ b/play-framework/student-api/app/model/Student.java @@ -1,15 +1,19 @@ -package models; +package model; + public class Student { private String firstName; private String lastName; private int age; private int id; - public Student(){} - public Student(String firstName, String lastName, int age) { - super(); + + public Student() { + } + + public Student(String firstName, String lastName, int age, int id) { this.firstName = firstName; this.lastName = lastName; this.age = age; + this.id = id; } public String getFirstName() { @@ -43,5 +47,4 @@ public class Student { public void setId(int id) { this.id = id; } - } diff --git a/play-framework/student-api/app/store/StudentStore.java b/play-framework/student-api/app/store/StudentStore.java new file mode 100644 index 0000000000..315db5b916 --- /dev/null +++ b/play-framework/student-api/app/store/StudentStore.java @@ -0,0 +1,37 @@ +package store; + +import model.Student; + +import java.util.*; + +public class StudentStore { + private Map students = new HashMap<>(); + + public Optional addStudent(Student student) { + int id = students.size(); + student.setId(id); + students.put(id, student); + return Optional.ofNullable(student); + } + + public Optional getStudent(int id) { + return Optional.ofNullable(students.get(id)); + } + + public Set getAllStudents() { + return new HashSet<>(students.values()); + } + + public Optional updateStudent(Student student) { + int id = student.getId(); + if (students.containsKey(id)) { + students.put(id, student); + return Optional.ofNullable(student); + } + return Optional.empty(); + } + + public boolean deleteStudent(int id) { + return students.remove(id) != null; + } +} diff --git a/play-framework/introduction/app/util/Util.java b/play-framework/student-api/app/utils/Util.java similarity index 60% rename from play-framework/introduction/app/util/Util.java rename to play-framework/student-api/app/utils/Util.java index a853a4cb43..3fb9833ada 100644 --- a/play-framework/introduction/app/util/Util.java +++ b/play-framework/student-api/app/utils/Util.java @@ -1,17 +1,17 @@ -package util; +package utils; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import play.libs.Json; public class Util { public static ObjectNode createResponse(Object response, boolean ok) { ObjectNode result = Json.newObject(); - result.put("isSuccessfull", ok); - if (response instanceof String) + result.put("isSuccessful", ok); + if (response instanceof String) { result.put("body", (String) response); - else result.put("body", (JsonNode) response); - + } else { + result.putPOJO("body", response); + } return result; } -} \ No newline at end of file +} diff --git a/play-framework/student-api/build.sbt b/play-framework/student-api/build.sbt new file mode 100644 index 0000000000..13d3fe96cd --- /dev/null +++ b/play-framework/student-api/build.sbt @@ -0,0 +1,10 @@ +name := """student-api""" +organization := "com.baeldung" + +version := "1.0-SNAPSHOT" + +lazy val root = (project in file(".")).enablePlugins(PlayJava) + +scalaVersion := "2.13.0" + +libraryDependencies += guice diff --git a/play-framework/student-api/conf/application.conf b/play-framework/student-api/conf/application.conf new file mode 100644 index 0000000000..85c184dcb1 --- /dev/null +++ b/play-framework/student-api/conf/application.conf @@ -0,0 +1,2 @@ +# This is the main configuration file for the application. +# https://www.playframework.com/documentation/latest/ConfigFile diff --git a/play-framework/student-api/conf/logback.xml b/play-framework/student-api/conf/logback.xml new file mode 100644 index 0000000000..e8c982543f --- /dev/null +++ b/play-framework/student-api/conf/logback.xml @@ -0,0 +1,35 @@ + + + + + + + ${application.home:-.}/logs/application.log + + %date [%level] from %logger in %thread - %message%n%xException + + + + + + %coloredLevel %logger{15} - %message%n%xException{10} + + + + + + + + + + + + + + + + + + + + diff --git a/play-framework/student-api/conf/routes b/play-framework/student-api/conf/routes new file mode 100644 index 0000000000..f89b866953 --- /dev/null +++ b/play-framework/student-api/conf/routes @@ -0,0 +1,12 @@ +# Routes +# This file defines all application routes (Higher priority routes first) +# ~~~~ + +GET / controllers.StudentController.listStudents() +GET /:id controllers.StudentController.retrieve(id:Int) +POST / controllers.StudentController.create(request: Request) +PUT / controllers.StudentController.update(request: Request) +DELETE /:id controllers.StudentController.delete(id:Int) + +# Map static resources from the /public folder to the /assets URL path +GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) diff --git a/play-framework/student-api/project/build.properties b/play-framework/student-api/project/build.properties new file mode 100644 index 0000000000..c0bab04941 --- /dev/null +++ b/play-framework/student-api/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.2.8 diff --git a/play-framework/student-api/project/plugins.sbt b/play-framework/student-api/project/plugins.sbt new file mode 100644 index 0000000000..1c8c62a0d5 --- /dev/null +++ b/play-framework/student-api/project/plugins.sbt @@ -0,0 +1,7 @@ +// The Play plugin +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3") + +// Defines scaffolding (found under .g8 folder) +// http://www.foundweekends.org/giter8/scaffolding.html +// sbt "g8Scaffold form" +addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0") diff --git a/play-framework/student-api/test/ApplicationLiveTest.java b/play-framework/student-api/test/ApplicationLiveTest.java deleted file mode 100644 index beeef1a602..0000000000 --- a/play-framework/student-api/test/ApplicationLiveTest.java +++ /dev/null @@ -1,172 +0,0 @@ - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Arrays; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; -import model.Student; -import play.test.*; -import static play.test.Helpers.*; - -public class ApplicationLiveTest{ - private static final String BASE_URL = "http://localhost:9000"; - - @Test -public void testInServer() throws Exception { - TestServer server = testServer(3333); - running(server, () -> { - try { - WSClient ws = play.libs.ws.WS.newClient(3333); - CompletionStage completionStage = ws.url("/").get(); - WSResponse response = completionStage.toCompletableFuture().get(); - ws.close(); - assertEquals(OK, response.getStatus()); - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - }); -} - @Test - public void whenCreatesRecord_thenCorrect() { - Student student = new Student("jody", "west", 50); - JSONObject obj = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))); - assertTrue(obj.getBoolean("isSuccessfull")); - JSONObject body = obj.getJSONObject("body"); - assertEquals(student.getAge(), body.getInt("age")); - assertEquals(student.getFirstName(), body.getString("firstName")); - assertEquals(student.getLastName(), body.getString("lastName")); - } - - @Test - public void whenDeletesCreatedRecord_thenCorrect() { - Student student = new Student("Usain", "Bolt", 25); - JSONObject ob1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body"); - int id = ob1.getInt("id"); - JSONObject obj1 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject())); - assertTrue(obj1.getBoolean("isSuccessfull")); - makeRequest(BASE_URL + "/" + id, "DELETE", null); - JSONObject obj2 = new JSONObject(makeRequest(BASE_URL + "/" + id, "POST", new JSONObject())); - assertFalse(obj2.getBoolean("isSuccessfull")); - } - - @Test - public void whenUpdatesCreatedRecord_thenCorrect() { - Student student = new Student("john", "doe", 50); - JSONObject body1 = new JSONObject(makeRequest(BASE_URL, "POST", new JSONObject(student))).getJSONObject("body"); - assertEquals(student.getAge(), body1.getInt("age")); - int newAge = 60; - body1.put("age", newAge); - JSONObject body2 = new JSONObject(makeRequest(BASE_URL, "PUT", body1)).getJSONObject("body"); - assertFalse(student.getAge() == body2.getInt("age")); - assertTrue(newAge == body2.getInt("age")); - } - - @Test - public void whenGetsAllRecords_thenCorrect() { - Student student1 = new Student("jane", "daisy", 50); - Student student2 = new Student("john", "daniel", 60); - Student student3 = new Student("don", "mason", 55); - Student student4 = new Student("scarlet", "ohara", 90); - - makeRequest(BASE_URL, "POST", new JSONObject(student1)); - makeRequest(BASE_URL, "POST", new JSONObject(student2)); - makeRequest(BASE_URL, "POST", new JSONObject(student3)); - makeRequest(BASE_URL, "POST", new JSONObject(student4)); - - JSONObject objects = new JSONObject(makeRequest(BASE_URL, "GET", null)); - assertTrue(objects.getBoolean("isSuccessfull")); - JSONArray array = objects.getJSONArray("body"); - assertTrue(array.length() >= 4); - } - - public static String makeRequest(String myUrl, String httpMethod, JSONObject parameters) { - - URL url = null; - try { - url = new URL(myUrl); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - HttpURLConnection conn = null; - try { - - conn = (HttpURLConnection) url.openConnection(); - } catch (IOException e) { - e.printStackTrace(); - } - conn.setDoInput(true); - - conn.setReadTimeout(10000); - - conn.setRequestProperty("Content-Type", "application/json"); - DataOutputStream dos = null; - int respCode = 0; - String inputString = null; - try { - conn.setRequestMethod(httpMethod); - - if (Arrays.asList("POST", "PUT").contains(httpMethod)) { - String params = parameters.toString(); - - conn.setDoOutput(true); - - dos = new DataOutputStream(conn.getOutputStream()); - dos.writeBytes(params); - dos.flush(); - dos.close(); - } - respCode = conn.getResponseCode(); - if (respCode != 200 && respCode != 201) { - String error = inputStreamToString(conn.getErrorStream()); - return error; - } - inputString = inputStreamToString(conn.getInputStream()); - - } catch (IOException e) { - - e.printStackTrace(); - } - return inputString; - } - - public static String inputStreamToString(InputStream is) { - BufferedReader br = null; - StringBuilder sb = new StringBuilder(); - - String line; - try { - - br = new BufferedReader(new InputStreamReader(is)); - while ((line = br.readLine()) != null) { - sb.append(line); - } - - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (br != null) { - try { - br.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - return sb.toString(); - - } -} diff --git a/play-framework/student-api/test/controllers/StudentControllerUnitTest.java b/play-framework/student-api/test/controllers/StudentControllerUnitTest.java new file mode 100644 index 0000000000..bf645b72f9 --- /dev/null +++ b/play-framework/student-api/test/controllers/StudentControllerUnitTest.java @@ -0,0 +1,95 @@ +package controllers; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.Test; +import play.Application; +import play.inject.guice.GuiceApplicationBuilder; +import play.libs.Json; +import play.mvc.Http; +import play.mvc.Result; +import play.test.WithApplication; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static play.mvc.Http.Status.OK; +import static play.test.Helpers.*; + +public class StudentControllerUnitTest extends WithApplication { + + @Override + protected Application provideApplication() { + return new GuiceApplicationBuilder().build(); + } + + @Test + public void givenStudentPostData_whenCreatingStudent_ThenShouldReturnCreatedStudent() { + final ObjectNode jsonNode = Json.newObject(); + jsonNode.put("firstName", "John"); + jsonNode.put("lastName", "Baeldung"); + jsonNode.put("age", 25); + + Http.RequestBuilder request = new Http.RequestBuilder() + .method(POST) + .bodyJson(jsonNode) + .uri("/"); + + Result result = route(app, request); + assertEquals(CREATED, result.status()); + assertTrue(result.contentType().isPresent()); + assertEquals("application/json", result.contentType().get()); + } + + @Test + public void givenUrlToListStudents_whenListingStudents_ThenShouldReturnStudentList() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/"); + + Result result = route(app, request); + assertEquals(OK, result.status()); + assertTrue(result.contentType().isPresent()); + assertEquals("application/json", result.contentType().get()); + } + + @Test + public void givenUrlToRetrieveSingleStudent_whenRetrievingStudent_ThenShouldReturn404NotFound() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(GET) + .uri("/1"); + + Result result = route(app, request); + assertEquals(NOT_FOUND, result.status()); + assertTrue(result.contentType().isPresent()); + assertEquals("application/json", result.contentType().get()); + } + + @Test + public void givenUrlToUpdateStudent_whenaUpdatingStudent_ThenShouldFail() { + final ObjectNode jsonNode = Json.newObject(); + jsonNode.put("firstName", "John"); + jsonNode.put("lastName", "Baeldung"); + jsonNode.put("age", 25); + + Http.RequestBuilder request = new Http.RequestBuilder() + .method(PUT) + .bodyJson(jsonNode) + .uri("/"); + + Result result = route(app, request); + assertEquals(INTERNAL_SERVER_ERROR, result.status()); + assertTrue(result.contentType().isPresent()); + assertEquals("application/json", result.contentType().get()); + } + + @Test + public void givenIdToDeleteStudent_whenDeletingStudent_ThenShouldFail() { + Http.RequestBuilder request = new Http.RequestBuilder() + .method(DELETE) + .uri("/1"); + + Result result = route(app, request); + assertEquals(NOT_FOUND, result.status()); + assertTrue(result.contentType().isPresent()); + assertEquals("application/json", result.contentType().get()); + } +} diff --git a/pom.xml b/pom.xml index 81338b9f81..2f27bdf6fd 100644 --- a/pom.xml +++ b/pom.xml @@ -535,6 +535,7 @@ metrics microprofile + ml msf4j mustache @@ -1253,6 +1254,7 @@ metrics microprofile + ml msf4j mustache diff --git a/spring-5-reactive-client/pom.xml b/spring-5-reactive-client/pom.xml index 1b71815eb4..70771f6832 100644 --- a/spring-5-reactive-client/pom.xml +++ b/spring-5-reactive-client/pom.xml @@ -56,7 +56,6 @@ - org.springframework.boot spring-boot-devtools @@ -89,6 +88,14 @@ org.projectlombok lombok + + + + org.eclipse.jetty + jetty-reactive-httpclient + ${jetty-reactive-httpclient.version} + test + @@ -110,6 +117,7 @@ 1.0 1.0 4.1 + 1.0.3 diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java new file mode 100644 index 0000000000..95c63f267f --- /dev/null +++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/WebClientLoggingIntegrationTest.java @@ -0,0 +1,154 @@ +package com.baeldung.reactive.logging; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.Appender; +import com.baeldung.reactive.logging.filters.LogFilters; +import com.baeldung.reactive.logging.netty.CustomLogger; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.net.URI; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; +import org.springframework.http.client.reactive.JettyClientHttpConnector; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.netty.channel.BootstrapHandlers; +import reactor.netty.http.client.HttpClient; + +import static com.baeldung.reactive.logging.jetty.RequestLogEnhancer.enhance; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + + +public class WebClientLoggingIntegrationTest { + + @AllArgsConstructor + @Data + class Post { + private String title; + private String body; + private int userId; + } + + private Appender jettyAppender; + private Appender nettyAppender; + private Appender mockAppender; + private String sampleUrl = "https://jsonplaceholder.typicode.com/posts"; + + private Post post; + private String sampleResponseBody; + + @BeforeEach + private void setup() throws Exception { + + post = new Post("Learn WebClient logging with Baeldung!", "", 1); + sampleResponseBody = new ObjectMapper().writeValueAsString(post); + + ch.qos.logback.classic.Logger jetty = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.reactive.logging.jetty"); + jettyAppender = mock(Appender.class); + when(jettyAppender.getName()).thenReturn("com.baeldung.reactive.logging.jetty"); + jetty.addAppender(jettyAppender); + + ch.qos.logback.classic.Logger netty = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("reactor.netty.http.client"); + nettyAppender = mock(Appender.class); + when(nettyAppender.getName()).thenReturn("reactor.netty.http.client"); + netty.addAppender(nettyAppender); + + ch.qos.logback.classic.Logger test = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.reactive"); + mockAppender = mock(Appender.class); + when(mockAppender.getName()).thenReturn("com.baeldung.reactive"); + test.addAppender(mockAppender); + + } + + @Test + public void givenJettyHttpClient_whenEndpointIsConsumed_thenRequestAndResponseBodyLogged() { + SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); + org.eclipse.jetty.client.HttpClient httpClient = new org.eclipse.jetty.client.HttpClient(sslContextFactory) { + @Override + public Request newRequest(URI uri) { + Request request = super.newRequest(uri); + return enhance(request); + } + }; + + WebClient + .builder() + .clientConnector(new JettyClientHttpConnector(httpClient)) + .build() + .post() + .uri(sampleUrl) + .body(BodyInserters.fromObject(post)) + .retrieve() + .bodyToMono(String.class) + .block(); + + verify(jettyAppender).doAppend(argThat(argument -> (((LoggingEvent) argument).getFormattedMessage()).contains(sampleResponseBody))); + } + + @Test + public void givenNettyHttpClientWithWiretap_whenEndpointIsConsumed_thenRequestAndResponseBodyLogged() { + + reactor.netty.http.client.HttpClient httpClient = HttpClient + .create() + .wiretap(true); + WebClient + .builder() + .clientConnector(new ReactorClientHttpConnector(httpClient)) + .build() + .post() + .uri(sampleUrl) + .body(BodyInserters.fromObject(post)) + .exchange() + .block(); + + verify(nettyAppender).doAppend(argThat(argument -> (((LoggingEvent) argument).getFormattedMessage()).contains("00000300"))); + } + + @Test + public void givenNettyHttpClientWithCustomLogger_whenEndpointIsConsumed_thenRequestAndResponseBodyLogged() { + + reactor.netty.http.client.HttpClient httpClient = HttpClient + .create() + .tcpConfiguration( + tc -> tc.bootstrap( + b -> BootstrapHandlers.updateLogSupport(b, new CustomLogger(HttpClient.class)))); + WebClient + .builder() + .clientConnector(new ReactorClientHttpConnector(httpClient)) + .build() + .post() + .uri(sampleUrl) + .body(BodyInserters.fromObject(post)) + .exchange() + .block(); + + verify(nettyAppender).doAppend(argThat(argument -> (((LoggingEvent) argument).getFormattedMessage()).contains(sampleResponseBody))); + } + + @Test + public void givenDefaultHttpClientWithFilter_whenEndpointIsConsumed_thenRequestAndResponseLogged() { + WebClient + .builder() + .filters(exchangeFilterFunctions -> { + exchangeFilterFunctions.addAll(LogFilters.prepareFilters()); + }) + .build() + .post() + .uri(sampleUrl) + .body(BodyInserters.fromObject(post)) + .exchange() + .block(); + + verify(mockAppender).doAppend(argThat(argument -> (((LoggingEvent) argument).getFormattedMessage()).contains("domain=.typicode.com;"))); + } + + +} diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/filters/LogFilters.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/filters/LogFilters.java new file mode 100644 index 0000000000..c1c3d3e895 --- /dev/null +++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/filters/LogFilters.java @@ -0,0 +1,54 @@ +package com.baeldung.reactive.logging.filters; + +import java.util.Arrays; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import reactor.core.publisher.Mono; + +@Slf4j +public class LogFilters { + public static List prepareFilters() { + return Arrays.asList(logRequest(), logResponse()); + } + + private static ExchangeFilterFunction logRequest() { + return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { + if (log.isDebugEnabled()) { + StringBuilder sb = new StringBuilder("Request: \n") + .append(clientRequest.method()) + .append(" ") + .append(clientRequest.url()); + clientRequest + .headers() + .forEach((name, values) -> values.forEach(value -> sb + .append("\n") + .append(name) + .append(":") + .append(value))); + log.debug(sb.toString()); + } + return Mono.just(clientRequest); + }); + } + + private static ExchangeFilterFunction logResponse() { + return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> { + if (log.isDebugEnabled()) { + StringBuilder sb = new StringBuilder("Response: \n") + .append("Status: ") + .append(clientResponse.rawStatusCode()); + clientResponse + .headers() + .asHttpHeaders() + .forEach((key, value1) -> value1.forEach(value -> sb + .append("\n") + .append(key) + .append(":") + .append(value))); + log.debug(sb.toString()); + } + return Mono.just(clientResponse); + }); + } +} diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/jetty/RequestLogEnhancer.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/jetty/RequestLogEnhancer.java new file mode 100644 index 0000000000..43e3660743 --- /dev/null +++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/jetty/RequestLogEnhancer.java @@ -0,0 +1,93 @@ +package com.baeldung.reactive.logging.jetty; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Locale; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; + +@Slf4j +public class RequestLogEnhancer { + + public static Request enhance(Request request) { + StringBuilder group = new StringBuilder(); + request.onRequestBegin(theRequest -> group + .append("Request ") + .append(theRequest.getMethod()) + .append(" ") + .append(theRequest.getURI()) + .append("\n")); + request.onRequestHeaders(theRequest -> { + for (HttpField header : theRequest.getHeaders()) + group + .append(header) + .append("\n"); + }); + request.onRequestContent((theRequest, content) -> { + group.append(toString(content, getCharset(theRequest.getHeaders()))); + }); + request.onRequestSuccess(theRequest -> { + log.debug(group.toString()); + group.delete(0, group.length()); + }); + group.append("\n"); + request.onResponseBegin(theResponse -> { + group + .append("Response \n") + .append(theResponse.getVersion()) + .append(" ") + .append(theResponse.getStatus()); + if (theResponse.getReason() != null) { + group + .append(" ") + .append(theResponse.getReason()); + } + group.append("\n"); + }); + request.onResponseHeaders(theResponse -> { + for (HttpField header : theResponse.getHeaders()) + group + .append(header) + .append("\n"); + }); + request.onResponseContent((theResponse, content) -> { + group.append(toString(content, getCharset(theResponse.getHeaders()))); + }); + request.onResponseSuccess(theResponse -> { + log.debug(group.toString()); + }); + return request; + } + + private static String toString(ByteBuffer buffer, Charset charset) { + byte[] bytes; + if (buffer.hasArray()) { + bytes = new byte[buffer.capacity()]; + System.arraycopy(buffer.array(), 0, bytes, 0, buffer.capacity()); + } else { + bytes = new byte[buffer.remaining()]; + buffer.get(bytes, 0, bytes.length); + } + return new String(bytes, charset); + } + + private static Charset getCharset(HttpFields headers) { + String contentType = headers.get(HttpHeader.CONTENT_TYPE); + if (contentType != null) { + String[] tokens = contentType + .toLowerCase(Locale.US) + .split("charset="); + if (tokens.length == 2) { + String encoding = tokens[1].replaceAll("[;\"]", ""); + return Charset.forName(encoding); + } + } + return StandardCharsets.UTF_8; + } + +} + diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/netty/CustomLogger.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/netty/CustomLogger.java new file mode 100644 index 0000000000..9f2a4d127f --- /dev/null +++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/logging/netty/CustomLogger.java @@ -0,0 +1,42 @@ +package com.baeldung.reactive.logging.netty; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.logging.LoggingHandler; +import java.nio.charset.Charset; + +import static io.netty.util.internal.PlatformDependent.allocateUninitializedArray; +import static java.lang.Math.max; +import static java.nio.charset.Charset.defaultCharset; + +public class CustomLogger extends LoggingHandler { + public CustomLogger(Class clazz) { + super(clazz); + } + + @Override + protected String format(ChannelHandlerContext ctx, String event, Object arg) { + if (arg instanceof ByteBuf) { + ByteBuf msg = (ByteBuf) arg; + return decode(msg, msg.readerIndex(), msg.readableBytes(), defaultCharset()); + } + return super.format(ctx, event, arg); + } + + private String decode(ByteBuf src, int readerIndex, int len, Charset charset) { + if (len != 0) { + byte[] array; + int offset; + if (src.hasArray()) { + array = src.array(); + offset = src.arrayOffset() + readerIndex; + } else { + array = allocateUninitializedArray(max(len, 1024)); + offset = 0; + src.getBytes(readerIndex, array, 0, len); + } + return new String(array, offset, len, charset); + } + return ""; + } +} diff --git a/spring-5-reactive-client/src/test/resources/logback-test.xml b/spring-5-reactive-client/src/test/resources/logback-test.xml index 7072369b8d..42cb0865c5 100644 --- a/spring-5-reactive-client/src/test/resources/logback-test.xml +++ b/spring-5-reactive-client/src/test/resources/logback-test.xml @@ -6,11 +6,15 @@ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - + + + + + - + \ No newline at end of file diff --git a/spring-cloud-bus/spring-cloud-config-client/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud-bus/spring-cloud-config-client/src/test/java/org/baeldung/SpringContextIntegrationTest.java deleted file mode 100644 index c0298daeb1..0000000000 --- a/spring-cloud-bus/spring-cloud-config-client/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.baeldung; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import com.baeldung.SpringCloudConfigClientApplication; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = SpringCloudConfigClientApplication.class) -public class SpringContextIntegrationTest { - - @Test - public void contextLoads() { - } - -} diff --git a/spring-cloud-bus/spring-cloud-config-client/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud-bus/spring-cloud-config-client/src/test/java/org/baeldung/SpringContextLiveTest.java index 8a33efef43..a401d41e1e 100644 --- a/spring-cloud-bus/spring-cloud-config-client/src/test/java/org/baeldung/SpringContextLiveTest.java +++ b/spring-cloud-bus/spring-cloud-config-client/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -7,12 +7,27 @@ import org.springframework.test.context.junit4.SpringRunner; import com.baeldung.SpringCloudConfigClientApplication; +/** + * This LiveTest requires: + * 1- The 'spring-cloud-bus/spring-cloud-config-server' service running, with valid Spring Cloud Config properties, for instance: + * 1.1- `spring.cloud.config.server.git.uri` pointing to a valid URI, which has `user.role` and `user.password` properties configured in a properties file. For example, to achieve this in a dev environment: + * 1.1.1- `cd my/custom/path` + * 1.1.2- `git init .` + * 1.1.3- `echo user.role=Programmer >> application.properties` + * 1.1.4- `echo user.password=d3v3L >> application.properties` + * 1.1.5- `git add .` + * 1.1.6- `git commit -m 'inital commit'` + * 1.1.7- 'spring-cloud-bus/spring-cloud-config-server' with property `spring.cloud.config.server.git.uri=my/custom/path` + * + * Note: This is enough to run the ContextTest successfully, but to get the full functionality shown in the related article, we'll need also a RabbitMQ instance running (e.g. `docker run -d --hostname my-rabbit --name some-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3-management`) + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = SpringCloudConfigClientApplication.class) public class SpringContextLiveTest { - @Test - public void contextLoads() { - } + @Test + public void contextLoads() { + } } diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/pom.xml index cf583c216a..7166b0fd32 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/pom.xml @@ -1,5 +1,6 @@ - 4.0.0 data-flow-server @@ -12,7 +13,7 @@ parent-boot-1 com.baeldung 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../../parent-boot-1 @@ -20,6 +21,16 @@ org.springframework.cloud spring-cloud-starter-dataflow-server-local + + org.hibernate + hibernate-core + ${hibernate.compatible.version} + + + org.hibernate + hibernate-entitymanager + ${hibernate.compatible.version} + @@ -42,8 +53,9 @@ - 1.1.0.RELEASE - Brixton.SR7 + 1.3.1.RELEASE + Edgware.SR6 + 5.2.12.Final diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/main/resources/application.properties b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/main/resources/application.properties new file mode 100644 index 0000000000..20ad5d5bcb --- /dev/null +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/main/resources/application.properties @@ -0,0 +1,2 @@ +#spring.datasource.url=jdbc:h2:mem:dataflow +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect \ No newline at end of file diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/org/baeldung/SpringContextLiveTest.java deleted file mode 100644 index 980c096f5e..0000000000 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/java/org/baeldung/SpringContextLiveTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.baeldung; - -import org.baeldung.spring.cloud.DataFlowServerApplication; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = DataFlowServerApplication.class) -public class SpringContextLiveTest { - - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { - } -} diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/resources/application.properties b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/resources/application.properties new file mode 100644 index 0000000000..70e3e5c65b --- /dev/null +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-server/src/test/resources/application.properties @@ -0,0 +1 @@ +spring.datasource.url=jdbc:h2:mem:dataflow \ No newline at end of file diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-shell/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-shell/pom.xml index 52cb204201..9c379624d3 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-shell/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/data-flow-shell/pom.xml @@ -12,7 +12,7 @@ parent-boot-1 com.baeldung 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../../parent-boot-1 diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/log-sink/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/log-sink/pom.xml index ecabb91a98..73fb82d79f 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/log-sink/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/log-sink/pom.xml @@ -12,7 +12,7 @@ parent-boot-1 com.baeldung 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../../parent-boot-1 diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-processor/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-processor/pom.xml index de354ca698..28a9d3e6e0 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-processor/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-processor/pom.xml @@ -12,7 +12,7 @@ parent-boot-1 com.baeldung 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../../parent-boot-1 diff --git a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-source/pom.xml b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-source/pom.xml index a4d06e13d2..3b748fd7df 100644 --- a/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-source/pom.xml +++ b/spring-cloud-data-flow/spring-cloud-data-flow-stream-processing/time-source/pom.xml @@ -12,7 +12,7 @@ parent-boot-1 com.baeldung 0.0.1-SNAPSHOT - ../../parent-boot-1 + ../../../parent-boot-1 diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml index 89c9318c4e..b6b5a1cf0f 100644 --- a/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 org.baeldung.cloud @@ -43,6 +44,11 @@ org.springframework.cloud spring-cloud-task-batch + + com.h2database + h2 + test + diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java index be2a173589..30e17cb956 100644 --- a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java @@ -14,6 +14,13 @@ import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +/** + * This Application requires: + * * a MySql instance running, that allows a root user with no password, and with a database named + * + * (e.g. with the following command `docker run -p 3306:3306 --name bael-mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true -e MYSQL_DATABASE=springcloud mysql:latest`) + * + */ @SpringBootApplication @EnableTask @EnableBatchProcessing diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextIntegrationTest.java similarity index 60% rename from spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextLiveTest.java rename to spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextIntegrationTest.java index ddbcbf65ea..0caa626c14 100644 --- a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextLiveTest.java +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/java/org/baeldung/SpringContextIntegrationTest.java @@ -10,18 +10,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.baeldung.task.JobConfiguration; import com.baeldung.task.TaskDemo; -/** - * This Live Test requires: - * * a MySql instance running, that allows a root user with no password, and with a database named - * - * (e.g. with the following command `docker run -p 3306:3306 --name bael-mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true -e MYSQL_DATABASE=springcloud mysql:latest`) - * - */ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootApplication -@ContextConfiguration(classes = { JobConfiguration.class, TaskDemo.class }, initializers = { - ConfigFileApplicationContextInitializer.class }) -public class SpringContextLiveTest { +@ContextConfiguration(classes = { JobConfiguration.class, TaskDemo.class }, initializers = { ConfigFileApplicationContextInitializer.class }) +public class SpringContextIntegrationTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/resources/application.yml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/resources/application.yml new file mode 100644 index 0000000000..794ac4d247 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/test/resources/application.yml @@ -0,0 +1,11 @@ +spring: + datasource: + url: jdbc:h2:mem:springcloud + username: sa + password: + jpa: + hibernate: + ddl-auto: create-drop + properties: + hibernate: + dialect: org.hibernate.dialect.H2Dialect \ No newline at end of file